私は最近、Java メソッドを呼び出すときにジェネリック型を明示的に宣言するための奇妙な構文に出くわしました。例えば:
Collections.<String>emptyList();
空の を返しますList<String>
。<T> emptyList()
ただし、 の実装はチェックされていない型キャストであるため、これはばかげているように見え(List<T>) EMPTY_LIST
ます。そのため、すべての結果は同じ型の消去になります (そして同じオブジェクトになります)。さらに、この種の明示的な型宣言は通常必要ありません。タイプを推測します。
List<String> empty = Collections.emptyList();
さらに掘り下げた後、この構文を使用したい場所が他に2つ見つかりました。それらはすべて、グアバライブラリを使用しており、1行にあまりにも多くのステートメントを配置しようとしていることが原因です。
同期ラッパーなどを使用してコレクションをデコレートし、コンパイラが型を推測できない。型宣言を取り出すと、次は機能しません:
cannot convert from Set<Object> to Set<String>
:Set<String> set = Collections.synchronizedSet(Sets.<String>newHashSet());
コンパイラが具体的すぎる型パラメーターを作成しようとすると、具体的でない型パラメーターを取得します。たとえば、型宣言がないと、次のステートメントも同様に文句を言います:
cannot convert from Map<String, String> to Map<String, Object>
:Map<String, Object> toJson = ImmutableMap.<String, Object>of("foo", "bar");
最初のケースでは推論された型パラメーターが一般的すぎ、2 番目のケースでは具体的すぎるというのは皮肉なことですが、それは Java のジェネリック システムの成果物に過ぎないと思います。
ただし、この言語構造自体は、Guava チームによって発明されたこれらの奇妙な使用例を除いて回避できるようです。さらに、コンパイラが上記の両方の例で型引数を推論する方法があり、開発者がそうしないことを選択したことは明らかです。Javaプログラミングでこの構造を使用することが必要または有用であるという例はありますか?それとも、コンパイラを単純にする/JDK開発者の生活を楽にするためだけに存在しますか?