なぜこれが機能しないのですか? 「非静的メソッドprintへの静的参照を作成できません...」というコンパイラエラーが発生します。
public class Chapter3 {
public void print(String s) {
System.out.println(s);
}
public static void main(String[] args) {
Arrays.asList("a", "b", "c").forEach(Chapter3::print);
}
}
メソッド参照、ラムダ式、または通常のメソッド呼び出しのいずれを使用するかに関係なく、インスタンスメソッドには呼び出しに適切なインスタンスが必要です。インスタンスは、関数呼び出しによって提供される場合があります。 forEach
が_BiConsumer<Chapter3,String>
_を期待した場合、それは機能しました。ただし、forEach
は_Consumer<String>
_を想定しているため、スコープ内に_Chapter3
_のインスタンスはありません。これは、_Chapter3.print
_をstatic
メソッドに変更するか、メソッド呼び出しのターゲットとしてインスタンスを提供することで簡単に修正できます。
_public class Chapter3 {
public void print(String s) {
System.out.println(s);
}
public static void main(String[] args) {
Arrays.asList("a", "b", "c").forEach(new Chapter3()::print);
}
}
_
ここでは、_Chapter3
_の新しいインスタンスであるnew Chapter3()
の結果が、そのprint
メソッドへのメソッド参照と、上のメソッドを呼び出す_Consumer<String>
_に対してキャプチャされます。そのインスタンスを構築できます。
forEach
は_Consumer<? super T>
_(その署名はdefault void forEach(Consumer<? super T> action)
)を受け入れます。これは、単一の引数を持つメソッドaccept(T t)
の関数型インターフェースです。
引数を持つメソッドの非静的メソッド参照を渡す場合、実際には2つの引数があります。_Chapter3
_インスタンスへのthis
参照とString引数です。これは、forEach
が期待するものと一致しません。
コードが実行されているのと同じオブジェクトからインスタンスメソッドを適用しようとしている場合に備えて
Arrays.asList("a", "b", "c").forEach(this::print);
私は今それを手に入れたと思います。ストリームの内容はString型であるため、Stringインスタンスでprintを呼び出すことはできません。
たとえば、これは機能します
public class Chapter3 {
final String value;
public Chapter3(String value) {
this.value = value;
}
public void print() {
System.out.println(value);
}
public static void main(String[] args) {
Arrays.asList(new Chapter3("a"), new Chapter3("b")).forEach(Chapter3::print);
}
}
関数のタイプと関数の生成元のオブジェクトが一致しない場合は、非静的エラーが表示されます。たとえば、このコード行は、関数が動作しているタイプとしてFooを想定しているためコンパイルされませんが、関数はFoobar用です。
Function<Foo, Bar> func = Foobar::getBar;
Forループやその他の引数にある場合だけでなく、「スコープ内にあるもの」を処理する必要もありません。これは、新しい関数オブジェクトを使用するときにJava誤ったラベルが付けられるタイプの不一致エラーです。これを、他のジェネリックを構築するときに発生することと比較してください。
List<Foo> list = new ArrayList<Bar>();
そのコード行は、「互換性のないタイプ」というエラーでコンパイルに失敗します。さらに良いのは、機能オブジェクトをほぼ同じ方法で処理しているにもかかわらず、このコードが互換性のない型でも失敗することです。
public void test() {
Function<Foo, Double> test2 = Foo::getDouble;
//fails with Incompatible types
test3(test2);
}
public void test3(Function<Foobar, Double> function) {
//who cares
}
私の最善の提案は、このエラーが発生し始めたら、関数宣言を新しい行に引き出して、実際の問題が何であるかを確認できるようにすることです。 Javaが「非静的メソッドを静的コンテキストから参照できない」を選択した理由は私を超えています。
print
関数をstatic
にすることができます。こうすれば、それを呼び出すためのインスタンスは必要ありません。
public class Chapter3 {
public static void print(String s) {
System.out.println(s);
}
public static void main(String[] args) {
Arrays.asList("a", "b", "c").forEach(Chapter3::print);
}
}