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

我們一起實(shí)戰(zhàn)學(xué)習(xí)Java8 Stream新特性

開發(fā) 前端
sorted方法的入?yún)⑹且粋€(gè)比較器Comparator,這里我們直接使用Comparator.comparing方法構(gòu)建一個(gè)根據(jù)價(jià)格排序的比較器,并使用reversed方法返回一個(gè)降序的比較器。最后我們使用終結(jié)方法collect(Collectors.toList())將結(jié)果收集到集合當(dāng)中。

引言

大家好,我是了不起。剛剛不久Java23如期發(fā)布,但目前國(guó)內(nèi)市場(chǎng)Java8還是占據(jù)著主導(dǎo)地位。今天我將模擬實(shí)際工作中的需求,帶領(lǐng)大家學(xué)習(xí)Java8中的Stream新特性,大家可以收藏起來以防在需要的時(shí)候找不到。

實(shí)體類聲明

@Getter
@Setter
public class ComputerDTO {
    /**
     * 計(jì)算機(jī)編號(hào)
     */
    private String computerNo;
    /**
     * 品牌
     */
    private String brand;
    /**
     * 價(jià)格
     */
    private BigDecimal price;
    /**
     * cpu核數(shù)
     */
    private Integer coreQuantity;
    /**
     * 內(nèi)存GB
     */
    private Integer memory;
    /**
     * 硬盤信息,包含容量和類型,如 "500GB HDD" 或 "256GB SSD"
     */
    private String hardDisk;
    /**
     * 產(chǎn)地
     */
    private String place;
}

場(chǎng)景描述

我暫且充當(dāng)一下產(chǎn)品經(jīng)理,現(xiàn)在羅列出了下列需求,基本上覆蓋了日常使用Stream流的大多場(chǎng)景,各位小伙伴可以先行看一看有沒有思路。

經(jīng)典場(chǎng)景

  1. 篩選出所有品牌為“abc”的電腦,并按價(jià)格降序排序。
  2. 計(jì)算所有電腦的價(jià)格總和。
  3. 找出內(nèi)存最大的電腦的信息。
  4. 統(tǒng)計(jì)硬盤類型為SSD的電腦數(shù)量。
  5. 將所有電腦的產(chǎn)地轉(zhuǎn)換成一個(gè)不重復(fù)的集合。
  6. 創(chuàng)建一個(gè)Map,鍵為品牌,值為該品牌的電腦列表。
  7. 獲取每個(gè)品牌的平均價(jià)格。
  8. 獲取一個(gè)Map,鍵為計(jì)算機(jī)編號(hào),值為該計(jì)算機(jī)信息。

組合應(yīng)用

  1. 篩選出價(jià)格低于5000元且CPU核數(shù)大于等于4的電腦。
  2. 找出每個(gè)品牌中最貴的電腦,并返回一個(gè)包含這些電腦的列表。
  3. 統(tǒng)計(jì)每個(gè)品牌的電腦數(shù)量,并按數(shù)量降序排序。
  4. 找出所有品牌為“abc”且內(nèi)存大于等于8GB的電腦,并按CPU核數(shù)降序排序。
  5. 統(tǒng)計(jì)每個(gè)品牌的平均價(jià)格,并找出平均價(jià)格最高的品牌。
  6. 創(chuàng)建一個(gè)Map,鍵為品牌,值為該品牌所有電腦的總價(jià)。

經(jīng)典場(chǎng)景實(shí)戰(zhàn)攻克

下面我來帶大家一道一道攻克,并在這個(gè)過程中帶大家梳理一下Stream流使用過程中的一些注意事項(xiàng)。

我們假設(shè)需要處理的數(shù)據(jù)是一個(gè)ComputerDTO的List,如下:

List<ComputerDTO> computers=getComputers();

Stream流模型的操作很豐富,我們今天將使用到一些常用的方法,這些方法可以被分成兩種。

