倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

Java 8 のメソッド参照について

ちょっと頭痛がするので「こなし」記事。

演算子の参照


プリミティブ型の演算子をメソッド参照みたく取得することはデキナイ?

IntBinaryOperator plus = (i, j) -> i + j;

はもちろん OK だけど

IntBinaryOperator plus = int::+;

みたいな風には書けないのかな? まぁ、たとえ書けたとしても最初の方が分かりやすいけど。

メソッド参照があいまいなことがある


Java8 から「::」演算子を使ってメソッドを関数オブジェクトとして参照することができるようになりました:

// インスタンスメソッド String#length() : Integer の参照
Function<String, Integer> func1 = String::length;
assert func1.apply("Java 8") == 6;

// static メソッド String#valueOf(Integer) : String の参照
Function<Integer, String> func2 = String::valueOf;
assert func2.apply(1).equals("1");

2つ目の static メソッドの参照は問題ないと思います。 1つ目のインスタンスメソッドの参照では、(必要なら)apply() メソッドの第1引数(今の場合 String)に対して length() メソッドを探します。 さて、ここで

Function<Integer> f = Integer::toString;

とすると「メソッド参照が無効です。toString() のメソッド参照があいまいです」とコンパイラに怒られてしまいます。 これは

  • Integer のインスタンスメソッド toString() : String
  • Integer の static メソッド String#toString(Integer) : String

の区別がつかないためのよう。 実際に使いたいならラムダ式で

Function<String, Integer> func1 = s -> s.length();
Function<Integer, String> func2 = s -> String.valueOf(s);

のように書かないといけないようです。 まぁ、今後どちらかが優先して返される、なんて変更もありえますが。