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

深度掌握J(rèn)ava Stream 流操作,讓你的代碼高出一個(gè)逼格!

開發(fā) 后端
我們都知道,從 Java8 開始,jdk 新增加了一個(gè) Stream 類,用來補(bǔ)充集合類,它的強(qiáng)大,相信用過它的朋友,能明顯的感受到,不用使用for循環(huán)就能對(duì)集合作出很好的操作。

[[393227]]

本文轉(zhuǎn)載自微信公眾號(hào)「Java極客技術(shù)」,作者鴨血粉絲。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。  

一、介紹

我們都知道,從 Java8 開始,jdk 新增加了一個(gè) Stream 類,用來補(bǔ)充集合類,它的強(qiáng)大,相信用過它的朋友,能明顯的感受到,不用使用for循環(huán)就能對(duì)集合作出很好的操作。

Stream 使用一種類似用 SQL 語句從數(shù)據(jù)庫查詢數(shù)據(jù)的直觀方式來提供一種對(duì) Java 集合運(yùn)算和表達(dá)的高階抽象。

這種風(fēng)格將要處理的元素集合看作一種流, 流在管道中傳輸, 并且可以在管道的節(jié)點(diǎn)上進(jìn)行處理, 比如篩選, 排序,聚合等。

元素流在管道中經(jīng)過中間操作(intermediate operation)的處理,最后由最終操作(terminal operation)得到前面處理的結(jié)果。

操作流程如下:

  1. +--------------------+       +------+   +------+   +---+   +-------+ 
  2. | stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect| 
  3. +--------------------+       +------+   +------+   +---+   +-------+ 

采用 Stream API 可以極大提高 Java 程序員的生產(chǎn)力,讓程序員寫出高效率、干凈、簡潔的代碼。

下面,我們就以實(shí)際的日常開發(fā)編程風(fēng)格做對(duì)比,學(xué)習(xí)完 Stream 的編程風(fēng)格之后,我敢保證,你會(huì)愛上它!

二、遍歷操作

2.1、遍歷集合

