1.雙括號初始化
使用雙大括號初始化(
以下簡稱雙大括號初始化)是一種 Java 工具,用於在聲明列表、集合和映射等集合的同時創建它們。
當您需要具有固定元素的清單(例如支援的產品或貨幣單位的清單)時,在初始化清單的同時聲明該清單可以提高程式碼的可讀性。這就是雙括號初始化越來越受歡迎的原因,因為沒有其他標準方法可以在程式碼中同時初始化來建立集合。不幸的是,與其他程式語言不同,Java 不支援文字集合。由於這個限制,即使創建一個
包含少量元素的不可修改列表,也會迫使我們以重複調用的形式編寫許多行程式碼,
add()
以添加所需的元素並進行最終包裝:
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(3);
list.add(5);
list.add(7);
List<Integer> unmodifiableList = Collections.unmodifiableList(list);
這是不必要的冗餘描述,可以簡化。讓我們以一種方便的方式填充靜態列表,即在初始化期間直接在靜態區塊中填充,這就是
Double brace
初始化將幫助我們的,允許我們將所有內容寫在一行中:
List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>() {{
add(2);
add(3);
add(5);
}});
同樣,
Double brace
初始化會幫助我們填入值 和
HashMap
:
Map<Integer, String> intToString = new HashMap<Integer, String>(){{
put(1, "one");
put(2, "two");
put(3, "three");
}};
這一切看起來都很優雅,但它有其缺點,這使得雙括號初始化成為一種反模式。我們將在下一章進一步討論它們。
雙括號初始化的優點和缺點。
Double
大括號初始化使用匿名內部類別的創建。然而,最初隱藏在表面上的東西,
Double brace
初始化會創建一個類,並在每次使用它時進一步初始化其實例。此外,使用了對此私有類別的隱藏引用,這可能會導致記憶體洩漏。您也不能對泛型使用幽靈運算子(菱形運算子 < >),因為我們無法存取匿名類別的內部。
(譯者:再次更詳細地講:
在第一個之後{ ,創建了一個內部匿名類,在第二個之後,{ 在創建該類的實例時進行初始化,在該實例中我們可以訪問外部(相對於匿名)類。) |
優點:
- 減少程式碼行數
- 在一個表達式中建立和初始化。
缺點:
- 建立一個對您隱藏的匿名類別。
- 每次我們使用它的實例時,這都會為我們帶來額外的費用。
- 每次創建對其的隱藏引用時,都可能導致記憶體洩漏。
結論:由於上述缺點以及雙大括號替代方案的存在,初始化在 Java 世界中被視為反模式。
Java 中雙大括號初始化的替代方案
好消息是,在 Java 中還有其他方法可以實現相同的目標。我們可以使用 Collection 類別中的 Copy 建構子在一行程式碼中實作 ArrayList 的建立和初始化,如下所示:
List<Integer> list = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(2, 3, 5)));
Arrays.asList()
將會傳回一個傳遞給
ArrayList
複製建構函式的固定長度清單。請記住從
Arrays.asList()
和傳回的固定長度清單之間的差異
Collections.unmodifiableList()
:您無法新增或刪除
ArrayList
- 的元素,但您可以使用 來透過索引變更元素
set()
,而對於 所傳回的清單則無法執行此操作
Collections.unmodifiableList()
。如果你想獲得一個小列表,這是最好的方法,儘管它對於其他集合來說不太透明
Set
,所以你必須
List
在創建
Set
-a 之前創建它。但這仍然比雙括號初始化更好,因為在這種情況下,每次使用時都不會建立額外的內部匿名類別。如果您執行的是 Java 8,您還有另一種替代方法。JDK 8 Stream API 將透過將輸出
Stream Factory
方法組合到集合中來幫助您建立小型集合
List
:
List<String> list = Collections.unmodifiableList(Stream.of("abc", "bcd", "cde").collect(toList()));
Set
您可以使用以下
Collectors.toSet()
方法 代替
Collectors.toList()
:
Set<String> set = Collections.unmodifiableSet(Stream.of("abc", "bcd", "cde").collect(toSet()));
順便說一句,
Stream collect
方法並不能保證它們產生的集合不會被更改。在 Java 8 中,它們傳回的集合(例如 -
ArrayList
、
HashSet
和
HashMap
)非常常見(我們可以更改它們),但這一事實可能會在未來的 JDK 版本中得到修正。
Double brace
這就是關於Java 初始化的全部內容。該模板對於測試和演示來說是可以接受的,但對於生產使用來說還不夠好。由於其固有的缺點,雙括號初始化如今已成為一種反模式,特別是考慮到可用的替代方案。我自己仍然使用這個構造來初始化靜態地圖,僅此而已。因為我更喜歡透過與建構函數中的創建相結合來
List
創建。如果我使用 Java 8 - 使用 Stream API 和.
相關文章:如果您喜歡本教程並且想要了解有關 Java 程式設計模式、原理和最佳實踐的更多信息,您可能還想查看我們
網站上的其他文章。
推薦閱讀:如果您想了解更多有關模式和最佳實踐的信息,您應該閱讀
Joshua Bloch 的《有效編程》,沒有一本書可以取代它。而如果你已經精通Java,並且正在尋找一本關於設計模式的書,其幽默的講授風格有趣且易於閱讀,請關注
《Head First》。設計模式”。
Collections
Array.asList
collect()
譯者:我特意提供了布洛赫原著的鏈接,因為它翻譯成俄語並不成功(例如,Builder = 構造函數)。 |
文章翻譯什麼是 Java 中的雙括號初始化?反模式範例(2015 年 10 月發布)。
GO TO FULL VERSION