私はそれらに対して論理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
どうしてこれなの?
情報については、Eclipse Lunaバージョン1を使用します。
これは、コンパイラーのコーナーケースです。引数の可変引数ラッピングを配列に適用するか、単に配列を渡すかを決定するために、最後の引数のタイプを知る必要がありますが、ラムダ式の場合、呼び出されたメソッドシグネチャがタイプ。しかし、ラムダ式が配列型になることはないため、何が起こるかは明らかです。そのため、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);
}
NetbeansとEclipseの両方には、Javaでラムダ式を解析する領域に多くのバグがあります。それらはゆっくりと修正されますが、修正されるまで、私が見つけた最良の回避策は次のとおりです。1。型を宣言する2.それが機能しない場合はブロックを使用する3.それが機能しない場合は、実装する匿名オブジェクトを作成する述語/関数など.
これらはコードを煩雑にしますが、多くの状況で必要になります。
Eclipseはすべてのプロジェクトの完全なクリーンアップと再構築を必要とする場合があり、問題は解消されます。