自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

學(xué)習(xí)集合類源碼對(duì)我們實(shí)際工作的幫助和應(yīng)用!

開發(fā) 前端
UnmodifiableList是Collections中的內(nèi)部類,通過調(diào)用 Collections.unmodifiableList(List list) 可返回指定集合的不可變集合。

Java的集合類包括Map和Collection兩大類。Collection包括List、Set和Queue三個(gè)小類。

「如下圖:」

圖片

這邊文章通過源碼解讀的方式帶大家了解一下:集合類使用過程中常見的問題以及學(xué)習(xí)一些優(yōu)秀的設(shè)計(jì)思想。

「集合批量操作性能」

集合的單個(gè)操作,一般都沒有性能問題,性能問題主要出現(xiàn)的批量操作上。

如批量新增操作:

在 List 和 Map 大量數(shù)據(jù)新增的時(shí)候,使用 for 循環(huán) + add/put 方法新增,這樣子會(huì)有很大的擴(kuò)容成本,我們應(yīng)該盡量使用 addAll 和 putAll 方法進(jìn)行新增,如下演示了兩種方案的性能對(duì)比:

圖片

單個(gè) for 循環(huán)新增 300 w 個(gè),耗時(shí)1518。


批量新增 300 w 個(gè),耗時(shí)8。

可以看到,批量新增方法性能是單個(gè)新增方法性能的 189 倍,主要原因在于批量新增,只會(huì)擴(kuò)容一次,大大縮短了運(yùn)行時(shí)間,而單個(gè)新增,每次到達(dá)擴(kuò)容閥值時(shí),都會(huì)進(jìn)行擴(kuò)容,在整個(gè)過程中就會(huì)不斷的擴(kuò)容,浪費(fèi)了很多時(shí)間。

我們來看下批量新增的源碼:

圖片

我們可以看到,整個(gè)批量新增的過程中,只擴(kuò)容了一次。

「集合線程安全性」

集合的非線程安全指的是:集合類作為共享變量,被多線程讀寫的時(shí)候是不安全的,如果要實(shí)現(xiàn)線程安全的集合,在類注釋中,JDK 統(tǒng)一推薦我們使用 Collections.synchronized* 類。

Collections 幫我們實(shí)現(xiàn)了 List、Set、Map 對(duì)應(yīng)的線程安全的方法, 如下圖:

圖片

從源碼中我們可以看到 Collections 是通過 synchronized 關(guān)鍵字給 List 操作數(shù)組的方法加上鎖,來實(shí)現(xiàn)線程安全的。

集合類方法常見的問題?

List?

「Arrays.asList()方法」

我們把數(shù)組轉(zhuǎn)化成集合時(shí),常使用 Arrays.asList(array),這個(gè)方法有兩個(gè)問題,代碼演示如下:

問題一:修改數(shù)組的值,會(huì)直接影響原list。

public void testArrayToList(){
Integer[] array = new Integer[]{1,2,3,4,5,6};
List<Integer> list = Arrays.asList(array);

// 問題1:修改數(shù)組的值,會(huì)直接影響原 list
log.info("數(shù)組被修改之前,集合第一個(gè)元素為:{}",list.get(0));
array[0] = 10;
log.info("數(shù)組被修改之前,集合第一個(gè)元素為:{}",list.get(0));
}

問題二:不能對(duì)新 List 進(jìn)行 add、remove 等操作,否則運(yùn)行時(shí)會(huì)報(bào) UnsupportedOperationException 錯(cuò)誤。

public void testArrayToList(){
Integer[] array = new Integer[]{1,2,3,4,5,6};
List<Integer> list = Arrays.asList(array);

// 問題2:使用 add、remove 等操作 list 的方法時(shí),
// 會(huì)報(bào) UnsupportedOperationException 異常
list.add(7);
}

原因分析:

圖片

圖片