終結(jié)方法:返回值類型不再是Stream類型的方法,不再支持鏈?zhǔn)秸{(diào)用。如count、forEach、collect方法等。

非終結(jié)方法:返回值類型仍然是Stream類型的方法,支持鏈?zhǔn)秸{(diào)用。如map、filter、sorted方法等。

場(chǎng)景1

篩選出所有品牌為“abc”的電腦,并按價(jià)格降序排序。

List<ComputerDTO> abcComputers = computers.stream()
       .filter(computer -> "abc".equals(computer.getBrand()))
       .sorted(Comparator.comparing(ComputerDTO::getPrice).reversed())
       .collect(Collectors.toList());

首先我們將這個(gè)場(chǎng)景拆解成兩個(gè)過程,第一個(gè)過程是將列表中的所有品牌不為“abc”的電腦過濾掉,這里我們需要使用到filter方法。

filter方法的入?yún)⑹呛粋€(gè)參數(shù)返回結(jié)果為boolean類型的函數(shù)式接口,這里我們直接使用lambda表達(dá)式實(shí)現(xiàn)。

需要注意的是filter方法將會(huì)保留符合表達(dá)式的數(shù)據(jù),這里可以和集合的removeIf方法進(jìn)行對(duì)比記憶,并且我們使用stream處理數(shù)據(jù)并不會(huì)改變?cè)蟘omputers。

第二個(gè)過程是將過濾后的結(jié)果按照價(jià)格降序排序,這里我們使用sorted方法實(shí)現(xiàn)。

sorted方法的入?yún)⑹且粋€(gè)比較器Comparator,這里我們直接使用Comparator.comparing方法構(gòu)建一個(gè)根據(jù)價(jià)格排序的比較器,并使用reversed方法返回一個(gè)降序的比較器。

最后我們使用終結(jié)方法collect(Collectors.toList())將結(jié)果收集到集合當(dāng)中。

場(chǎng)景2

計(jì)算所有電腦的價(jià)格總和。

BigDecimal totalCost = computers.stream()
       .map(ComputerDTO::getPrice)
       .reduce(BigDecimal.ZERO, BigDecimal::add);

這個(gè)場(chǎng)景我們需要先將集合中的ComputerDTO對(duì)象轉(zhuǎn)換為價(jià)格,因?yàn)槲覀冃枰淖罱K結(jié)果是一個(gè)BigDecimal類型,所以需要先使用map方法對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換。

map方法的入?yún)⑹且粋€(gè)Function函數(shù)式接口,下面貼出一張圖幫助大家理解map方法的作用。

圖片圖片

map方法在工作中常常被使用,例如需要根據(jù)一個(gè)實(shí)體類集合獲取一個(gè)屬性值集合,通常先使用map方法獲取屬性值,看情況需要可以使用distinct方法去重、filter過濾、sorted方法排序,最后使用collect方法收集起來。

在當(dāng)前場(chǎng)景中我們需要計(jì)算所有電腦的價(jià)格總和,所以可以使用reduce終結(jié)方法進(jìn)行匯總。

圖片圖片

場(chǎng)景3

找出內(nèi)存最大的電腦的信息。

Optional<ComputerDTO> maxMemoryComputer = computers.stream()
       .max(Comparator.comparingInt(ComputerDTO::getMemory));

這個(gè)場(chǎng)景簡(jiǎn)單粗暴,直接將待處理數(shù)據(jù)轉(zhuǎn)成流,然后使用max方法就可以解決,不過需要注意的是max方法返回的數(shù)據(jù)使用Optional包了一層。

Optional類同樣是Java8提供的,使用isPresent方法可以判斷包含值是否為null,通過get方法可以獲取包含值,如果包含值為null會(huì)拋出一個(gè)NoSuchElementException異常,所以通常搭配isPresent方法使用。

場(chǎng)景4

統(tǒng)計(jì)硬盤類型為SSD的電腦數(shù)量。

long ssdCount = computers.stream()
       .filter(computer -> computer.getHardDisk().contains("SSD"))
       .count();

這個(gè)場(chǎng)景使用了一個(gè)新的終結(jié)方法count,count方法用于統(tǒng)計(jì)流中元素個(gè)數(shù),返回值類型為long類型。

場(chǎng)景5

將所有電腦的產(chǎn)地轉(zhuǎn)換成一個(gè)不重復(fù)的集合。

Set<String> places = computers.stream()
       .map(ComputerDTO::getPlace)
       .collect(Collectors.toSet());

