優れたユースケースは、「レバー」インターフェースと呼ばれるものです。抽象メソッドは少数(理想的には1)のみですが、多くの機能を提供するという点で多くの「レバレッジ」を提供するインターフェースです。クラスに1つのメソッドを実装する必要がありますが、「無料」で他の多くのメソッドを取得します。単一抽象的で、例えば、コレクションインタフェースを考えるforeach
方法及びdefault
方法のようにmap
、fold
、reduce
、filter
、partition
、groupBy
、sort
、sortBy
、など
以下に例をいくつか示します。から始めましょうjava.util.function.Function<T, R>
。単一の抽象メソッドがありR apply<T>
ます。また、2つの異なる方法(前または後)で別の関数と関数を構成できる2つのデフォルトメソッドがあります。これらの構成メソッドは両方とも、次を使用して実装されます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)
}
}
このような「レバー」インターフェースはラムダ(SAMインターフェース)で実装できるため、これはラムダとの組み合わせで非常に興味深いものになります。
これは、拡張メソッドがC♯で追加されたのと同じユースケースですが、デフォルトのメソッドには1つの明確な利点があります。「適切な」インスタンスメソッドです。つまり、インターフェイスのプライベート実装詳細にアクセスできます(private
インターフェイスメソッドが登場しますJava 9)では、拡張メソッドは静的メソッドの構文糖にすぎません。
Javaがインターフェイスインジェクションを取得した場合、タイプセーフなスコープ付きモジュールモンキーパッチも許可されます。これは、JVMの言語実装者にとって非常に興味深いものです。たとえば、現時点では、JRubyは、Javaクラスを継承するかラップして、追加のRubyセマンティクスを提供しますが、理想的には、同じクラスを使用します。インターフェイスインジェクションとデフォルトメソッドをRubyObject
使用するとjava.lang.Object
、たとえばにインターフェイスをインジェクトできるため、Java Object
とRuby Object
はまったく同じものになります。