web-dev-qa-db-ja.com

Java 8メソッド非静的メソッドへの参照

なぜこれが機能しないのですか? 「非静的メソッド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);
    }
}
14
andres.santana

メソッド参照、ラムダ式、または通常のメソッド呼び出しのいずれを使用するかに関係なく、インスタンスメソッドには呼び出しに適切なインスタンスが必要です。インスタンスは、関数呼び出しによって提供される場合があります。 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>_に対してキャプチャされます。そのインスタンスを構築できます。

18
Holger

forEachは_Consumer<? super T>_(その署名はdefault void forEach(Consumer<? super T> action))を受け入れます。これは、単一の引数を持つメソッドaccept(T t)の関数型インターフェースです。

引数を持つメソッドの非静的メソッド参照を渡す場合、実際には2つの引数があります。_Chapter3_インスタンスへのthis参照とString引数です。これは、forEachが期待するものと一致しません。

8
Eran

コードが実行されているのと同じオブジェクトからインスタンスメソッドを適用しようとしている場合に備えて

Arrays.asList("a", "b", "c").forEach(this::print);
6

私は今それを手に入れたと思います。ストリームの内容は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);
}
}
4
andres.santana

関数のタイプと関数の生成元のオブジェクトが一致しない場合は、非静的エラーが表示されます。たとえば、このコード行は、関数が動作しているタイプとして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が「非静的メソッドを静的コンテキストから参照できない」を選択した理由は私を超えています。

0
Taugenichts

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);
    }
}
0
Willi Mentzel