欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

工作中Java集合的規(guī)范使用操作詳解

 更新時(shí)間:2022年11月29日 10:04:16   作者:卡布奇諾-海晨  
這篇文章主要為大家詳細(xì)介紹了工作中Java集合使用時(shí)需要注意的規(guī)范,文中的示例代碼講解詳細(xì),對(duì)我們使用Java集合有一定的幫助,感興趣的可以了解一下

一、前言

現(xiàn)代軟件行業(yè)的高速發(fā)展對(duì)開發(fā)者的綜合素質(zhì)要求越來(lái)越高,因?yàn)椴粌H是編程知識(shí)點(diǎn),其它維度的知識(shí)點(diǎn)也會(huì)影響到軟件的最終交付質(zhì)量。比如:五花八門的錯(cuò)誤碼會(huì)人為地增加排查問(wèn)題的難度;數(shù)據(jù)庫(kù)的表結(jié)構(gòu)和索引設(shè)計(jì)缺陷帶來(lái)的系統(tǒng)架構(gòu)缺陷或性能風(fēng)險(xiǎn);工程結(jié)構(gòu)混亂導(dǎo)致后續(xù)項(xiàng)目維護(hù)艱難;沒有鑒權(quán)的漏洞代碼容易被黑客攻擊等。依據(jù)約束力強(qiáng)弱及故障敏感性,規(guī)約依次分為【強(qiáng)制】、【推薦】、【參考】三大類。在延伸的信息中,“說(shuō)明”對(duì)規(guī)約做了適當(dāng)擴(kuò)展和解釋;“正例”提倡什么樣的編碼和實(shí)現(xiàn)方式;“反例”說(shuō)明需要提防的雷區(qū),以及真實(shí)的錯(cuò)誤案例。

現(xiàn)代軟件架構(gòu)的復(fù)雜性需要協(xié)同開發(fā)完成,如何高效地協(xié)同呢?無(wú)規(guī)矩不成方圓,無(wú)規(guī)范難以協(xié)同,比如,制定交通法規(guī)表面上是要限制行車權(quán),實(shí)際上是保障公眾的人身安全,試想如果沒有限速,沒有紅綠燈,誰(shuí)還敢上路行駛?對(duì)軟件來(lái)說(shuō),適當(dāng)?shù)囊?guī)范和標(biāo)準(zhǔn)絕不是消滅代碼內(nèi)容的創(chuàng)造性、優(yōu)雅性,而是限制過(guò)度個(gè)性化,以一種普遍認(rèn)可的統(tǒng)一方式一起做事,提升協(xié)作效率,降低溝通成本。代碼的字里行間流淌的是軟件系統(tǒng)的血液,代碼質(zhì)量的提升是盡可能少踩坑,杜絕踩重復(fù)的坑,切實(shí)提升系統(tǒng)穩(wěn)定性,碼出質(zhì)量。

二、規(guī)范使用Java集合

1.【強(qiáng)制】關(guān)于 hashCode 和 equals 的處理,遵循如下規(guī)則:

1)只要覆寫 equals,就必須覆寫 hashCode。

2)因?yàn)?Set 存儲(chǔ)的是不重復(fù)的對(duì)象,依據(jù) hashCode 和 equals 進(jìn)行判斷,所以 Set 存儲(chǔ)的對(duì)象必須覆寫這兩種方法。

3)如果自定義對(duì)象作為 Map 的鍵,那么必須覆寫 hashCode 和 equals。

說(shuō)明:String 因?yàn)楦矊懥?hashCode 和 equals 方法,所以可以愉快地將 String 對(duì)象作為 key 來(lái)使用。

2.【強(qiáng)制】判斷所有集合內(nèi)部的元素是否為空,使用 isEmpty() 方法,而不是 size() == 0 的方式。

說(shuō)明:在某些集合中,前者的時(shí)間復(fù)雜度為 O(1),而且可讀性更好。

正例:

