Параметризацию иногда упрекают в том, что она увеличивает объем кода. Для наглядности возьмем пример holding/MapOfList.java из главы 11. Создание контейнера Map с List выглядит так:
Map<Person, List<? extends Pet>> petPeople =
new HashMap<Person, List<? extends Pet>>():
(Ключевое слово extends и вопросительные знаки будут описаны позднее в этой главе.) Казалось бы, эта конструкция избыточна, а компилятор мог бы вычислить один из списков аргументов по-другому. В действительности сделать это он не может, но вычисление аргументов типов все же позволяет немного упростить код. Например, мы можем создать вспомогательную библиотеку с различными статическими методами, содержащими самые распространенные реализации различных контейнеров:
//: net/mindview/util/New.java
// Utilities to simplify generic container creation
// by using type argument inference.
package net.mindview.util;
import java.util.*;
public class New {
public static <K,V> Map<K,V> map() {
return new HashMap<K,V>();
}
public static <T> List<T> list() {
return new ArrayList<T>();
}
public static <T> LinkedList<T> lList() {
return new LinkedList<T>();
}
public static <T> Set<T> set() {
return new HashSet<T>();
}
public static <T> Queue<T> queue() {
return new LinkedList<T>();
}
// Примеры:
public static void main(String[] args) {
Map<String, List<String>> sls = New.map();
List<String> ls = New.list();
LinkedList<String> lls = New.lList();
Set<String> ss = New.set();
Queue<String> qs = New.queue();
}
}
Примеры использования представлены в main() — вычисление аргументов типов устраняет необходимость в повторении списков параметров. Этот прием можно использовать в holding/MapOfList.java:
Пример интересный, однако трудно сказать, насколько он эффективен в действительности. Человеку, читающему код, придется просмотреть дополнительную библиотеку и разобраться в ее коде. Возможно, вместо этого стоит оставить исходное (пусть и избыточное) определение — как ни парадоксально, этот вариант проще. Хотя, если в стандартную библиотеку Java будет добавлено некое подобие New.java, им можно будет пользоваться. Вычисление типов не работает ни в каких других ситуациях, кроме присваивания. Если передать результат вызова метода (скажем, New.map()) в аргументе другого метода, компилятор не пытается выполнить вычисление типа. Вместо этого вызов метода интерпретируется так, как если бы возвращаемое значение присваивалось переменной типа Object. Пример ошибки такого рода: