Javaでのメソッド参照の評価

1. 概要

Java 8では、メソッド参照の概念が導入されました。 ラムダ式に似ているとよく見られます。
ただし、メソッド参照とラムダ式はまったく同じものではありません。 この記事では、それらが異なる理由と、それらを間違った方法で使用することのリスクを示します。

2. ラムダとメソッド参照の構文

はじめに、ラムダ式の例をいくつか見てみましょう。
Runnable r1 = () -> "some string".toUpperCase();
Consumer<String> c1 = x -> x.toUpperCase();
そして、メソッド参照のいくつかの例:
Function<String, String> f1 = String::toUpperCase;
Runnable r2 = "some string"::toUpperCase;
Runnable r3 = String::new;
これらの例により、メソッド参照をラムダの短縮表記として考えることができます。
しかし、公式のhttps://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13[Oracle documentation]を見てみましょう。 興味深い例を見つけることができます:
(test ? list.replaceAll(String::trim) : list) :: iterator
ご覧のとおり、Java言語仕様では、二重コロン演算子の前に異なる種類の式を使用できます。 *

の前の部分は、 the * * target reference *と呼ばれます。

次に、メソッド参照評価のプロセスについて説明します。

3. メソッド参照評価

次のコードを実行するとどうなりますか?
public static void main(String[] args) {
    Runnable runnable = (f("some") + f("string"))::toUpperCase;
}

private static String f(String string) {
    System.out.println(string);
    return string;
}
_Runnable_オブジェクトを作成しました。 それ以上、それ以下は何もない。 ただし、出力は次のとおりです。
some
string
これは、宣言が最初に発見されたときにターゲット参照が評価されるために発生しました。したがって、目的の遅延を失いました。 *ターゲット参照も1回だけ評価されます。*この行を上記の例に追加すると:
runnable.run()
出力は表示されません。 次のケースはどうですか?
SomeWorker worker = null;
Runnable workLambda = () -> worker.work() // ok
Runnable workMethodReference = worker::work; // boom! NullPointerException
前述のhttps://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13 [ドキュメント]で提供される説明:
_「インスタンスメソッドを呼び出すメソッド呼び出し式(§15.12)は、ターゲット参照がnullの場合、NullPointerExceptionをスローします。」_
予期しない状況を防ぐための最良の方法は、*ターゲット参照として変数アクセスと複雑な式を使用しない*ことです。
メソッド参照を、ラムダに相当する簡潔で短い表記としてのみ使用することをお勧めします。 *

*演算子の前にクラス名のみを付けると、安全性が保証されます。

4. 結論

この記事では、メソッド参照の評価プロセスについて学びました。
アプリケーションの動作に突然驚かないように、従うべきリスクとルールを知っています。