Java 9增強的「菱形」語法

2020-07-16 10:05:16
在 Java 7 版本以前,如果使用帶泛型的介面、類定義變數,那麼呼叫構造器建立物件時構造器的後面也必須帶泛型,這顯得有些多餘了。例如如下兩條語句:
List<String> strList = new ArrayList<String>();
Map<String, Integer> scores = new HashMap<String, Integer>();
上面兩條語句中等號右邊的尖括號部分完全是多餘的,Java 7 版本以前是必需的,不能省略。從 Java 7 開始,Java 允許在構造器後不帶完整的泛型資訊,只要給出一對尖括號<>即可。Java 可以推斷出尖括號裡應該是什麼泛型資訊。

即上面兩條語句可以改寫為如下形式:
List<String> strList = new ArrayList<>();
Map<String, Integer> scores = new HashMap<>();
把兩個尖括號並排放在一起非常像一個菱形,這種語法也就被稱為“菱形”語法。下面程式示範了 Java 7 的菱形語法。
public class Test {
    public static void main(String[] args) {
        // Java自動推斷出ArrayList的<>裡應該是String
        List<String> names = new ArrayList<>();
        names.add("C語言中文網Java入門教學");
        names.add("C語言中文網Spring入門教學");
        // 遍歷names集合,集合元素就是String型別
        names.forEach(ele -> System.out.println(ele.length()));
        // Java 自動推斷出 HashMap 的<>裡應該是 String,List<String>
        Map<String, List<String>> coursesInfo = new HashMap<>();
        // Java自動推斷出ArrayList的<>裡應該是String
        List<String> courses = new ArrayList<>();
        courses.add("Java入門教學");
        courses.add("Python基礎教學");
        coursesInfo.put("C語言中文網", courses);
        // 遍歷 Map 時,Map 的 key 是 String 型別,value List<String>型別
        coursesInfo.forEach((key, value) -> System.out.println(key + "-->" + value));
    }
}
上面程式中程式碼第 4、10 和 12 行程式碼就是“菱形”語法的範例。從該程式不難看出,“菱形”語法對原有的泛型並沒有改變,只是更好地簡化了泛型程式設計。

Java 9 再次增強了“菱形”語法,它甚至允許在建立匿名內部類時使用菱形語法,Java 可根據上下文來推斷匿名內部類中泛型的型別。下面程式示範了在匿名內部類中使用菱形語法。
interface Foo<T> {
    void test(T t);
}

public class AnnoymousTest {
    public static void main(String[] args) {
        // 指定Foo類中泛型為String
        Foo<String> f = new Foo<>() {
            // test()方法的引數型別為String
            public void test(String t) {
                System.out.println("test 方法的 t 引數為:" + t);
            }
        };
        // 使用泛型萬用字元,此時相當於萬用字元的上限為Object
        Foo<?> fo = new Foo<>() {
            // test()方法的引數型別為Object
            public void test(Object t) {
                System.out.println("test 方法的 Object 引數為:" + t);
            }
        };
        // 使用泛型萬用字元,萬用字元的上限為Number
        Foo<? extends Number> fn = new Foo<>() {
            // 此時test ()方法的引數型別為Number
            public void test(Number t) {
                System.out.println("test 方法的 Number 引數為:" + t);
            }
        };
    }
}
上面程式先定義了一個帶泛型宣告的介面,接下來第 8、15 和 22 行程式碼分別示範了在匿名內部類中使用菱形語法。第 8 行程式碼宣告變數時明確地將泛型指定為 String 型別,因此在該匿名內部類中 T 型別就代表了 String 型別;第 15 行程式碼宣告變數時使用萬用字元來代表泛型(相當於萬用字元的上限為 Object),因此系統只能推斷出 T 代表 Object,所以在該匿名內部類中 T 型別就代表了 Object 型別;第 22 行程式碼宣告變數時使用了帶上限(上限是 Number)的萬用字元,因此系統可以推斷出 T 代表 Number 類。

無論以上哪種方式,Java 9 都允許在使用匿名內部類時使用菱形語法。