泛型是 Java 5 引入的參數化類型機制,讓集合等容器擁有編譯期類型安全。但早期版本要求「宣告端」與「實例化端」雙雙寫入型別參數,顯得冗餘。Java 7 推出鑽石運算子 <>,Java 8 再大幅增強目標類型推斷,將推論範圍擴展至方法參數、建構子、Lambda 等語境,極大提升程式碼簡潔度。
| 版本 | 特性 | 範例 |
|---|---|---|
| Java 5 | 泛型引入 | List<String> list = new ArrayList<String>(); |
| Java 7 | 鑽石運算子 (實例化端推論) | List<String> list = new ArrayList<>(); |
| Java 8 | 目標類型推斷 (方法/建構子/Lambda) | List<String> list = Collections.emptyList(); |
Map<String, Integer> map = new HashMap<>(); // 編譯器從左側推斷右側型別
// 注意:必須保留 <>,否則為原始類型,會有 unchecked 警告
限制:僅適用於「變數宣告 + 實例化」同一語句,無法用於方法參數傳遞:
// Java 7 編譯失敗
list.addAll(new ArrayList<>()); // 無法推斷型別參數
目標類型:編譯器根據表達式出現的語境,預期的具體類型。例如:
static <T> List<T> emptyList() { ... }
// Java 7 需顯式指定
List<String> list7 = Collections.<String>emptyList();
// Java 8 直接推斷
List<String> list8 = Collections.emptyList(); // 目標類型 List 推斷 T=String
static <T> T pick(T a1, T a2) { return a2; }
Serializable s = pick("d", new ArrayList<String>());
// 推斷 T = Serializable (String 與 ArrayList 共同父介面)
class MyClass<X> {
<T> MyClass(T t) { ... }
}
// Java 8 同時推斷類別型別參數 X 與建構子型別參數 T
MyClass<Integer> obj = new MyClass<>("hello"); // X=Integer, T=String
這是 Java 8 類型推論威力最大的應用場景:
// 無目標類型:編譯錯誤
// var fn = x -> x + 1;
// 有目標類型:完美推斷
Function<Integer, Integer> fn = x -> x + 1;
Comparator<String> cmp = (a, b) -> a.length() - b.length();
Runnable r = () -> System.out.println("Hello");
編譯器從函數式介面的單一抽象方法 (SAM) 簽名推斷 Lambda 參數與回傳型別。
List<String> list = List.of("a", "b", "c"); // Java 9+ 不可變集合
Set<Integer> set = Set.of(1, 2, 3);
Map<String, Integer> map = Map.of("a", 1, "b", 2);
List<String> result = list.stream()
.filter(s -> s.length() > 3) // 推斷 s: String
.map(String::toUpperCase) // 推斷 String -> String
.collect(Collectors.toList()); // 目標類型 List
Optional<User> opt = findUser(id);
String name = opt.map(User::getName) // Optional
.orElse("Guest");
User user = User.builder()
.name("Tom")
.age(25)
.email("tom@example.com")
.build(); // 目標類型 User 推斷建構者泛型
Object),需顯式指定:Collections.<String>emptyList()。List vs List<String>) 會阻斷推論,保留 <> 習慣。Java 8 的類型推論升級,核心在於目標類型概念的引入,將推論從「宣告-實例化」雙邊延伸至方法呼叫、建構子、Lambda、Stream 等完整表達式語境。配合鑽石運算子 <>,開發者終於能專注業務邏輯,而非重複撰寫型別參數。善用此特性,配合現代 IDE 的型別顯示功能,即可寫出兼具型別安全與簡潔優雅的程式碼。