web-dev-qa-db-ja.com

この式のターゲットタイプは関数型インターフェイスである必要があります

私はそれらに対して論理ANDを実行する複数の述語でフィルタリングする関数を作成しました:

@SafeVarargs
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) {
    return source.filter(Arrays.stream(predicates).reduce(predicates[0], Predicate::and));
}  

呼び出すとき:

filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0, x -> x%3 == 0).forEach(System.out::println);

これは正常に動作し、3と9を出力します。ただし、次のような単一の述語を渡すと、

filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0).forEach(System.out::println);

コンパイルエラーが発生します。

The target type of this expression must be a functional interface

どうしてこれなの?

enter image description here 情報については、Eclipse Lunaバージョン1を使用します。

15
user2336315

これは、コンパイラーのコーナーケースです。引数の可変引数ラッピングを配列に適用するか、単に配列を渡すかを決定するために、最後の引数のタイプを知る必要がありますが、ラムダ式の場合、呼び出されたメソッドシグネチャがタイプ。しかし、ラムダ式が配列型になることはないため、何が起こるかは明らかです。そのため、javacは問題なくコンパイルされます。

許容できる回避策の1つは、メソッドをオーバーロードすることです。

@SafeVarargs
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) {
    return source.filter(
        Arrays.stream(predicates).reduce(predicates[0], Predicate::and));
}
public static <T> Stream<T> filter(Stream<T> source, Predicate<T> predicate) {
    return source.filter(predicate);
}

単一引数の場合の効率を同時に改善しながら、呼び出し側で変更を必要としないため、これは許容できる回避策です。


Varargsメソッドは引数を0にできますが、そのように呼び出されると失敗します。だからあなたはどちらか、別のオーバーロードを追加する必要があります:

public static <T> Stream<T> filter(Stream<T> source) {
    return source;
}

または、メソッドを引数なしの場合に安全にします。

@SafeVarargs
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) {
    return Arrays.stream(predicates).reduce(Predicate::and)
                 .map(source::filter).orElse(source);
}
8
Holger

NetbeansとEclipseの両方には、Javaでラムダ式を解析する領域に多くのバグがあります。それらはゆっくりと修正されますが、修正されるまで、私が見つけた最良の回避策は次のとおりです。1。型を宣言する2.それが機能しない場合はブロックを使用する3.それが機能しない場合は、実装する匿名オブジェクトを作成する述語/関数など.

これらはコードを煩雑にしますが、多くの状況で必要になります。

2
sprinter

Eclipseはすべてのプロジェクトの完全なクリーンアップと再構築を必要とする場合があり、問題は解消されます。

0
Peteter