ジェネリクスを使ったいくつかの実装のメモです。
Class<T>を受け取ってジェネリクス<T>を持つオブジェクトを返す
ジェネリクスを指定するものを普通に宣言してしまうと冗長になりやすいので、こういったオブジェクトを何度も生成する場合はUtilクラスへ生成関数を作った方がいいかなと思ってます。
実装例
// クラスに対応するListを返す関数
<T> List<T> generateList(Class<T> clazz) {
return new ArrayList<>();
}
// クラスに対応するBeanPropertyRowMapperを返す関数
<T> BeanPropertyRowMapper<T> getBeanPropertyRowMapper(Class<T> clazz) {
return new BeanPropertyRowMapper<>(clazz);
}
利用例
// こう書くと冗長
new BeanPropertyRowMapper<Something>(Something.class);
// こう書いた方が読みやすい
Util.getBeanPropertyRowMapper(Something.class);
型はどうでもいい時に警告/エラーを出さないように書く
「ジェネリクスを取る型を用いるが、中身の型は関係ない」ような場合、単純に型を省略して書くと警告が出ます。
警告が出る例
// ハッシュセットを用いた重複チェック
boolean checkForDuplicate(List list) {
return list.size() == new HashSet(list).size();
}
このような場合、<?>とダイヤモンド演算子で警告が出ないように書けます。
実装例
// ハッシュセットを用いた重複チェック
boolean checkForDuplicate(List<?> list) {
return list.size() == new HashSet<>(list).size();
}
<T>で指定することでも書けますが、ちょっと冗長になります。
冗長な実装例
// ハッシュセットを用いた重複チェック
<T> boolean checkForDuplicate(List<T> list) {
return list.size() == new HashSet<>(list).size();
}
Streamを使う場合
Listを引数にとってStream処理を行う場合も<?>を書かなければコンパイルが通らなかったりします。
コンパイルが通らない例
BeanPropertySqlParameterSource[] makeParamArray(List entities) {
return entities.stream()
.map(BeanPropertySqlParameterSource::new)
.toArray(BeanPropertySqlParameterSource[]::new);
}
コンパイルが通る例
BeanPropertySqlParameterSource[] makeParamArray(List<?> entities) {
return entities.stream()
.map(BeanPropertySqlParameterSource::new)
.toArray(BeanPropertySqlParameterSource[]::new);
}