日常開發(fā)中,我們經(jīng)常需要需要遍歷集合對(duì)象中的元素,例如,我們會(huì)采用如下方式進(jìn)行遍歷元素,然后過濾出某個(gè)字段的集合,jdk7 的操作:

  1. /** 
  2.  * jdk7 從集合對(duì)象中獲取用戶ID集合 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public List<Long> getUserIds(List<User> userList){ 
  7.     List<Long> userIds = new ArrayList<>(); 
  8.     for (User user : userList) { 
  9.         userIds.add(user.getUserId()); 
  10.     } 
  11.     return userIds; 

當(dāng)采用 Stream 編程之后,只需要通過一行代碼,即可實(shí)現(xiàn):

  1. /** 
  2.  * jdk8 從集合對(duì)象中獲取用戶ID集合 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public List<Long> getUserIds(List<User> userList){ 
  7.     List<Long> userIds = userList.stream().map(User::getUserId).collect(Collectors.toList()); 
  8.     return userIds; 

2.2、篩選元素

篩選元素,是日常開發(fā)中經(jīng)常會(huì)碰到,例如在 jdk7,我們會(huì)這么操作:

  1. /** 
  2.  * jdk7 從集合對(duì)象中過濾出用戶ID不為空的數(shù)據(jù) 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public List<Long> getUserIds7(List<User> userList){ 
  7.     List<Long> userIds = new ArrayList<>(); 
  8.     for (User user : userList) { 
  9.         if(user.getUserId() != null){ 
  10.             userIds.add(user.getUserId()); 
  11.         } 
  12.     } 
  13.     return userIds; 

采用 Stream api,我們只需要通過filter方法來篩選出需要的數(shù)據(jù),即可過濾出用戶ID不為空的數(shù)據(jù)。

  1. /** 
  2.  * jdk8 從集合對(duì)象中篩選出用戶ID不為空的數(shù)據(jù) 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public List<Long> getUserIds8(List<User> userList){ 
  7.     List<Long> userIds = userList.stream().filter(item -> item.getUserId() != null).map(User::getUserId).collect(Collectors.toList()); 
  8.     return userIds; 

2.3、刪除重復(fù)的內(nèi)容

如果你想對(duì)返回的集合內(nèi)容排除重復(fù)的數(shù)據(jù),操作也很簡單,在合并的時(shí)候使用Collectors.toSet()即可!

  1. /** 
  2.  * jdk8 從集合對(duì)象中篩選出用戶ID不為空的數(shù)據(jù),并進(jìn)行去重 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public Set<Long> getUserIds(List<User> userList){ 
  7.     Set<Long> userIds = userList.stream().filter(item -> item.getUserId() != null).map(User::getUserId).collect(Collectors.toSet()); 
  8.     return userIds; 

2.4、數(shù)據(jù)類型轉(zhuǎn)換

在實(shí)際的開發(fā)過程中,經(jīng)常會(huì)出現(xiàn)數(shù)據(jù)類型定義不一致的問題,例如有的系統(tǒng),使用String接受,有的是用Long,對(duì)于這種場景,我們需要將其轉(zhuǎn)換,操作也很簡單

  1. /** 
  2.  * jdk8 將Long類型數(shù)據(jù)轉(zhuǎn)換成String類型 
  3.  * @param userIds 
  4.  * @return 
  5.  */ 
  6. public List<String> getUserIds10(List<Long> userIds){ 
  7.     List<String> userIdStrs = userIds.stream().map(x -> x.toString()).collect(Collectors.toList()); 
  8.     return userIdStrs; 

2.5、數(shù)組轉(zhuǎn)集合

我們還會(huì)碰到,前端傳給我們的是一個(gè)數(shù)組,但是我們需要轉(zhuǎn)成集合,采用 stream api 操作也很簡單!

  1. public static void main(String[] args) { 
  2.         //創(chuàng)建一個(gè)字符串?dāng)?shù)組 
  3.         String[] strArray = new String[]{"a","b","c"}; 
  4.         //轉(zhuǎn)換后的List 屬于 java.util.ArrayList 能進(jìn)行正常的增刪查操作 
  5.         List<String> strList = Stream.of(strArray).collect(Collectors.toList()); 

三、集合轉(zhuǎn)Map操作

在實(shí)際的開發(fā)過程中,還有一個(gè)使用最頻繁的操作就是,將集合元素中某個(gè)主鍵字段作為key,元素作為value,來實(shí)現(xiàn)集合轉(zhuǎn)map的需求,這種需求在數(shù)據(jù)組裝方面使用的非常多,尤其是在禁止連表 sql 查詢操作的公司,視圖數(shù)據(jù)的拼裝只能在代碼層面來實(shí)現(xiàn)。

例如下面這段代碼,角色表里面關(guān)聯(lián)角色組ID信息,當(dāng)查詢角色信息的時(shí)候,需要把角色組名稱也展示處理,采用map方式來匹配,效率會(huì)非常高。

實(shí)際代碼案例分享

  1. //角色組ID集合 
  2. Set<Long> roleGroupIds = new HashSet<>(); 
  3. //查詢所有的角色信息 
  4. List<RoleInfo> dbList = roleInfoMapper.findByPage(request); 
  5. for (RoleInfo source : dbList) { 
  6.     roleGroupIds.add(source.getRoleGroupId()); 
  7.     RoleInfoDto result = new RoleInfoDto(); 
  8.     BeanUtils.copyProperties(source, result); 
  9.     resultList.add(result); 
  10. //查詢角色組信息 
  11. if (CollectionUtils.isNotEmpty(roleGroupIds)) { 
  12.     List<RoleGroupInfo> roleGroupInfoList = roleGroupInfoMapper.selectByIds(new ArrayList<>(roleGroupIds)); 
  13.     if (CollectionUtils.isNotEmpty(roleGroupInfoList)) { 
  14.      //將List轉(zhuǎn)換成Map,其中id主鍵作為key,對(duì)象作為value 
  15.         Map<Long, RoleGroupInfo> sourceMap = new HashMap<>(); 
  16.         for (RoleGroupInfo roleGroupInfo : roleGroupInfoList) { 
  17.             sourceMap.put(roleGroupInfo.getId(), roleGroupInfo); 
  18.         } 
  19.   //封裝角色組名稱 
  20.         for (RoleInfoDto result : resultList) { 
  21.             if (sourceMap.containsKey(result.getRoleGroupId())) { 
  22.                 result.setRoleGroupName(sourceMap.get(result.getRoleGroupId()).getName()); 
  23.             } 
  24.         } 
  25.     } 

3.1、集合轉(zhuǎn) map(不分組)

在 jdk7 中,將集合中的元素轉(zhuǎn) map,我們通常會(huì)采用如下方式。

  1. /** 
  2.  * jdk7 將集合轉(zhuǎn)換成Map,其中用戶ID作為主鍵key 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public Map<Long, User> getMap(List<User> userList){ 
  7.     Map<Long, User> userMap = new HashMap<>(); 
  8.     for (User user : userList) { 
  9.         userMap.put(user.getUserId(), user); 
  10.     } 
  11.     return userMap; 

在 jdk8 中,采用 stream api的方式,我們只需要一行代碼即可實(shí)現(xiàn)

  1. /** 
  2.  * jdk8 將集合轉(zhuǎn)換成Map,其中用戶ID作為主鍵key,如果集合對(duì)象有重復(fù)的key,以第一個(gè)匹配到的為主 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public Map<Long, User> getMap(List<User> userList){ 
  7.     Map<Long, User> userMap = userList.stream().collect(Collectors.toMap(User::getUserId, v -> v, (k1,k2) -> k1)); 
  8.     return userMap; 

打開Collectors.toMap方法源碼,一起來看看到底是啥。

  1. public static <T, K, U> 
  2. Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, 
  3.                                 Function<? super T, ? extends U> valueMapper, 
  4.                                 BinaryOperator<U> mergeFunction) { 
  5.     return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); 

從參數(shù)表可以看出:

  • 第一個(gè)參數(shù):表示 key
  • 第二個(gè)參數(shù):表示 value
  • 第三個(gè)參數(shù):表示某種規(guī)則

上文中的Collectors.toMap(User::getUserId, v -> v, (k1,k2) -> k1),表達(dá)的意思就是將userId的內(nèi)容作為key,v -> v是表示將元素user作為value,其中(k1,k2) -> k1表示如果存在相同的key,將第一個(gè)匹配的元素作為內(nèi)容,第二個(gè)舍棄!

3.2、集合轉(zhuǎn)map(分組)

在實(shí)際的操作中,有一些場景需要我們將相同的key,加入到一個(gè)集合,而不是覆蓋,哪改如何做呢?

如果是采用 jdk7,我們大概會(huì)這么做。

  1. /** 
  2.  * jdk7 將集合轉(zhuǎn)換成Map,將相同的key,加入到一個(gè)集合中,實(shí)現(xiàn)分組 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public Map<Long, List<User>> getMapGroup(List<User> userList){ 
  7.     Map<Long, List<User>> userListMap = new HashMap<>(); 
  8.     for (User user : userList) { 
  9.         if(userListMap.containsKey(user.getUserId())){ 
  10.             userListMap.get(user.getUserId()).add(user); 
  11.         } else { 
  12.             List<User> users = new ArrayList<>(); 
  13.             users.add(user); 
  14.             userListMap.put(user.getUserId(), users); 
  15.         } 
  16.     } 
  17.     return userListMap; 

而在 jdk8 中,采用 stream api的方式,我們只需要一行代碼即可實(shí)現(xiàn)

  1. /** 
  2.  * jdk8 將集合轉(zhuǎn)換成Map,將相同的key,加入到一個(gè)集合中,實(shí)現(xiàn)分組 
  3.  * @param userList 
  4.  * @return 
  5.  */ 
  6. public Map<Long, List<User>> getMapGroup(List<User> userList){ 
  7.     Map<Long, List<User>> userMap = userList.stream().collect(Collectors.groupingBy(User::getUserId)); 
  8.     return userMap; 

四、分頁操作

stream api 的強(qiáng)大之處還不僅僅是對(duì)集合進(jìn)行各種組合操作,還支持分頁操作。

例如,將如下的數(shù)組從小到大進(jìn)行排序,排序完成之后,從第1行開始,查詢10條數(shù)據(jù)出來,操作如下:

  1. //需要查詢的數(shù)據(jù) 
  2. List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5,10, 6, 20, 30, 40, 50, 60, 100); 
  3. List<Integer> dataList= numbers.stream().sorted((x, y) -> x.compareTo(y)).skip(0).limit(10).collect(Collectors.toList()); 
  4. System.out.println(dataList.toString()); 

其中skip參數(shù)表示第幾行,limit表示查詢的數(shù)量,類似頁容量!

五、查找與匹配操作

stream api 還支持對(duì)集合進(jìn)行查找,同時(shí)還支持正則匹配模式。

  • allMatch(檢查是否匹配所有元素)
  1. List<Integer> list = Arrays.asList(10, 5, 7, 3); 
  2. boolean allMatch = list.stream()// 
  3.         .allMatch(x -> x > 2);//是否全部元素都大于2 
  4. System.out.println(allMatch); 
  • findFirst(返回第一個(gè)元素)
  1. List<Integer> list = Arrays.asList(10, 5, 7, 3); 
  2. Optional<Integerfirst = list.stream()// 
  3.         .findFirst(); 
  4. Integer val = first.get(); 
  5. System.out.println(val);//輸出10 

reduce(可以將流中元素反復(fù)結(jié)合起來,得到一個(gè)值)

  1. List<Integer> list = Arrays.asList(10, 5, 7, 3); 
  2. Integer result = list.stream()// 
  3.     .reduce(2, Integer::sum); 
  4. System.out.println(result);//輸出27,其實(shí)相當(dāng)于2+10+5+7+3,就是一個(gè)累加 

stream api 支持的操作方法非常多,這里只列舉了幾種類型,具體在使用的時(shí)候,可以參考官網(wǎng)接口文檔說明!

六、并行操作

所謂并行,指的是多個(gè)任務(wù)在同一時(shí)間點(diǎn)發(fā)生,并由不同的cpu進(jìn)行處理,不互相搶占資源;而并發(fā),指的是多個(gè)任務(wù)在同一時(shí)間點(diǎn)內(nèi)同時(shí)發(fā)生了,但由同一個(gè)cpu進(jìn)行處理,互相搶占資源。

這點(diǎn)上大家一定要區(qū)分清楚,別弄混了!

stream api 的并行操作和串行操作,只有一個(gè)方法區(qū)別,其他都一樣,例如下面我們使用parallelStream來輸出空字符串的數(shù)量:

  1. List<String> strings = Arrays.asList("abc""""bc""efg""abcd","""jkl"); 
  2. // 采用并行計(jì)算方法,獲取空字符串的數(shù)量 
  3. long count = strings.parallelStream().filter(string -> string.isEmpty()).count(); 

在實(shí)際使用的時(shí)候,并行操作不一定比串行操作快!對(duì)于簡單操作,數(shù)量非常大,同時(shí)服務(wù)器是多核的話,建議使用Stream并行!反之,采用串行操作更可靠!

七、小結(jié)

本文主要,圍繞 jdk stream api 操作,結(jié)合實(shí)際的日常開發(fā)需求,做了簡單總結(jié)和分享,鑒于筆者才疏學(xué)淺,可能也有理解不到位的地方,歡迎網(wǎng)友們批評(píng)指出!

 

 

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2024-12-02 10:15:15

2021-09-27 10:03:55

裝飾器代碼

2021-07-12 07:08:54

責(zé)任鏈模式對(duì)象

2021-08-11 06:57:17

驗(yàn)證碼圖片顯示

2024-07-29 09:13:42

2020-06-08 15:18:50

Python圖片PIL

2017-11-09 08:48:49

JavaScript編程黑科技

2016-11-17 12:49:36

云運(yùn)維銀行卡建設(shè)

2017-12-07 15:05:50

全球互聯(lián)網(wǎng)創(chuàng)新峰會(huì)

2022-10-31 07:09:15

拷貝代碼項(xiàng)目

2025-02-17 08:50:00

CSS代碼JavaScript

2020-09-29 14:13:29

寫一個(gè)高逼格可視化“圓

2019-12-25 14:19:21

Python編程語言Java

2024-12-05 08:13:18

2020-12-21 13:33:00

medit編輯器Linux

2023-11-23 16:46:55

LinuxAWK運(yùn)維

2024-04-12 09:01:08

2024-03-11 00:05:00

2024-02-26 18:11:08

Docker容器鏡像

2023-12-14 09:40:37

系統(tǒng)開源
點(diǎn)贊
收藏

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