亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java?Stream.reduce()用法詳細(xì)解析

 更新時間:2022年12月13日 15:03:20   作者:向著百萬年薪努力的小趙  
Stream API提供了豐富的中間函數(shù),歸并函數(shù)和終端函數(shù),這些函數(shù)還支持并行化執(zhí)行,下面這篇文章主要給大家介紹了關(guān)于Java?Stream.reduce()用法的相關(guān)資料,需要的朋友可以參考下

在學(xué)習(xí)這個函數(shù)的用法之前,我們要先知道這個函數(shù)參數(shù)的意義

基本使用

先舉一個簡單的例子:

算法題:Words
題目描述
每個句子由多個單詞組成,句子中的每個單詞的長度都可能不一樣,我們假設(shè)每個單詞的長度Ni為該單詞的重量,你需要做的就是給出整個句子的平均重量V。

解答要求
時間限制:1000ms, 內(nèi)存限制:100MB
輸入
輸入只有一行,包含一個字符串S(長度不會超過100),代表整個句子,句子中只包含大小寫的英文字母,每個單詞之間有一個空格。

輸出
輸出句子S的平均重量V(四舍五入保留兩位小數(shù))。

Who Love Solo
輸出樣例 
3.67

這道題的意思是求一句話中每個單詞的平均長度,我們求得總長度然后除以單詞數(shù)量即可,剛好能用到reduce()這個方法。

public class Demo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[] s = sc.nextLine().split(" ");
        double res = Arrays.stream(s).mapToDouble(a ->a.length()).reduce(0,(a,b)->a+b);
        System.out.println(String.format("%.2f",res/s.length));
    }
}

在代碼中,.reduce(0,(a,b)->a+b);這一塊就是我們經(jīng)典的使用案例,我們要先明白其中a,b的含義,然后再學(xué)習(xí)如何使用
關(guān)鍵概念:初始值的定義(Identity),累加器(Accumulator),組合器(Combiner)

  • Identity : 定義一個元素代表是歸并操作的初始值,如果Stream 是空的,也是Stream 的默認(rèn)結(jié)果
  • Accumulator: 定義一個帶兩個參數(shù)的函數(shù),第一個參數(shù)是上個歸并函數(shù)的返回值,第二個是Strem 中下一個元素。
  • Combiner: 調(diào)用一個函數(shù)來組合歸并操作的結(jié)果,當(dāng)歸并是并行執(zhí)行或者當(dāng)累加器的函數(shù)和累加器的實(shí)現(xiàn)類型不匹配時才會調(diào)用此函數(shù)。

也就是說0就是我們的初始值,(a,b)->a+b就是我們的累加器,其中a就是上一次的計算結(jié)果,b就是Stream流中當(dāng)前元素,而后面的a+b則是計算規(guī)則,比如如果我們改成a*b,那就是計算乘積了,當(dāng)然我們也可以用方法引用來代替 lambda 表達(dá)式。

double res = Arrays.stream(s).mapToDouble(a ->a.length()).reduce(0,Double::sum);

這就是最基本的使用了,不知道小伙伴們有沒有學(xué)會呢?

額外舉例

當(dāng)然,我們可以用reduce 方法處理其他類型的 stream,例如,可以操作一個 String 類型的數(shù)組,把數(shù)組的字符串進(jìn)行拼接。

List<String> letters = Arrays.asList("a", "b", "c", "d", "e");
String result = letters
  .stream()
  .reduce("", (partialString, element) -> partialString + element);
assertThat(result).isEqualTo("abcde");

同樣也可以用方法引用來簡化代碼

String result = letters.stream().reduce("", String::concat);
assertThat(result).isEqualTo("abcde");

我們再把上面的拼接字符串的例子改下需求,先把字符串轉(zhuǎn)變成大寫然后再拼接

String result = letters
  .stream()
  .reduce(
    "", (partialString, element) -> partialString.toUpperCase() + element.toUpperCase());
assertThat(result).isEqualTo("ABCDE");

另外,我們可以并行地歸并元素(并行歸并,下面會詳細(xì)講解),如下并行歸并一個數(shù)字?jǐn)?shù)組來求和

List<Integer> ages = Arrays.asList(25, 30, 45, 28, 32);
int computedAges = ages.parallelStream().reduce(0, a, b -> a + b, Integer::sum);