這個(gè)場(chǎng)景在工作中常常會(huì)用到,也是上面提到的map的經(jīng)典用法,只不過這里將流中數(shù)據(jù)通過collect(Collectors.toSet())收集到了Set中,利用了Set的特性進(jìn)行去重,而沒有使用distinct方法進(jìn)行去重。

這里引申一下,上點(diǎn)難度,如果這里最終需要獲取的是根據(jù)產(chǎn)地去重后的ComputerDTO集合呢,使用流的方式又該怎樣實(shí)現(xiàn)。

這是工作中另外的一個(gè)經(jīng)典場(chǎng)景,List集合按照對(duì)象屬性去重,其實(shí)最終也是利用了Set的特性,在Set的構(gòu)造函數(shù)中傳入了自定義比較器!

List<ComputerDTO> newList = computers.stream().collect(Collectors
                .collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ComputerDTO::getPlace)))
                        , ArrayList::new));

這里使用的Collectors.collectingAndThen方法只是將返回結(jié)果Set轉(zhuǎn)化為了List,核心處理就是Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(ComputerDTO::getPlace)))。

場(chǎng)景6

創(chuàng)建一個(gè)Map,鍵為品牌,值為該品牌的電腦列表。

Map<String, List<ComputerDTO>> computersByBrand = computers.stream()
       .collect(Collectors.groupingBy(ComputerDTO::getBrand));

這個(gè)場(chǎng)景也是工作中常常會(huì)遇到的場(chǎng)景,對(duì)原有數(shù)據(jù)根據(jù)某一個(gè)緯度進(jìn)行分組,然后不同組的數(shù)據(jù)使用不同的邏輯進(jìn)行處理。Stream為這個(gè)需求也提供了專門的方法Collectors.groupingBy。

場(chǎng)景7

獲取每個(gè)品牌的平均價(jià)格。

Map<String, Double> averagePrices = computers.stream()
       .collect(Collectors.groupingBy(ComputerDTO::getBrand, Collectors.averagingDouble(c -> c.getPrice().doubleValue())));

這個(gè)場(chǎng)景是場(chǎng)景6的進(jìn)階玩法,根據(jù)某一個(gè)緯度進(jìn)行分組,分組后再對(duì)數(shù)據(jù)進(jìn)行處理。

這里使用的是Collectors.groupingBy兩個(gè)參數(shù)的重載方法。

場(chǎng)景8

獲取一個(gè)Map,鍵為計(jì)算機(jī)編號(hào),值為該計(jì)算機(jī)信息。

Map<String, ComputerDTO> computerInfoMap = computers.stream().collect(Collectors.toMap(ComputerDTO::getComputerNo, item -> item));

Map<String, ComputerDTO> computerInfoMap = computers.stream().collect(HashMap::new, (m, v) -> m.put(v.getComputerNo(), v), HashMap::putAll);

這個(gè)場(chǎng)景在工作中出現(xiàn)的頻率很高,通常有兩種方法去實(shí)現(xiàn),其中Collectors.toMap方法有一個(gè)小坑,大家在使用時(shí)需要注意一下。

java8的Collectors.toMap的value不能為null。

如果待處理的數(shù)據(jù)中value值存在null,則會(huì)出現(xiàn)莫名其妙的空指針異常,所以我在工作中往往會(huì)使用第二種方式。

組合應(yīng)用代碼參考

通過上面經(jīng)典場(chǎng)景的講解,其實(shí)我們可以注意到,基本上絕大多數(shù)的應(yīng)用都離不開collect方法,這個(gè)方法在流的使用中極為重要,在后續(xù)的文章中我也會(huì)為大家進(jìn)一步的講解collect方法,敬請(qǐng)期待!

組合場(chǎng)景就是對(duì)經(jīng)典場(chǎng)景中的一些常用API進(jìn)行組合應(yīng)用,所以就不在這里一一贅述,僅為大家提供了參考代碼。

  1. 篩選出價(jià)格低于5000元且CPU核數(shù)大于等于4的電腦。
List<ComputerDTO> affordableAndPowerful = computers.stream()
       .filter(computer -> computer.getPrice().compareTo(new BigDecimal("5000")) < 0 && computer.getCoreQuantity() >= 4)
       .collect(Collectors.toList());
  1. 找出每個(gè)品牌中最貴的電腦,并返回一個(gè)包含這些電腦的列表。
