M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

公式チュートリアルの「ターゲット型付け」セクションを読む

前回ポストのあとOracleの公式チュートリアル"The Java Tutorials"の"Nested Classes" > "Lambda Expressions"に含まれるセクション"Target Typing"を読んでみました。ターゲット型とターゲット型付けという概念の理解のため若干の助けになるかと思います。

          *  *  *

ターゲット型付け

ラムダ式の型はどのように決定されるのでしょうか? 先ほど〔Personのコレクションの中から〕「性別は男性で年齢が18〜25才の間の人」を抽出するのに使用されたラムダ式を思い出してみてください:

p -> p.getGender() == Person.Sex.MALE
    && p.getAge() >= 18
    && p.getAge() <= 25

このラムダ式は以下の2つのメソッドで使用されていました:

  • public static void printPersons(List< Person> roster, CheckPerson tester) ──これはアプローチ3「ローカルクラスで検索条件コードを指定する」で登場しました〔訳注:このセクションではCheckPersonというインターフェースとそれを実装するインナークラスが宣言されています。このクラスのメソッドの実装部には上述のラムダ式に相当するロジックが記述されています。そしてセクションの終盤でこのクラスの代わりにラムダ式が導入されます〕。
  • public void printPersonsWithPredicate(List<Person> roster, Predicate<Person> tester) ──これはアプローチ6「ラムダ式で標準の関数型インターフェースを使う」で登場しました〔訳注:このセクションではPredicate<T>というjava.util.functionパッケージに所属する標準の関数型インターフェースに適合するかたちでラムダ式が宣言され引数として設定されています〕。

Javaランタイムが printPersons メソッドを呼び出すとき、引数として CheckPerson 型のデータが渡されることが期待されています。このためラムダ式はその型になります。一方、Javaランタイムが printPersonsWithPredicate メソッドを呼び出すとき、引数として Predicate< Person>型のデータが渡されることが期待されています。このためラムダ式はその型になります。このメソッドが期待するデータ型を「ターゲット型」と呼びます。ラムダ式のデータ型の決定のため、Javaコンパイラは当該のラムダ式が置かれた文脈や状況におけるターゲット型を利用します。このためラムダ式が使える状況というのは、Javaコンパイラがターゲット型を決定できる状況に限定されます:

ターゲット型とメソッド引数

メソッド引数のため、Javaコンパイラはそのターゲット型を決定します。これには他の2つの言語機能が関与します。それは多重定義解決〔多重定義されたメソッドのいずれを実行するかの決定〕と型引数推論〔省略された型パラメータの推論〕です。

次の2つの関数型インターフェースについて考えてみてください(java.lang.Runnable java.util.concurrent.Callable< V>):

public interface Runnable {
    void run();
}

public interface Callable<V> {
    V call();
}

 Runnable.run メソッドは値を返しません。対して Callable.call メソッドは値を返します。
ここであなたは次のようなinvokeメソッドを用意しているとしましょう(メソッドの多重定義についてより詳しく知りたい方は「メソッドを定義する」のセクションを参照してください)。

void invoke(Runnable r) {
    r.run();
}

<T> T invoke(Callable<T> c) {
    return c.call();
}

さて、次の構文ではいずれのメソッドが呼び出されるのでしょうか?

String s = invoke(() -> "done");

 invoke(Callable< T>) が呼び出されるでしょう。なぜならこのメソッドは値を返すメソッドだからです。対してinvoke(Runnable) はそうではありません。この場合、ラムダ式 () -> "done" の型は Callable<T>になります。

          *  *  *

原典は、Oracleの公式チュートリアル"The Java Tutorials"の"Nested Classes" > "Lambda Expressions"に含まれるセクション"Target Typing"です。

m12i.hatenablog.com