當(dāng)對一個流進(jìn)行并行操作時,在運(yùn)行時會把流分割多個子流來并行操作。在上面例子中,我們需要一個函數(shù)來組合各個子流返回的結(jié)果,這個函數(shù)就是前面提到的Combiner(組合器)。

有一個注意點(diǎn),下面的代碼無法通過編譯

List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
int computedAges = 
  users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());

上代碼無法編譯的原因是,流中包含的是User 對象,但是累加函數(shù)的參數(shù)分別是數(shù)字和user 對象,而累加器的實(shí)現(xiàn)是求和,所以編譯器無法推斷參數(shù) user 的類型。可以把代碼改為如下可以通過編譯

int result = users.stream()
  .reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(), Integer::sum);
assertThat(result).isEqualTo(65);

當(dāng)順序讀流或者累加器的參數(shù)和它的實(shí)現(xiàn)的類型匹配時,我們不需要使用組合器。

并行讀流

如上文提到的,我們可以并行的使用 reduce() 方法。并行使用時,要注意一下幾點(diǎn):

  • 結(jié)果和處理的順序無關(guān)
  • 操作不影響原有數(shù)據(jù)
  • 操作沒有狀態(tài)和同樣的輸入有一樣的輸出結(jié)果
    我們注意上面3點(diǎn),以防出現(xiàn)不預(yù)期的結(jié)果,一般并行處理包含大量數(shù)據(jù)的流或者耗時的操作。

處理異常

在以上的例子中,reduce 方法都沒拋出異常,如果出現(xiàn)異常我們該如何優(yōu)雅的處理異常呢?看下面例子:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int divider = 2;
int result = numbers.stream().reduce(0, a / divider + b / divider);

如果 divider =0 , 會拋出 ArithmeticException,遇到這種情況,一般的處理方法使用 try/catch 捕獲異常

public static int divideListElements(List<Integer> values, int divider) {
    return values.stream()
      .reduce(0, (a, b) -> {
          try {
              return a / divider + b / divider;
          } catch (ArithmeticException e) {
              LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");
          }
          return 0;
      });
}

如果直接使用 try/catch 會影響代碼的可讀性,我們可以把 divide 的操作封裝一個單獨(dú)的方法,并在里面捕獲異常,如下:

rivate static int divide(int value, int factor) {
    int result = 0;
    try {
        result = value / factor;
    } catch (ArithmeticException e) {
        LOGGER.log(Level.INFO, "Arithmetic Exception: Division by Zero");
    }
    return result
}

divideListElements 調(diào)用 divide 方法

public static int divideListElements(List<Integer> values, int divider) {
    return values.stream().reduce(0, (a, b) -> divide(a, divider) + divide(b, divider));
}

復(fù)雜對象的處理

我們可以使用 reduce 方法處理復(fù)雜的對象,reduce 需要接受和復(fù)雜對象相對應(yīng)的 identity、accumulator、combiner。
假設(shè)一個場景:計算一個網(wǎng)站用戶的評分,該評分是所有用戶所有評論的平均值。

有個類 Review 定義如下:

public class Review {
 
    private int points;
    private String review;
 
    // constructor, getters and setters
}

類 Rating 引用 Review 計算用戶的評分

public class Rating {
 
    double points;
    List<Review> reviews = new ArrayList<>();
 
    public void add(Review review) {
        reviews.add(review);
        computeRating();
    }
 
    private double computeRating() {
        double totalPoints = 
          reviews.stream().map(Review::getPoints).reduce(0, Integer::sum);
        this.points = totalPoints / reviews.size();
        return this.points;
    }
 
    public static Rating average(Rating r1, Rating r2) {
        Rating combined = new Rating();
        combined.reviews = new ArrayList<>(r1.reviews);
        combined.reviews.addAll(r2.reviews);
        combined.computeRating();
        return combined;
    }
 
}

先組裝一些用戶和用戶的評論

User john = new User("John", 30);
john.getRating().add(new Review(5, ""));
john.getRating().add(new Review(3, "not bad"));
User julie = new User("Julie", 35);
john.getRating().add(new Review(4, "great!"));
john.getRating().add(new Review(2, "terrible experience"));
john.getRating().add(new Review(4, ""));
List<User> users = Arrays.asList(john, julie);