Map<String, Object> map = new HashMap<>(16);
if (map.isEmpty()) {
System.out.println("no element in this map.");
}

3.【強(qiáng)制】在使用 java.util.stream.Collectors 類的 toMap() 方法轉(zhuǎn)為 Map 集合時(shí),一定要使用參數(shù)類型為 BinaryOperator,參數(shù)名為 mergeFunction 的方法,否則當(dāng)出現(xiàn)相同 key 時(shí)會(huì)拋出

IllegalStateException 異常。

說(shuō)明:參數(shù) mergeFunction 的作用是當(dāng)出現(xiàn) key 重復(fù)時(shí),自定義對(duì) value 的處理策略。

正例:

List<Pair<String, Double>> pairArrayList = new ArrayList<>(3);
pairArrayList.add(new Pair<>("version", 12.10));
pairArrayList.add(new Pair<>("version", 12.19));
pairArrayList.add(new Pair<>("version", 6.28));
// 生成的 map 集合中只有一個(gè)鍵值對(duì):{version=6.28}
Map<String, Double> map = pairArrayList.stream()
.collect(Collectors.toMap(Pair::getKey, Pair::getValue, (v1, v2) -> v2));

反例:

String[] departments = new String[]{"RDC", "RDC", "KKB"};
// 拋出 IllegalStateException 異常
Map<Integer, String> map = Arrays.stream(departments)
.collect(Collectors.toMap(String::hashCode, str -> str));

4.【強(qiáng)制】在使用 java.util.stream.Collectors 類的 toMap() 方法轉(zhuǎn)為 Map 集合時(shí),一定要注意當(dāng) value為 null 時(shí)會(huì)拋 NPE 異常。

說(shuō)明:在 java.util.HashMap 的 merge 方法里會(huì)進(jìn)行如下的判斷:

if (value == null || remappingFunction == null)
throw new NullPointerException();

反例:

List<Pair<String, Double>> pairArrayList = new ArrayList<>(2);
pairArrayList.add(new Pair<>("version1", 8.3));
pairArrayList.add(new Pair<>("version2", null));
// 拋出 NullPointerException 異常
Map<String, Double> map = pairArrayList.stream()
.collect(Collectors.toMap(Pair::getKey, Pair::getValue, (v1, v2) -> v2));

5.【強(qiáng)制】ArrayList 的 subList 結(jié)果不可強(qiáng)轉(zhuǎn)成 ArrayList,否則會(huì)拋出 ClassCastException 異常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。

說(shuō)明:subList() 返回的是 ArrayList 的內(nèi)部類 SubList,并不是 ArrayList 本身,而是 ArrayList 的一個(gè)視圖,對(duì)于SubList 的所有操作最終會(huì)反映到原列表上。同時(shí)注意數(shù)組越界異常。

6.【強(qiáng)制】使用 Map 的方法 keySet() / values() / entrySet() 返回集合對(duì)象時(shí),不可以對(duì)其進(jìn)行添加元素操作,否則會(huì)拋出 UnsupportedOperationException 異常。

7.【強(qiáng)制】Collections 類返回的對(duì)象,如:emptyList() / singletonList() 等都是 immutable list,不可對(duì)其進(jìn)行添加或者刪除元素的操作。

反例:如果查詢無(wú)結(jié)果,返回 Collections.emptyList() 空集合對(duì)象,調(diào)用方一旦在返回的集合中進(jìn)行了添加元素的操作,就會(huì)觸發(fā) UnsupportedOperationException 異常。

8.【強(qiáng)制】在 subList 場(chǎng)景中,高度注意對(duì)父集合元素的增加或刪除,均會(huì)導(dǎo)致子列表的遍歷、增加、刪除產(chǎn)生 ConcurrentModificationException 異常。

說(shuō)明:抽查表明,90% 的程序員對(duì)此知識(shí)點(diǎn)都有錯(cuò)誤的認(rèn)知。

