Java怎樣創(chuàng)建集合才能避免造成內(nèi)存泄漏你了解嗎
由于Java語(yǔ)言的集合框架中(collections, 如list, map, set等)沒(méi)有提供任何簡(jiǎn)便的語(yǔ)法結(jié)構(gòu),這使得在建立常量集合時(shí)的工作非常繁索。每次建立時(shí)我們都要做:
1、定義一個(gè)空的集合類(lèi)變量
2、向這個(gè)結(jié)合類(lèi)中逐一添加元素
3、將集合做為參數(shù)傳遞給方法
例如,要將一個(gè)Set變量傳給一個(gè)方法:
Set users = new HashSet(); users.add("Hollis"); users.add("hollis"); users.add("HollisChuang"); users.add("hollis666"); transferUsers(users);
這樣的寫(xiě)法稍微有些復(fù)雜,有沒(méi)有簡(jiǎn)潔的方式呢?
雙括號(hào)語(yǔ)法初始化集合
其實(shí)有一個(gè)比較簡(jiǎn)潔的方式,那就是雙括號(hào)語(yǔ)法(double-brace syntax
)建立并初始化一個(gè)新的集合:
public class DoubleBraceTest { public static void main(String[] args) { Set users = new HashSet() {{ add("Hollis"); add("hollis"); add("HollisChuang"); add("hollis666"); }}; } }
同理,創(chuàng)建并初始化一個(gè)HashMap的語(yǔ)法如下:
Map<String,String> users = new HashMap<>() {{ put("Hollis","Hollis"); put("hollis","hollis"); put("HollisChuang","HollisChuang"); }};
不只是Set、Map,jdk中的集合類(lèi)都可以用這種方式創(chuàng)建并初始化。
當(dāng)我們使用這種雙括號(hào)語(yǔ)法初始化集合類(lèi)的時(shí)候,在對(duì)Java文件進(jìn)行編譯時(shí),可以發(fā)現(xiàn)一個(gè)奇怪的現(xiàn)象,使用javac對(duì)DoubleBraceTest進(jìn)行編譯:
javac DoubleBraceTest.java
我們會(huì)發(fā)現(xiàn),得到兩個(gè)class文件:
DoubleBraceTest.class DoubleBraceTest$1.class
有經(jīng)驗(yàn)的朋友可能一看到這兩個(gè)文件就會(huì)知道,這里面一定用到了匿名內(nèi)部類(lèi)。
沒(méi)錯(cuò),使用這個(gè)雙括號(hào)初始化的效果是創(chuàng)建匿名內(nèi)部類(lèi)。創(chuàng)建的類(lèi)有一個(gè)隱式的this指針指向外部類(lèi)。
不建議使用這種形式
首先,使用這種形式創(chuàng)建并初始化集合會(huì)導(dǎo)致很多內(nèi)部類(lèi)被創(chuàng)建。因?yàn)槊看问褂秒p大括號(hào)初始化時(shí),都會(huì)生成一個(gè)新類(lèi)。如這個(gè)例子:
Map hollis = new HashMap(){{ put("firstName", "Hollis"); put("lastName", "Chuang"); put("contacts", new HashMap(){{ put("0", new HashMap(){{ put("blogs", "http://www.hollischuang.com"); }}); put("1", new HashMap(){{ put("wechat", "hollischuang"); }}); }}); }};
這會(huì)使得很多內(nèi)部類(lèi)被創(chuàng)建出來(lái):
DoubleBraceTest$1$1$1.class DoubleBraceTest$1$1$2.class DoubleBraceTest$1$1.class DoubleBraceTest$1.class DoubleBraceTest.class
這些內(nèi)部類(lèi)被創(chuàng)建出來(lái),是需要被類(lèi)加載器加載的,這就帶來(lái)了一些額外的開(kāi)銷(xiāo)。
如果您使用上面的代碼在一個(gè)方法中創(chuàng)建并初始化一個(gè)map,并從方法返回該map,那么該方法的調(diào)用者可能會(huì)毫不知情地持有一個(gè)無(wú)法進(jìn)行垃圾收集的資源。
public Map getMap() { Map hollis = new HashMap(){{ put("firstName", "Hollis"); put("lastName", "Chuang"); put("contacts", new HashMap(){{ put("0", new HashMap(){{ put("blogs", "http://www.hollischuang.com"); }}); put("1", new HashMap(){{ put("wechat", "hollischuang"); }}); }}); }}; return hollis; }
我們嘗試通過(guò)調(diào)用getMap得到這樣一個(gè)通過(guò)雙括號(hào)初始化出來(lái)的map
public class DoubleBraceTest { public static void main(String[] args) { DoubleBraceTest doubleBraceTest = new DoubleBraceTest(); Map map = doubleBraceTest.getMap(); } }
返回的Map現(xiàn)在將包含一個(gè)對(duì)DoubleBraceTest的實(shí)例的引用。讀者可以嘗試這通過(guò)debug或者以下方式確認(rèn)這一事實(shí)。
Field field = map.getClass().getDeclaredField("this$0"); field.setAccessible(true); System.out.println(field.get(map).getClass());
替代方案
很多人使用雙括號(hào)初始化集合,主要是因?yàn)樗容^方便,可以在定義集合的同時(shí)對(duì)他進(jìn)行初始化。
但其實(shí),目前已經(jīng)有很多方案可以做這個(gè)事情了,不需要再使用這種存在風(fēng)險(xiǎn)的方案。
使用Arrays工具類(lèi)
當(dāng)我們想要初始化一個(gè)List的時(shí)候,可以借助Arrays類(lèi),Arrays中提供了asList可以把一個(gè)數(shù)組轉(zhuǎn)換成List:
List<String> list2 = Arrays.asList("hollis ", "Hollis", "HollisChuang");
但是需要注意的是,asList 得到的只是一個(gè) Arrays 的內(nèi)部類(lèi),是一個(gè)原來(lái)數(shù)組的視圖 List,因此如果對(duì)它進(jìn)行增刪操作會(huì)報(bào)錯(cuò)。
使用Stream
Stream是Java中提供的新特性,他可以對(duì)傳入流內(nèi)部的元素進(jìn)行篩選、排序、聚合等中間操作(intermediate operate),最后由最終操作(terminal operation)得到前面處理的結(jié)果。
我們可以借助Stream來(lái)初始化集合:
List<String> list1 = Stream.of("hollis", "Hollis", "HollisChuang").collect(Collectors.toList());
使用第三方工具類(lèi)
很多第三方的集合工具類(lèi)可以實(shí)現(xiàn)這個(gè)功能,如Guava等:
ImmutableMap.of("k1", "v1", "k2", "v2"); ImmutableList.of("a", "b", "c", "d");
關(guān)于Guava和其中定義的不可變集合,我們?cè)诤竺鏁?huì)詳細(xì)介紹
Java 9內(nèi)置方法
其實(shí)在Java 9 中,在List、Map等集合類(lèi)中已經(jīng)內(nèi)置了初始化的方法,如List中包含了12個(gè)重載的of方法,就是來(lái)做這個(gè)事情的:
/** * Returns an unmodifiable list containing zero elements. * * See <a href="#unmodifiable" rel="external nofollow" >Unmodifiable Lists</a> for details. * * @param <E> the {@code List}'s element type * @return an empty {@code List} * * @since 9 */ static <E> List<E> of() { return ImmutableCollections.emptyList(); } static <E> List<E> of(E e1) { return new ImmutableCollections.List12<>(e1); } static <E> List<E> of(E... elements) { switch (elements.length) { // implicit null check of elements case 0: return ImmutableCollections.emptyList(); case 1: return new ImmutableCollections.List12<>(elements[0]); case 2: return new ImmutableCollections.List12<>(elements[0], elements[1]); default: return new ImmutableCollections.ListN<>(elements); } }
到此這篇關(guān)于Java怎樣創(chuàng)建集合才能避免造成內(nèi)存泄漏你了解嗎的文章就介紹到這了,更多相關(guān)Java 集合內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springcloud引入spring-cloud-starter-openfeign失敗的解決
這篇文章主要介紹了springcloud?引入spring-cloud-starter-openfeign失敗的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot集成Quartz實(shí)現(xiàn)定時(shí)任務(wù)的方法
Quartz是一個(gè)定時(shí)任務(wù)框架,其他介紹網(wǎng)上也很詳盡。這里要介紹一下Quartz里的幾個(gè)非常核心的接口。通過(guò)實(shí)例代碼給大家講解SpringBoot集成Quartz實(shí)現(xiàn)定時(shí)任務(wù)的方法,感興趣的朋友一起看看吧2020-05-05淺談Java中生產(chǎn)者與消費(fèi)者問(wèn)題的演變
這篇文章主要介紹了淺談Java中生產(chǎn)者與消費(fèi)者問(wèn)題的演變,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10springboot+redis過(guò)期事件監(jiān)聽(tīng)實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了springboot+redis過(guò)期事件監(jiān)聽(tīng)實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03springboot2.x只需兩步快速整合log4j2的方法
這篇文章主要介紹了springboot2.x只需兩步快速整合log4j2的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05基于Spring框架由ConditionalOnMissingBean注解引發(fā)的問(wèn)題
這篇文章主要介紹了基于Spring框架由ConditionalOnMissingBean注解引發(fā)的問(wèn)題,具有很好2023-11-11SpringBoot和Vue實(shí)現(xiàn)動(dòng)態(tài)二維碼的示例代碼
二維碼在現(xiàn)代社交和營(yíng)銷(xiāo)活動(dòng)中被廣泛使用,本文主要介紹了SpringBoot和Vue實(shí)現(xiàn)動(dòng)態(tài)二維碼的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-02-02SpringBoot整合Redis實(shí)現(xiàn)刷票過(guò)濾功能
隨著互聯(lián)網(wǎng)的不斷發(fā)展,網(wǎng)站或APP的用戶流量增加,也衍生出了一些惡意刷量等問(wèn)題,給數(shù)據(jù)分析及運(yùn)營(yíng)帶來(lái)極大的困難,所以本文使用SpringBoot和Redis實(shí)現(xiàn)一個(gè)刷票過(guò)濾功能,需要的可以參考一下2023-06-06RocketMQMessageListener注解對(duì)rocketmq消息的消費(fèi)實(shí)現(xiàn)機(jī)制
這篇文章主要為大家介紹了RocketMQMessageListener注解對(duì)rocketmq消息的消費(fèi)實(shí)現(xiàn)機(jī)制源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10SpringBoot啟動(dòng)器Starters使用及原理解析
這篇文章主要介紹了SpringBoot啟動(dòng)器Starters使用及原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04