成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

學習集合類源碼對我們實際工作的幫助和應用!

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

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

「如下圖:」

圖片

這邊文章通過源碼解讀的方式帶大家了解一下:集合類使用過程中常見的問題以及學習一些優秀的設計思想。

「集合批量操作性能」

集合的單個操作,一般都沒有性能問題,性能問題主要出現的批量操作上。

如批量新增操作:

在 List 和 Map 大量數據新增的時候,使用 for 循環 + add/put 方法新增,這樣子會有很大的擴容成本,我們應該盡量使用 addAll 和 putAll 方法進行新增,如下演示了兩種方案的性能對比:

圖片

單個 for 循環新增 300 w 個,耗時1518。


批量新增 300 w 個,耗時8。

可以看到,批量新增方法性能是單個新增方法性能的 189 倍,主要原因在于批量新增,只會擴容一次,大大縮短了運行時間,而單個新增,每次到達擴容閥值時,都會進行擴容,在整個過程中就會不斷的擴容,浪費了很多時間。

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

圖片

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

「集合線程安全性」

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

Collections 幫我們實現了 List、Set、Map 對應的線程安全的方法, 如下圖:

圖片

從源碼中我們可以看到 Collections 是通過 synchronized 關鍵字給 List 操作數組的方法加上鎖,來實現線程安全的。

集合類方法常見的問題?

List?

「Arrays.asList()方法」

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

問題一:修改數組的值,會直接影響原list。

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

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

問題二:不能對新 List 進行 add、remove 等操作,否則運行時會報 UnsupportedOperationException 錯誤。

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

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

原因分析:

圖片

圖片

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

「list.toArray方法」

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

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

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

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

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

原因分析:

toArray 的無參方法,無法強轉成具體類型,這個編譯的時候,就會有提醒,我們一般都會去使用帶有參數的 toArray 方法,這時就有一個坑,如果參數數組的大小不夠,這時候返回的數組值是空。

圖片

「Collections.emptyList()方法」

問題:

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

分析:

Collections.emptyList() 返回的是不可變的空列表,這個空列表對應的類型是EmptyList,這個類是Collections中的靜態內部類,繼承了AbstractList。

AbstractList中默認的add方法是沒有實現的,直接拋出UnsupportedOperationException異常。

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

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

圖片

「List.subList()方法」

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

圖片

圖片

圖片

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

「UnmodifiableList」

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

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

反過來如果修改了原來的集合,則這個不可變集合仍會被同步修改。因為不可變集合底層使用的還是原來的List。

圖片

Map?

「ConcurrentHashMap不允許為null」

ConcurrentHashMap#put?方法的源碼,開頭就看到了對KV的判空校驗。

圖片

為什么ConcurrentHashMap?與 HashMap設計的判斷邏輯不一樣?

Doug Lea 老爺子的解釋是:

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

貼一下常用Map?子類集合對于 null存儲情況:

圖片

「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);
});
}

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

結果并沒有按先后順序返回。

原因分析

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

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

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

Set?

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

不然HashSet調用默認的hashCode方法判斷對象的地址,不等就達不到想根據對象的值去重的目的。

圖片

責任編輯:武曉燕 來源: 日常加油站
相關推薦

2013-03-01 10:13:19

編程競賽程序員

2010-07-05 14:20:29

2010-07-05 08:31:25

SQL Server快

2010-07-26 09:48:49

SQL Server復

2021-06-22 09:13:19

FacebookMIT深度學習

2015-11-16 10:17:21

工作數據分析

2010-03-01 10:45:59

WCF集合類

2025-06-06 08:04:17

2009-08-08 08:52:56

GoogleChromeFirefox

2025-05-19 00:00:00

Git代碼自動化

2024-01-12 10:05:48

自定義注解SpringJava

2013-12-19 15:52:08

自動化運維自動化運維工具Puppet

2010-03-25 18:37:28

Python技巧

2019-02-01 09:00:34

AR SDKAR開發

2021-11-30 22:51:36

機器學習大數據技術

2024-12-11 08:20:57

設計模式源碼

2017-01-05 11:34:16

Linux

2015-08-12 15:31:18

人工智能深度學習Fackbook

2010-03-17 17:06:10

python腳本語言

2024-02-23 10:10:00

List接口Java
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产免费人成xvideos视频 | av手机在线 | 日日夜夜天天 | 亚洲精品日韩综合观看成人91 | 天天干天天谢 | 成人欧美一区二区三区黑人孕妇 | 国产午夜精品一区二区三区四区 | 亚洲精品电影 | 99精品视频在线观看免费播放 | 九九视频在线观看 | 日韩精品一区二区三区高清免费 | 国产一区二区影院 | 日韩中文一区二区三区 | 亚洲97 | 欧美日韩精品在线一区 | 一区二区三区视频播放 | 免费av在线网站 | 久久久久国产一区二区三区 | 欧美色视频免费 | 黄色操视频 | 一本岛道一二三不卡区 | 日日天天 | 中文字幕第十页 | 欧美激情精品久久久久久 | 九九视频在线观看视频6 | 久久亚洲天堂 | www.天天操.com| 日日摸天天添天天添破 | 天天综合久久 | 欧美午夜精品久久久久久浪潮 | 91麻豆精品国产91久久久久久久久 | 精品免费视频 | 免费毛片网 | 国产男女猛烈无遮掩视频免费网站 | 久久久久久国产精品免费 | 中文字幕第一页在线 | 99九九视频 | 夜夜骑首页 | 中文在线观看视频 | 欧美亚洲国产一区二区三区 | 91天堂|