Map<String, ComputerDTO> mostExpensivePerBrand = computers.stream()
            .collect(Collectors.groupingBy(ComputerDTO::getBrand,
                    Collectors.collectingAndThen(
                            Collectors.maxBy(Comparator.comparing(ComputerDTO::getPrice)),
                            optional -> optional.orElseThrow(() -> new NoSuchElementException("No computers found for this brand"))
       )
   ));

    List<ComputerDTO> mostExpensiveComputers = new ArrayList<>(mostExpensivePerBrand.values());
  1. 統(tǒng)計(jì)每個(gè)品牌的電腦數(shù)量,并按數(shù)量降序排序。
Map<String, Long> brandCounts = computers.stream()
       .collect(Collectors.groupingBy(ComputerDTO::getBrand, Collectors.counting()));

   List<Map.Entry<String, Long>> sortedBrandCounts = brandCounts.entrySet().stream()
       .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
       .collect(Collectors.toList());
  1. 找出所有品牌為“abc”且內(nèi)存大于等于8GB的電腦,并按CPU核數(shù)降序排序。
List<ComputerDTO> abcHighMemoryComputers = computers.stream()
       .filter(computer -> "abc".equals(computer.getBrand()) && computer.getMemory() >= 8)
       .sorted(Comparator.comparingInt(ComputerDTO::getCoreQuantity).reversed())
       .collect(Collectors.toList());
  1. 統(tǒng)計(jì)每個(gè)品牌的平均價(jià)格,并找出平均價(jià)格最高的品牌。
Optional<Map.Entry<String, Double>> highestAveragePrice = computers.stream()
       .collect(Collectors.groupingBy(
           ComputerDTO::getBrand,
           Collectors.averagingDouble(c -> c.getPrice().doubleValue())
       ))
       .entrySet().stream()
       .max(Map.Entry.comparingByValue());

   String highestBrand = highestAveragePrice.map(Map.Entry::getKey).orElse(null);
   double highestAverage = highestAveragePrice.map(Map.Entry::getValue).orElse(0.0);
  1. 創(chuàng)建一個(gè)Map,鍵為品牌,值為該品牌所有電腦的總價(jià)。
Map<String, BigDecimal> totalPricesByBrand = computers.stream()
       .collect(Collectors.groupingBy(
           ComputerDTO::getBrand,
           Collectors.reducing(BigDecimal.ZERO, ComputerDTO::getPrice, BigDecimal::add)
       ));

結(jié)語

學(xué)會(huì)使用java8的Stream新特性,可以極大的減少工作中的代碼量,可以使自己的代碼看起來更整潔,同時(shí)很多框架源碼中也大量使用Stream,掌握了它也可以為我們閱讀源碼提供幫助,希望這篇文章可以給大家?guī)韼椭?/p>

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

2021-05-19 10:37:16

WebFlux 前置工具

2022-02-14 10:16:22

Axios接口HTTP

2022-12-09 07:48:10

Java8Stream表達(dá)式

2022-12-30 09:24:23

Java8Stream操作

2021-11-26 09:44:42

鏈表節(jié)點(diǎn)定位

2022-12-01 09:59:57

內(nèi)核觀測(cè)性方法

2021-05-20 07:15:34

RSA-PSS算法簽名

2023-03-28 07:32:37

2023-03-26 12:45:52

Linux內(nèi)核頭文件

2025-03-27 02:00:00

SPIJava接口

2022-07-29 08:17:46

Java對(duì)象內(nèi)存

2023-09-15 06:56:01

RC.NET 6Release

2023-09-29 08:58:38

2021-10-11 10:25:33

排列nums數(shù)組

2021-03-18 00:04:13

C# 類型數(shù)據(jù)

2022-12-06 08:12:11

Java關(guān)鍵字

2023-08-04 08:20:56

DockerfileDocker工具

2022-03-31 18:59:43

數(shù)據(jù)庫InnoDBMySQL

2022-05-24 08:21:16

數(shù)據(jù)安全API

2023-08-10 08:28:46

網(wǎng)絡(luò)編程通信
點(diǎn)贊
收藏

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