從上圖中,我們可以發(fā)現(xiàn),Arrays.asList? 方法返回的 List 并不是 java.util.ArrayList,而是自己內(nèi)部的一個(gè)靜態(tài)類,該靜態(tài)類直接持有數(shù)組的引用,并且沒有實(shí)現(xiàn) add、remove 等方法,這些就是問題 1 和 2 的原因。

「list.toArray方法」

public void testListToArray(){
List<Integer> list = new ArrayList<Integer>(){{
add(1);
add(2);
add(3);
add(4);
}};

// 下面這行代碼是無法轉(zhuǎn)化成數(shù)組的,無參 toArray 返回的是 Object[],
// 無法向下轉(zhuǎn)化成 List<Integer>,編譯都無法通過
// List<Integer> list2 = list.toArray();

// 有參 toArray 方法,數(shù)組大小不夠時(shí),得到數(shù)組為 null 情況
Integer[] array0 = new Integer[2];
list.toArray(array0);
log.info("toArray 數(shù)組大小不夠,array0 數(shù)組[0] 值是{},數(shù)組[1] 值是{},",array0[0],array0[1]);

// 數(shù)組初始化大小正好,正好轉(zhuǎn)化成數(shù)組
Integer[] array1 = new Integer[list.size()];
list.toArray(array1);
log.info("toArray 數(shù)組大小正好,array1 數(shù)組[3] 值是{}",array1[3]);

// 數(shù)組初始化大小大于實(shí)際所需大小,也可以轉(zhuǎn)化成數(shù)組
Integer[] array2 = new Integer[list.size()+2];
list.toArray(array2);
log.info("toArray 數(shù)組大小多了,array2 數(shù)組[3] 值是{},數(shù)組[4] 值是{}",array2[3],array2[4]);
}
toArray 數(shù)組大小不夠,array0 數(shù)組[0] 值是null,數(shù)組[1] 值是null,
toArray 數(shù)組大小正好,array1 數(shù)組[3] 值是4
toArray 數(shù)組大小多了,array2 數(shù)組[3] 值是4,數(shù)組[4] 值是null

原因分析:

toArray 的無參方法,無法強(qiáng)轉(zhuǎn)成具體類型,這個(gè)編譯的時(shí)候,就會(huì)有提醒,我們一般都會(huì)去使用帶有參數(shù)的 toArray 方法,這時(shí)就有一個(gè)坑,如果參數(shù)數(shù)組的大小不夠,這時(shí)候返回的數(shù)組值是空。

圖片

「Collections.emptyList()方法」

問題:

在返回的 Collections.emptyList(); 上調(diào)用了add()方法,拋出異常 UnsupportedOperationException。

分析:

Collections.emptyList() 返回的是不可變的空列表,這個(gè)空列表對(duì)應(yīng)的類型是EmptyList,這個(gè)類是Collections中的靜態(tài)內(nèi)部類,繼承了AbstractList。

AbstractList中默認(rèn)的add方法是沒有實(shí)現(xiàn)的,直接拋出UnsupportedOperationException異常。

而EmptyList只是繼承了AbstractList,卻并沒有重寫add方法,因此直接調(diào)用add方法會(huì)拋異常。

除了emptyList,還有emptySet、emptyMap等也一樣。

圖片

「List.subList()方法」

list.subList() 產(chǎn)生的集合也會(huì)與原始List互相影響。

圖片

圖片

圖片

建議使用時(shí),通過List list = Lists.newArrayList(arrays); 來生成一個(gè)新的list,不要再操作原列表。

「UnmodifiableList」

UnmodifiableList是Collections中的內(nèi)部類,通過調(diào)用 Collections.unmodifiableList(List list) 可返回指定集合的不可變集合。

集合只能被讀取,不能做任何增刪改操作,從而保護(hù)不可變集合的安全。但這個(gè)不可變僅僅是正向的不可變。

反過來如果修改了原來的集合,則這個(gè)不可變集合仍會(huì)被同步修改。因?yàn)椴豢勺兗系讓邮褂玫倪€是原來的List。