9.【強(qiáng)制】使用集合轉(zhuǎn)數(shù)組的方法,必須使用集合的 toArray(T[] array),傳入的是類型完全一致、長(zhǎng)度為0 的空數(shù)組。

反例:直接使用 toArray 無(wú)參方法存在問(wèn)題,此方法返回值只能是 Object[]類,若強(qiáng)轉(zhuǎn)其它類型數(shù)組將出現(xiàn)ClassCastException 錯(cuò)誤。

正例:

List<String> list = new ArrayList<>(2);
list.add("guan");
list.add("bao");
String[] array = list.toArray(new String[0]);

說(shuō)明:使用 toArray 帶參方法,數(shù)組空間大小的 length:

1)等于 0,動(dòng)態(tài)創(chuàng)建與 size 相同的數(shù)組,性能最好。

2)大于 0 但小于 size,重新創(chuàng)建大小等于 size 的數(shù)組,增加 GC 負(fù)擔(dān)。

3)等于 size,在高并發(fā)情況下,數(shù)組創(chuàng)建完成之后,size 正在變大的情況下,負(fù)面影響與 2 相同。

4)大于 size,空間浪費(fèi),且在 size 處插入 null 值,存在 NPE 隱患。

10.【強(qiáng)制】使用 Collection 接口任何實(shí)現(xiàn)類的 addAll() 方法時(shí),要對(duì)輸入的集合參數(shù)進(jìn)行 NPE 判斷。

說(shuō)明:在 ArrayList#addAll 方法的第一行代碼即 Object[] a = c.toArray();其中 c 為輸入集合參數(shù),如果為 null,則直接拋出異常。

11.【強(qiáng)制】使用工具類 Arrays.asList() 把數(shù)組轉(zhuǎn)換成集合時(shí),不能使用其修改集合相關(guān)的方法,它的 add/ remove / clear 方法會(huì)拋出 UnsupportedOperationException 異常。

說(shuō)明:asList 的返回對(duì)象是一個(gè) Arrays 內(nèi)部類,并沒有實(shí)現(xiàn)集合的修改方法。Arrays.asList 體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,后臺(tái)的數(shù)據(jù)仍是數(shù)組。

String[] str = new String[]{ "yang", "guan", "bao" };
List list = Arrays.asList(str);

第一種情況:list.add("yangguanbao"); 運(yùn)行時(shí)異常。

第二種情況:str[0] = "change"; list 中的元素也會(huì)隨之修改,反之亦然。

12.【強(qiáng)制】泛型通配符<? extends T>來(lái)接收返回的數(shù)據(jù),此寫法的泛型集合不能使用 add 方法,而<? super T>不能使用 get 方法,兩者在接口調(diào)用賦值的場(chǎng)景中容易出錯(cuò)。

說(shuō)明:擴(kuò)展說(shuō)一下 PECS(Producer Extends Consumer Super) 原則,即頻繁往外讀取內(nèi)容的,適合用<? extends T>,經(jīng)常往里插入的,適合用<? super T>

13.【強(qiáng)制】在無(wú)泛型限制定義的集合賦值給泛型限制的集合時(shí),在使用集合元素時(shí),需要進(jìn)行instanceof 判斷,避免拋出 ClassCastException 異常。

說(shuō)明:畢竟泛型是在 JDK5 后才出現(xiàn),考慮到向前兼容,編譯器是允許非泛型集合與泛型集合互相賦值。

反例:

List<String> generics = null;
List notGenerics = new ArrayList(10);
notGenerics.add(new Object());
notGenerics.add(new Integer(1));
generics = notGenerics;
// 此處拋出 ClassCastException 異常
String string = generics.get(0);

14.【強(qiáng)制】不要在 foreach 循環(huán)里進(jìn)行元素的 remove / add 操作。remove 元素請(qǐng)使用 iterator 方式,如果并發(fā)操作,需要對(duì) iterator 對(duì)象加鎖。

正例:

List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (刪除元素的條件) {
iterator.remove();
}
}

反例:

