1. 概要

この記事では、Javaのダイヤモンド演算子と、ジェネリックスとコレクションAPIがその進化にどのように影響したかを見ていきます。

2. 生のタイプ

Java 1.5より前は、CollectionsAPIはraw型のみをサポートしていました–コレクションを構築するときに型引数をパラメーター化する方法はありませんでした。

List cars = new ArrayList();
cars.add(new Object());
cars.add("car");
cars.add(new Integer(1));

これにより、任意のタイプを追加し、実行時に潜在的なキャスト例外を発生させることができました

3. ジェネリックス

Java 1.5では、ジェネリックスが導入されました– これにより、オブジェクトを宣言および構築するときに、CollectionsAPIの引数を含むクラスの型引数をパラメーター化できます。

List<String> cars = new ArrayList<String>();

この時点で、コンストラクターでパラメーター化された型を指定する必要がありますが、これは多少判読できない場合があります。

Map<String, List<Map<String, Map<String, Integer>>>> cars 
 = new HashMap<String, List<Map<String, Map<String, Integer>>>>();

このアプローチの理由は、下位互換性のために raw型がまだ存在するため、コンパイラーはこれらのraw型とジェネリックを区別する必要があるためです。

List<String> generics = new ArrayList<String>();
List<String> raws = new ArrayList();

コンパイラーではコンストラクターでraw型を使用できますが、警告メッセージが表示されます。

ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized

4. ダイヤモンドオペレーター

ダイアモンド演算子– Java 1.7で導入– は型推論を追加し、割り当ての冗長性を減らします–ジェネリックスを使用する場合:

List<String> cars = new ArrayList<>();

Java 1.7コンパイラの型推論機能は、呼び出しに一致する最も適切なコンストラクタ宣言を決定します。

車両とエンジンを操作するための次のインターフェースとクラス階層を検討してください。

public interface Engine { }
public class Diesel implements Engine { }
public interface Vehicle<T extends Engine> { }
public class Car<T extends Engine> implements Vehicle<T> { }

ダイヤモンド演算子を使用して、Carの新しいインスタンスを作成しましょう。

Car<Diesel> myCar = new Car<>();

内部的には、コンパイラーはDieselEngineインターフェースを実装していることを認識しており、タイプを推測することで適切なコンストラクターを判別できます。

5. 結論

簡単に言えば、diamond演算子は型推論機能をコンパイラーに追加し、ジェネリックスで導入された割り当ての冗長性を減らします。

このチュートリアルのいくつかの例は、GitHubプロジェクトにありますので、ダウンロードして試してみてください。