一个很好的用例是我所谓的“杠杆”接口:这些接口只有少量的抽象方法(理想情况下为1),但是却提供了很多“杠杆”,因为它们为您提供了许多功能:仅需要在您的类中实现1个方法,但“免费”获得许多其他方法。想的集合接口,例如,具有单个抽象foreach
方法和default
方法,如map
,fold
,reduce
,filter
,partition
,groupBy
,sort
,sortBy
,等。
这里有几个例子。让我们从开始java.util.function.Function<T, R>
。它只有一个抽象方法R apply<T>
。它具有两个默认方法,使您可以在之前或之后以两种不同的方式将函数与另一个函数组成。这两种组合方法都是使用以下方法实现的apply
:
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
return (T t) -> after.apply(apply(t));
}
您还可以为类似对象创建一个接口,如下所示:
interface MyComparable<T extends MyComparable<T>> {
int compareTo(T other);
default boolean lessThanOrEqual(T other) {
return compareTo(other) <= 0;
}
default boolean lessThan(T other) {
return compareTo(other) < 0;
}
default boolean greaterThanOrEqual(T other) {
return compareTo(other) >= 0;
}
default boolean greaterThan(T other) {
return compareTo(other) > 0;
}
default boolean isBetween(T min, T max) {
return greaterThanOrEqual(min) && lessThanOrEqual(max);
}
default T clamp(T min, T max) {
if (lessThan( min)) return min;
if (greaterThan(max)) return max;
return (T)this;
}
}
class CaseInsensitiveString implements MyComparable<CaseInsensitiveString> {
CaseInsensitiveString(String s) { this.s = s; }
private String s;
@Override public int compareTo(CaseInsensitiveString other) {
return s.toLowerCase().compareTo(other.s.toLowerCase());
}
}
或者是一个极其简化的集合框架,其中所有集合操作都将返回Collection
,无论原始类型是什么:
interface MyCollection<T> {
void forEach(java.util.function.Consumer<? super T> f);
default <R> java.util.Collection<R> map(java.util.function.Function<? super T, ? extends R> f) {
java.util.Collection<R> l = new java.util.ArrayList();
forEach(el -> l.add(f.apply(el)));
return l;
}
}
class MyArray<T> implements MyCollection<T> {
private T[] array;
MyArray(T[] array) { this.array = array; }
@Override public void forEach(java.util.function.Consumer<? super T> f) {
for (T el : array) f.accept(el);
}
@Override public String toString() {
StringBuilder sb = new StringBuilder("(");
map(el -> el.toString()).forEach(s -> { sb.append(s); sb.append(", "); } );
sb.replace(sb.length() - 2, sb.length(), ")");
return sb.toString();
}
public static void main(String... args) {
MyArray<Integer> array = new MyArray<>(new Integer[] {1, 2, 3, 4});
System.out.println(array);
// (1, 2, 3, 4)
}
}
与lambda结合使用时,这变得非常有趣,因为这样的“杠杆”接口可以由lambda(它是SAM接口)实现。
这与在C♯中添加扩展方法的用例相同,但是默认方法具有一个明显的优势:它们是“适当的”实例方法,这意味着它们可以访问接口的私有实现详细信息(private
接口方法即将到来)在Java 9中),而扩展方法只是静态方法的语法糖。
如果Java获得接口注入,它也将允许类型安全的,作用域化的,模块化的猴子修补程序。对于JVM上的语言实现者来说,这将是非常有趣的:例如,目前,JRuby继承自Java类或包装Java类以为其提供其他Ruby语义,但是理想情况下,他们希望使用相同的类。随着接口注入和默认的方法,他们可以注入例如RubyObject
界面进入java.lang.Object
,这样一个Java Object
和Ruby的Object
是同样的事情。