for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}

說(shuō)明:反例中的執(zhí)行結(jié)果肯定會(huì)出乎大家的意料,那么試一下把“1”換成“2”會(huì)是同樣的結(jié)果嗎?

15.【強(qiáng)制】在 JDK7 版本及以上,Comparator 實(shí)現(xiàn)類要滿足如下三個(gè)條件,不然 Arrays.sort,Collections.sort 會(huì)拋 IllegalArgumentException 異常。

說(shuō)明:三個(gè)條件如下

1)x,y 的比較結(jié)果和 y,x 的比較結(jié)果相反。

2)x > y,y > z,則 x > z。

3)x = y,則 x,z 比較結(jié)果和 y,z 比較結(jié)果相同。

反例:下例中沒有處理相等的情況,交換兩個(gè)對(duì)象判斷結(jié)果并不互反,不符合第一個(gè)條件,在實(shí)際使用中可能會(huì)出現(xiàn)異常。

new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getId() > o2.getId() ? 1 : -1;
}
};

16.【推薦】泛型集合使用時(shí),在 JDK7 及以上,使用 diamond 語(yǔ)法或全省略。

說(shuō)明:菱形泛型,即 diamond,直接使用<>來(lái)指代前邊已經(jīng)指定的類型。

正例:

// diamond 方式,即<>
HashMap<String, String> userCache = new HashMap<>(16);
// 全省略方式
ArrayList<User> users = new ArrayList(10);

17.【推薦】集合初始化時(shí),指定集合初始值大小。

說(shuō)明:HashMap 使用構(gòu)造方法 HashMap(int initialCapacity) 進(jìn)行初始化時(shí),如果暫時(shí)無(wú)法確定集合大小,那么指定默認(rèn)值(16)即可。

正例:initialCapacity = (需要存儲(chǔ)的元素個(gè)數(shù) / 負(fù)載因子) + 1。注意負(fù)載因子(即 loaderfactor)默認(rèn)為 0.75,如果暫時(shí)無(wú)法確定初始值大小,請(qǐng)?jiān)O(shè)置為 16(即默認(rèn)值)。

反例:HashMap 需要放置 1024 個(gè)元素,由于沒有設(shè)置容量初始大小,隨著元素增加而不斷擴(kuò)容,resize() 方法總共會(huì)調(diào)用 8 次,反復(fù)重建哈希表和數(shù)據(jù)遷移。當(dāng)放置的集合元素個(gè)數(shù)達(dá)千萬(wàn)級(jí)時(shí)會(huì)影響程序性能。

18.【推薦】使用 entrySet 遍歷 Map 類集合 KV,而不是 keySet 方式進(jìn)行遍歷。

說(shuō)明:keySet 其實(shí)是遍歷了 2 次,一次是轉(zhuǎn)為 Iterator 對(duì)象,另一次是從 hashMap 中取出 key 所對(duì)應(yīng)的 value。而entrySet 只是遍歷了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用 Map.forEach 方法。

正例:values() 返回的是 V 值集合,是一個(gè) list 集合對(duì)象;keySet() 返回的是 K 值集合,是一個(gè) Set 集合對(duì)象;entrySet() 返回的是 K-V 值組合的 Set 集合。

19、【推薦】高度注意 Map 類集合 K / V 能不能存儲(chǔ) null 值的情況,如下表格:

 反例: 由于 HashMap 的干擾,很多人認(rèn)為 ConcurrentHashMap 是可以置入 null 值,而事實(shí)上,存儲(chǔ) null 值時(shí)會(huì)拋 出 NPE 異常。

20.【參考】合理利用好集合的有序性(sort)和穩(wěn)定性(order),避免集合的無(wú)序性(unsort)和不穩(wěn)定性(unorder)帶來(lái)的負(fù)面影響。

說(shuō)明:有序性是指遍歷的結(jié)果是按某種比較規(guī)則依次排列的,穩(wěn)定性指集合每次遍歷的元素次序是一定的。如:ArrayList 是 order / unsort;HashMap 是 unorder / unsort;TreeSet 是 order / sort。

