首先想到的是使用默认方法来支持一些函数式编程技术:
@FunctionalInterface
public interface Function3<A, B, C, D> {
D apply(A a, B b, C c);
default Function<A, Function<B, Function<C, D>>> curry() {
return a -> b -> c -> this.apply(a, b, c);
}
default Function<B, Function<C, D>> bindFirst(A a) {
return b -> c -> this.apply(a, b, c);
}
}
示例用法:
Function3<Long, Long, Long, Long> sum = (a, b, c) -> a + b + c;
long result = sum.apply(1L, 2L, 3L); // 6
Function<Long, Function<Long, Function<Long, Long>>> curriedSum = sum.curry();
result = curriedSum.apply(1L).apply(2L).apply(3L); // 6
Function<Long, Function<Long, Long>> incr = sum.bindFirst(1L);
result = incr.apply(7L).apply(3L); // 11
result = incr.apply(6L).apply(7L); // 14
您可以为其他参数设置类似的绑定方法,使用默认方法实现,例如bindSecond 和bindThird。
您可以使用默认方法来装饰父接口(正如@holi-java 在他的回答中解释的那样),还有很多适配器模式的示例(currying 和 binding 实际上是适配器)。
除了函数式编程,你可以使用默认方法来支持种,有限的多重继承:
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();
}
}
示例:
Frog frog = new Frog(29);
String habitatWhenYoung = frog.getHabitat(); // water
frog.liveOneDay();
String habitatWhenOld = frog.getHabitat(); // ground
也许不是最好的例子,但你明白了......
另一种用法是特质:
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
}
}
现在,每当您的类需要记录某些内容并报告某些指标时,您都可以使用:
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);
}
}
同样,这不是最好的实现,只是示例代码以了解如何通过默认方法使用特征。