8

Tユーティリティ ファクトリ メソッドが、バインドされたワイルドカード パラメータ ( など) ではなく、特定のジェネリック パラメータ ( など) を使用することが多いのはなぜ? super Tですか?

たとえば、Functions#forPredicateの署名は次のとおりです。

public static <T> Function<T, Boolean> forPredicate(Predicate<T> predicate)

使用しない理由:

public static <T> Function<T, Boolean> forPredicate(Predicate<? super T> predicate)

次のようなことが可能になるのはどれですか?

Predicate<Number> isPositivePredicate = ...
Function<Integer, Boolean> isPositiveInteger = Functions.forPredicate(isPositivePredicate);
// above line is compiler error:
//   Type mismatch: cannot convert from Function<Number,Boolean> to Function<Integer,Boolean>

これを不要にするために、との消費者が必要な限定されたワイルドカード パラメータを持つことが期待されているためですか? たとえば、Iterables#findの一般的な境界により、 a でaを使用できるようになります。FunctionPredicatePredicate<Number>Iterable<Integer>

public static <T> T find(Iterable<T> iterable,
                         Predicate<? super T> predicate)

他の理由はありますか?

4

2 に答える 2

6

はい、消費者が適切な範囲のワイルドカード パラメーターを持っていることを期待するのは絶対に正確ですが、いくつかの追加の理由が思い浮かびます。

  • 一般に、特定の理由があるまでジェネリック メソッドの型を拡張しません。この政策は何度か報われました。
  • Java の型推論は、常により高度なジェネリックを自動的に把握できるとは限らないため、より狭いジェネリックを維持することで、明示的に指定する必要があるユーザーの数を減らすことができますT
于 2013-01-31T17:50:37.967 に答える
2

このfind()例では、T常に明確に推測できます。

このforPredicate[1]()例では、T も明確に推論できます。

このforPredicate[2]()例では、どうあるTべきか不確実性があります。メソッドの結果がターゲット タイプに割り当てられている場合はT、ターゲット タイプから判断できます。それ以外の場合は、少し頭を悩ませています。

forPredicate(isPositive).apply(42);  // T is a subtype of Number, but which one?

java5/6 では、コンパイルされません。(まあ、Java 6でテストしたところコンパイルされますが、Java 6もコンパイルされるため、おそらくバグですforPredicate(p).apply("str")

Java 7 は少し改善されており、新しいルールはたまたまそれを指示していT=Numberます。それは機能しますが、それのための仲裁のように感じます.


理想的には、ワイルドカードについて心配する必要はありません。整数の述語が必要な場合は、Predicate<Integer>パラメーターを宣言する必要があります。Predicate<Number>議論も受け入れられるという事実は別の話です。Predicate<Number>変換するのはコンパイラの仕事であるべきですPredicate<Integer>。既存の Java ジェネリック型システムをオーバーホールすることなく変換できます。必要なのは新しい変換規則だけです。変換ライブラリを提供することもできます

Predicate<Number>  pn = ...;
Predicate<Integer> pi = convert(pn);

Iterable<Integer> iter1 = ...;
Iterable<Number>  iter2 = convert(iter1);

すべてのconvert()メソッドは機械的に生成できます。


Java 8 は物事を少し簡単にします。まだできない

Predicate<Number>  pn = n -> n.intValue()>0;
Predicate<Integer> pi = pn;  // error!

しかし、私たちはできる

Predicate<Integer> pi = pn::test;  // ok
// it means        pi = (Integer i)->pn.test(i)

また

Function<Integer, Boolean> f = pn::test;   // ok

これは と同等f = forPredicate[2](pn)です。forPredicate()Java 8 では、関数型間の変換に etc が必要になることはめったにありません。

于 2013-01-31T22:03:25.913 に答える