21.【參考】利用 Set 元素唯一的特性,可以快速對(duì)一個(gè)集合進(jìn)行去重操作,避免使用 List 的contains() 進(jìn)行遍歷去重或者判斷包含操作。

到此這篇關(guān)于工作中Java集合的規(guī)范使用操作詳解的文章就介紹到這了,更多相關(guān)Java集合內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java 選擇、冒泡排序、折半查找(實(shí)例講解)

    Java 選擇、冒泡排序、折半查找(實(shí)例講解)

    下面小編就為大家?guī)?lái)一篇Java 選擇、冒泡排序、折半查找(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • springboot]logback日志框架配置教程

    springboot]logback日志框架配置教程

    這篇文章主要介紹了springboot]logback日志框架配置,logback既可以通過(guò)application配置文件進(jìn)行日志的配置,又可以通過(guò)logback-spring.xml進(jìn)行日志的配置,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2022-04-04
  • Spring Cloud Gateway自定義異常處理Exception Handler的方法小結(jié)

    Spring Cloud Gateway自定義異常處理Exception Handler的方法小結(jié)

    這篇文章主要介紹了Spring Cloud Gateway自定義異常處理Exception Handler的方法,本文通過(guò)兩種方法結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • SpringLDAP連接LDAPS證書報(bào)錯(cuò)問(wèn)題及解決

    SpringLDAP連接LDAPS證書報(bào)錯(cuò)問(wèn)題及解決

    這篇文章主要介紹了SpringLDAP連接LDAPS證書報(bào)錯(cuò)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Spring加載properties文件的方法

    Spring加載properties文件的方法

    這篇文章主要為大家詳細(xì)介紹了Spring加載properties文件的兩種方法,一是通過(guò)xml方式,另一種方式是通過(guò)注解方式,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Java回調(diào)機(jī)制解讀

    Java回調(diào)機(jī)制解讀

    本文主要介紹了Java回調(diào)機(jī)制的相關(guān)知識(shí),具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • Java數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之循環(huán)鏈表

    Java數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)之循環(huán)鏈表

    循環(huán)鏈表是另一種形式的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)。它的特點(diǎn)是表中最后一個(gè)結(jié)點(diǎn)的指針域指向頭結(jié)點(diǎn),整個(gè)鏈表形成一個(gè)環(huán)。本文將為大家詳細(xì)介紹一下循環(huán)鏈表的特點(diǎn)與使用,需要的可以了解一下
    2021-12-12
  • JAVA自定義注解實(shí)現(xiàn)接口/ip限流的示例代碼

    JAVA自定義注解實(shí)現(xiàn)接口/ip限流的示例代碼

    本文主要介紹了JAVA自定義注解實(shí)現(xiàn)接口/ip限流的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • 智能 AI 代碼生成工具 Cursor 安裝和使用超詳細(xì)教程

    智能 AI 代碼生成工具 Cursor 安裝和使用超詳細(xì)教程

    Cursor.so 是一個(gè)集成了 GPT-4 的國(guó)內(nèi)直接可以訪問(wèn)的,優(yōu)秀而強(qiáng)大的免費(fèi)代碼生成器,可以幫助你快速編寫、編輯和討論代碼,這篇文章主要介紹了智能 AI 代碼生成工具 Cursor 安裝和使用介紹,需要的朋友可以參考下
    2023-05-05
  • java線程池ThreadPoolExecutor類使用小結(jié)

    java線程池ThreadPoolExecutor類使用小結(jié)

    這篇文章主要介紹了java線程池ThreadPoolExecutor類使用,本文主要對(duì)ThreadPoolExecutor的使用方法進(jìn)行一個(gè)詳細(xì)的概述,示例代碼介紹了ThreadPoolExecutor的構(gòu)造函數(shù)的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2022-03-03

最新評(píng)論