ジェネリックスについての理解
Javadocを眺めていると、ジェネリクスを利用したクラス、メソッド、インターフェースが存在します。Eとか、Kとか記載されていると、パラメータの意味が分からず読み飛ばしている方もいるのではないでしょうか?
そのような方のために、ジェネリック型を見かけてもドキュメントやコードが読めるよう解説をしたいと思います。
ジェネリック型とは、型に対してパラメータ化されるジェネリッククラスまたはインターフェースとなります。
ジェネリックス型を利用せず、汎用的な型を扱う場合は以下のようになります。
public class Box {
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
ジェネリックス型で定義した場合、以下のようなコードになります。
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
JavaDocで記載されているパラメータ名を紹介します。
- E - Element(要素)コレクションで利用
- K - Key(キー)
- N - Number(数値)
- T - Type(タイプ)
- V - Value(値)
- S,U,V etc - 2番目、3番目、4番目のType
ジェネリックスの具体的な書き方について
複数のタイプパラメータを扱うジェネリッククラス
ジェネリッククラスは複数の型パラメータを持つことが出来ます。例えばPairインターフェースを実装したOrderedPairクラスを例として記載します。
// 型パラメータを受け取るインターフェース
public interface Pair<K, V> {
public K getKey();
public V getValue();
}
// Pairインターフェースを実装したOrderPairクラス
public class OrderedPair<K, V> implements Pair<K, V> {
private K key;
private V value;
public OrderedPair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
OrderedPairクラスについては、以下のようなインスタンスを作成可能です。
ジェネリックについては型総称となるため、後付けでの型定義が可能となります。
Pair<String, Integer> p1 = new OrderedPiar<String, Integer>("Even", 8);
Pair<String, Integer> p2 = new OrderedPiar<String, Integer>("Hello", "world");
// ダイアモンド演算子でも定義可能
OrderedPiar<String, Integer> p3 = new OrderedPiar<>("Even", 8);
OrderedPiar<String, Integer> p4 = new OrderedPiar<>("Hello", "world");
パラメータ化された型でも定義可能
OrderedPair<String, Box<Integer>> p5 = new OrderedPair<>("xxxx", new Box<integer>(...));
実例
コードの解説をします。コードを読むと次のような解釈ができると思います。
FutureServiceはfutureクラスを引数に受け取り結果を受け取るメソッドが準備されている。
external.fetchBoxInfo()を非同期で実行し、結果boxDetailを受け取っている。
// 外部サービスAPIを非同期で実行
Future<BoxDetail> future = externalApi.fetchBoxInfo();
BoxDetail boxDetail = futureService.handleResult(future);
// 非同期処理を共通化
class FutureService {
public <T> T handleResult( Future<T> future )
{
if( timeout <= 0 ) {
// エラー処理
thow xxxException;
}
try {
return future.get(timeout, timeUnit);
} catch ( ExcecuteException | InterruptedException e ) {
throw xxxException
}
}
}
まとめ
「ジェネリックスについての理解」で紹介した内容についてはJavaDocチュートリアルに記載されている内容になります
ジェネリックスについては、Javaの初級研修のスコープ外かと思います。そのため慣れない記述を見ると躓てしまう方もいるかと思います。
今後躓かないためにも基礎をしっかり学ぶことで基本的なコードを読む・書くことできるようになるかと思います。基礎をしっかり学んでいきましょう。