圖片

Map?

「ConcurrentHashMap不允許為null」

ConcurrentHashMap#put?方法的源碼,開頭就看到了對(duì)KV的判空校驗(yàn)。

圖片

為什么ConcurrentHashMap?與 HashMap設(shè)計(jì)的判斷邏輯不一樣?

Doug Lea 老爺子的解釋是:

  • null?會(huì)引起歧義,如果value為null?,我們無法得知是值為null?,還是key未映射具體值?
  • Doug Lea 并不喜歡null?,認(rèn)為null 就是個(gè)隱藏的炸彈。

貼一下常用Map?子類集合對(duì)于 null存儲(chǔ)情況:

圖片

「HashMap 是無序的」

舉例:

import java.util.HashMap;

public class App {

public static void main(String[] args) {
HashMap<String, Object> result = getList();
result.forEach((k, v) -> {
System.out.println(k + ":" + v);
});
}

// 查詢方法(簡(jiǎn)化版)
public static HashMap<String, Object> getList() {
HashMap<String, Object> result = new HashMap<>(); // 最終返回的結(jié)果集
// 偽代碼:從數(shù)據(jù)庫(kù)中查詢出了數(shù)據(jù),然后對(duì)數(shù)據(jù)進(jìn)行處理之后,存到了
for (int i = 1; i <= 5; i++) {
result.put("2022-" + i, "hello java" + i);
}
return result;
}
}

結(jié)果并沒有按先后順序返回。

原因分析

HashMap 使用的是哈希方式進(jìn)行存儲(chǔ)的,因此存入和讀取的順序可能是不一致的,這也說 HashMap 是無序的集合,所以會(huì)導(dǎo)致插入的順序,與最終展示的順序不一致。

解決方案:將無序的 HashMap 改為有序的 LinkedHashMap。

LinkedHashMap 屬于 HashMap 的子類,所以 LinkedHashMap 除了擁有 HashMap 的所有特性之后,還具備自身的一些擴(kuò)展屬性,其中就包括 LinkedHashMap 中額外維護(hù)了一個(gè)雙向鏈表,這個(gè)雙向鏈表就是用來保存元素的(插入)順序的。

Set?

如果是需要對(duì)我們自定義的對(duì)象去重,就需要我們重寫 hashCode 和 equals 方法。

不然HashSet調(diào)用默認(rèn)的hashCode方法判斷對(duì)象的地址,不等就達(dá)不到想根據(jù)對(duì)象的值去重的目的。

圖片

責(zé)任編輯:武曉燕 來源: 日常加油站
相關(guān)推薦

2013-03-01 10:13:19

編程競(jìng)賽程序員

2010-07-05 14:20:29

2010-07-05 08:31:25

SQL Server快

2010-07-26 09:48:49

SQL Server復(fù)

2015-11-16 10:17:21

工作數(shù)據(jù)分析

2010-03-01 10:45:59

WCF集合類

2021-06-22 09:13:19

FacebookMIT深度學(xué)習(xí)

2009-08-08 08:52:56

GoogleChromeFirefox

2024-01-12 10:05:48

自定義注解SpringJava

2013-12-19 15:52:08

自動(dòng)化運(yùn)維自動(dòng)化運(yùn)維工具Puppet

2010-03-25 18:37:28

Python技巧

2019-02-01 09:00:34

AR SDKAR開發(fā)

2021-11-30 22:51:36

機(jī)器學(xué)習(xí)大數(shù)據(jù)技術(shù)

2024-12-11 08:20:57

設(shè)計(jì)模式源碼

2017-01-05 11:34:16

Linux

2024-02-23 10:10:00

List接口Java

2010-03-17 17:06:10

python腳本語言

2015-08-12 15:31:18

人工智能深度學(xué)習(xí)Fackbook

2024-02-27 11:38:46

AI工具Sora

2022-02-14 10:16:22

Axios接口HTTP
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)