Java 9 is near to come and more features will be added to Java interfaces, like private methods. default methods in interfaces were added in Java 8, essentially
First that comes to mind is the use of default methods to support some functional programming techniques:
@FunctionalInterface
public interface Function3 {
D apply(A a, B b, C c);
default Function>> curry() {
return a -> b -> c -> this.apply(a, b, c);
}
default Function> bindFirst(A a) {
return b -> c -> this.apply(a, b, c);
}
}
Sample usage:
Function3 sum = (a, b, c) -> a + b + c;
long result = sum.apply(1L, 2L, 3L); // 6
Function>> curriedSum = sum.curry();
result = curriedSum.apply(1L).apply(2L).apply(3L); // 6
Function> incr = sum.bindFirst(1L);
result = incr.apply(7L).apply(3L); // 11
result = incr.apply(6L).apply(7L); // 14
You can have similar binding methods for the other parameters, implemented with default methods, such as bindSecond and bindThird.
You can use default methods to decorate the parent interface (as @holi-java explains in his answer), also there a lot of examples of the adapter pattern (currying and binding are actually adapters).
Besides functional programming, you can use default methods to support kind of, limited multiple inheritance:
public interface Animal {
String getHabitat();
}
public interface AquaticAnimal extends Animal {
@Override
default String getHabitat() {
return "water";
}
}
public interface LandAnimal extends Animal {
@Override
default String getHabitat() {
return "ground";
}
}
public class Frog implements AquaticAnimal, LandAnimal {
private int ageInDays;
public Frog(int ageInDays) {
this.ageInDays = ageInDays;
}
public void liveOneDay() {
this.ageInDays++;
}
@Override
public String getHabitat() {
if (this.ageInDays < 30) { // is it a tadpole?
return AquaticAnimal.super.getHabitat();
} // else
return LandAnimal.super.getHabitat();
}
}
Sample:
Frog frog = new Frog(29);
String habitatWhenYoung = frog.getHabitat(); // water
frog.liveOneDay();
String habitatWhenOld = frog.getHabitat(); // ground
Maybe not the best example, but you get the idea...
Another usage would be traits:
public interface WithLog {
default Logger logger() {
return LoggerFactory.getLogger(this.getClass());
}
}
public interface WithMetrics {
default MetricsService metrics() {
return MetricsServiceFactory.getMetricsService(
Configuration.getMetricsIP(
Environment.getActiveEnv())); // DEV or PROD
}
}
Now, whenever you have a class that needs to log something and report some metrics, you could use:
public class YourClass implements WithLog, WithMetrics {
public void someLongMethod() {
this.logger().info("Starting long method execution...");
long start = System.nanoTime();
// do some very long action
long end = System.nanoTime();
this.logger().info("Finished long method execution");
this.metrics().reportExecutionTime("Long method: ", end - start);
}
}
Again, this is not the best possible implementation, but just sample code to see how traits can be used via default methods.