1. 関数メソッド

インターフェイスにメソッドが 1 つだけある場合、そのインターフェイス タイプの変数には、ラムダ式(ラムダ関数) で指定された値を割り当てることができます。このようなインターフェイスは、(Java がラムダ関数のサポートを追加した後)関数インターフェイスとして知られるようになりました。

たとえば、Java にはConsumer<Type>インターフェースがあり、accept(Type obj)インターフェースにはメソッドがあります。なぜこのインターフェースが必要なのでしょうか?

Java 8 では、コレクションにはforEach()メソッドがあり、これを使用すると、コレクションの各要素に対して何らかのアクションを実行できます 。ここでは、関数インターフェイスを使用してアクションをメソッドに渡します。 Consumer<T>forEach()

コレクションのすべての要素を表示する方法は次のとおりです。

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Hello", "how's", "life?");

list.forEach( (s) -> System.out.println(s) );
コレクションのすべての要素を表示する (ラムダ式を使用)

コンパイラは上記のコードを以下のコードに変換します。

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Hello", "how's", "life?");

list.forEach(new Consumer<String>()
{
   public void accept(String s)
   {
      System.out.println(s));
   }
});
コレクションのすべての要素を表示する (匿名クラスを使用)

最初のバージョンは 2 番目のバージョンよりも明らかに短いです。ラムダ式を含むコードは読みにくいですが、匿名内部クラスを含むコードはさらに読みにくい場合があります。



2. メソッドのリファレンス

ただし、ラムダ式のコードはさらに短く書くこともできます。

まず、パラメータを囲む括弧を省略できますs

list.forEach( (s) -> System.out.println(s) );
list.forEach( s -> System.out.println(s) );

これはパラメータが1 つある場合にのみ実行できます。複数のパラメータがある場合は、括弧を使用する必要があります。

そして 2 番目に、次のように書くことができます。

list.forEach( System.out::println );
最もコンパクトな表記法

これも全く同じ表記です。の後に括弧がないことに注意してくださいprintln

ここには同じコード、つまりメソッド呼び出しがあります。

object::method
x -> object.method(x)

考えてみてください。コレクションの各要素に対して何らかのアクションを実行したいと考えていましたlist。アクションが単一の関数呼び出し ( などprintln()) の場合は、その関数をパラメーターとしてメソッドに単純に渡すのが合理的です。

しかし、メソッドを呼び出すのではなく渡したいことをコンパイラにどのように説明すればよいでしょうか? これを行うには、ドット演算子の代わりに、メソッド名の前に2 つのコロンを使用します。単一のコロンは、三項演算子を示すためにすでに使用されています。

これは最も単純でコンパクトな表記法です。



3. コンストラクター

二重コロンを使用したメソッド参照は、I/O ストリームを扱うときに非常に便利です。これについては少し後で説明します。

それまでの間、メソッド参照を渡すための 3 つの一般的な方法について説明しましょう。

オブジェクトのメソッドへの参照

オブジェクトのメソッドへの参照を渡すには、次のように記述する必要があります。このコードは と同等です。object::method
x -> object.method(x)

特殊thisおよびsuper変数をオブジェクトとして使用できます。

クラスのメソッドへの参照

静的メソッドへの参照を渡すには、次のように記述する必要があります。このコードは次のようなコードに変換されますclass::methodx -> class.method(x);

コンストラクターへの参照

コンストラクターは静的クラス メソッドと同様に動作するため、コンストラクターに参照を渡すこともできます。見た目はこんな感じです。class::new

たとえば、コレクションの型消去を回避し、toArray()目的の配列を作成するコンストラクターへの参照をメソッドに渡すことができます。toArray(int[]::new);