調(diào)用 reduce 方法處理評分

Rating averageRating = users.stream()
  .reduce(new Rating(), 
    (rating, user) -> Rating.average(rating, user.getRating()), 
    Rating::average);

不知道大家學(xué)會了嗎?

總結(jié)

到此這篇關(guān)于Java Stream.reduce()用法的文章就介紹到這了,更多相關(guān)Stream.reduce()用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于Java實(shí)現(xiàn)計數(shù)排序,桶排序和基數(shù)排序

    基于Java實(shí)現(xiàn)計數(shù)排序,桶排序和基數(shù)排序

    這篇文章主要為大家詳細(xì)介紹了計數(shù)排序,桶排序和基數(shù)排序的多種語言的實(shí)現(xiàn)(JavaScript、Python、Go語言、Java),感興趣的小伙伴可以了解一下
    2022-12-12
  • 基于Java中最常用的集合類框架之HashMap(詳解)

    基于Java中最常用的集合類框架之HashMap(詳解)

    下面小編就為大家?guī)硪黄贘ava中最常用的集合類框架之HashMap(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • 一文搞懂MyBatis多數(shù)據(jù)源Starter實(shí)現(xiàn)

    一文搞懂MyBatis多數(shù)據(jù)源Starter實(shí)現(xiàn)

    本文將實(shí)現(xiàn)一個MyBatis的Springboot的Starter包,引用這個Starter包后,僅需要提供少量配置信息,就能夠完成MyBatis多數(shù)據(jù)源的初始化和使用,需要的小伙伴可以參考一下
    2023-04-04
  • springboot+mybatis plus實(shí)現(xiàn)樹形結(jié)構(gòu)查詢

    springboot+mybatis plus實(shí)現(xiàn)樹形結(jié)構(gòu)查詢

    實(shí)際開發(fā)過程中經(jīng)常需要查詢節(jié)點(diǎn)樹,根據(jù)指定節(jié)點(diǎn)獲取子節(jié)點(diǎn)列表,本文主要介紹了springboot+mybatis plus實(shí)現(xiàn)樹形結(jié)構(gòu)查詢,感興趣的可以了解一下
    2021-07-07
  • java為什么使用BlockingQueue解決競態(tài)條件問題面試精講

    java為什么使用BlockingQueue解決競態(tài)條件問題面試精講

    這篇文章主要為大家介紹了java為什么使用BlockingQueue解決競態(tài)條件問題面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Mybatis-plus配置分頁插件返回統(tǒng)一結(jié)果集

    Mybatis-plus配置分頁插件返回統(tǒng)一結(jié)果集

    本文主要介紹了Mybatis-plus配置分頁插件返回統(tǒng)一結(jié)果集,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 淺談Java之Map 按值排序 (Map sort by value)

    淺談Java之Map 按值排序 (Map sort by value)

    下面小編就為大家?guī)硪黄獪\談Java之Map 按值排序 (Map sort by value)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • 關(guān)于easyExcel中讀取Excel表頭的實(shí)例說明

    關(guān)于easyExcel中讀取Excel表頭的實(shí)例說明

    EasyExcel是阿里巴巴開源的一個excel處理框架,以使用簡單、節(jié)省內(nèi)存著稱,下面這篇文章主要給大家介紹了關(guān)于easyExcel中讀取Excel表頭的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • 淺談Spring6中的反射機(jī)制

    淺談Spring6中的反射機(jī)制

    Java反射機(jī)制是Java語言中一種動態(tài)(運(yùn)行時)訪問、檢測、修改它本身的能力,主要作用是動態(tài)(運(yùn)行時)獲取類的完整結(jié)構(gòu)信息、調(diào)用對象的方法,需要的朋友可以參考下
    2023-05-05
  • SpringCloud微服務(wù)架構(gòu)升級匯總

    SpringCloud微服務(wù)架構(gòu)升級匯總

    這篇文章主要介紹了SpringCloud微服務(wù)架構(gòu)升級匯總,它提倡將單一應(yīng)用程序劃分成一組小的服務(wù),服務(wù)之間互相協(xié)調(diào)、互相配合,為用戶提供最終價值,需要的朋友可以參考下
    2019-06-06

最新評論