Java函數式編程(2):流式計算

来源:https://www.cnblogs.com/xiangwang1111/archive/2022/11/07/16864384.html
-Advertisement-
Play Games

您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~ Lambda表達式雖然將介面作為代碼塊賦值給了變數,但如果僅僅只是Lambda表達式,還無法讓Java由量變引起質變。真正讓Lambda能夠發揮出巨大威力的,就是流式計算。 所謂流式計算,就是讓數據像在流水線上一樣,從一道工序流轉到下一道工序。 ...


您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~

 

Lambda表達式雖然將介面作為代碼塊賦值給了變數,但如果僅僅只是Lambda表達式,還無法讓Java由量變引起質變。真正讓Lambda能夠發揮出巨大威力的,就是流式計算。

所謂流式計算,就是讓數據像在流水線上一樣,從一道工序流轉到下一道工序。就像這樣:

 

 

 

 

如果把數據處理的方式比作流水線,那麼Spark、Storm和Flink就是目前市面上頭部的三家工廠。它們有各種各樣的數據裝配間(也就是各種處理數據的運算元),將數據按照所需加工成型。所以,不懂流式計算根本就做不了大數據開發。上面那張圖,如果換成流式計算的,就是這樣:

 

 

 

Lambda表達式就變成了一個個的數據裝配間。

還是以實際的代碼例子來說明。假如有這樣的代碼:

/**
 * 雇員數據
 *
 * @author 湘王
 */
public class Employee {
    public enum Type { MANAGER, SELLER, OFFICER };
    private String name;
    private String genger;
    private Integer age;
    private boolean married;
    private Type type;
    public Employee(final String name, final String genger, final Integer age, final boolean married, final Type type) {
        super();
        this.name = name;
        this.genger = genger;
        this.age = age;
        this.married = married;
        this.type = type;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGenger() {
        return genger;
    }
    public void setGenger(String genger) {
        this.genger = genger;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public boolean isMarried() {
        return married;
    }
    public void setMarried(boolean married) {
        this.married = married;
    }
    public Type getType() {
        return type;
    }
    public void setType(Type type) {
        this.type = type;
    }
    @Override
    public String toString() {
        return this.name + "(" + this.genger + ")-" + this.age;
    }
}

 

 

如果想篩選28歲以下的員工,並按年齡排序,用老辦法只能這麼做:

List<Employee> employees = Arrays.asList(
        new Employee("張勇", "男", 28, true, Employee.Type.MANAGER),
        new Employee("李強", "男", 22, false, Employee.Type.SELLER),
        new Employee("王武", "男", 32, false, Employee.Type.SELLER),
        new Employee("梅麗", "女", 26, true, Employee.Type.OFFICER),
        new Employee("鄭帥", "男", 29, false, Employee.Type.OFFICER),
        new Employee("曾美", "女", 27, true, Employee.Type.SELLER),
        new Employee("郝俊", "男", 22, true, Employee.Type.SELLER),
        new Employee("方圓", "女", 24, false, Employee.Type.SELLER)
);

// 傳統篩選數據的方法
// 篩選28歲以下的員工
List<Employee> list1 = new ArrayList<>();
for(Employee employee : employees) {
    if (employee.getAge() < 28) {
        list1.add(employee);
    }
}
// 按年齡排序
list1.sort(new Comparator<Employee>() {
    @Override
    public int compare(Employee o1, Employee o2) {
        return o1.getAge().compareTo(o2.getAge());
    }
});

 

如果要轉換成Lmabda表達式的話,就是這樣:

/**
 * 雇員函數式介面
 *
 * @author 湘王
 */
@FunctionalInterface
public interface EmployeeInterface<T> {
    boolean select(T t);
}



public static List<Employee> filter(List<Employee> employees, EmployeeInterface<Employee> ei) {
    List<Employee> list = new ArrayList<>();
    for(Employee employee : employees) {
        if (ei.select(employee)) {
            list.add(employee);
        }
    }
    return list;
}



// 使用Lambda表達式得到28歲以下的員工
List<Employee> list2 = filter(employees, employee -> employee.getAge() < 28);

// 按年齡排序
list2.sort((e1, e2) -> e1.getAge().compareTo(e2.getAge()));

 

 

可以看到,這雖然用了Lambda表達式替代了舊的方法,但可能要寫大量的函數式介面,Lambda淪為雞肋,完全談不上簡便快速,更別說優雅!

所以,這時候如果用流式計算,那簡直不要太優雅:

// Lambda表達式 + 流式計算
List<Employee> list3 = employees
                                // 生成「流」
                                .stream()
                                // 過濾
                                .filter(emp -> emp.getAge() < 28)
                                // 排序
                                .sorted((o1, o2) -> o1.getAge().compareTo(o2.getAge()))
                                // 生成新的結果集合
                                .collect(Collectors.toList());

 

 

僅僅幾行代碼就搞定了,完全沒有之前那種「傻大黑粗」的感覺了。

上面的代碼,可以用這幅圖來還原:

 

 

 

1、先用filter運算元(流式計算中的函數,或者方法,在大數據中統稱為運算元,我也習慣這麼稱呼)將符合年齡條件的雇員篩選出來;

2、再按照年齡從低到高排序;

3、將排好序的員工列表輸出出來。

就是這麼簡單粗暴!

就像藏寶圖一樣,只有將Lambda表達式和流式計算這兩張碎片拼起來,才是完整的Java函數式編程。

 

所有的流式計算運算元可以分為兩大類:中間操作和終端操作。

1、中間操作:返回另一個流,如filter、map、flatMap等;

2、終端操作:從流水線中生成結果,如collect、count、reduce、forEach等。

 

現在,咱們已經找到了函數式編程這個寶藏。那麼再回到最初的問題:當要實現某寶、某東和某哈哈的員工聯誼並解決單身問題時,有更好的辦法嗎?

當然有,而且只用一行代碼就可以搞定:

List<Employee> unMarriedList4 = list.stream().filter(company -> Company.Type.BIG == company.getType()).flatMap(companys -> companys.getEmployees().stream()).filter(Employee::isMarried).sorted(Comparator.comparing(Employee::getAge)).collect(Collectors.toList());

 

 


 

 

感謝您的大駕光臨!咨詢技術、產品、運營和管理相關問題,請關註後留言。歡迎騷擾,不勝榮幸~

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 好家伙,JS基礎接著學, 本篇內容為《JS高級程式設計》第四章學習筆記 1.原始值和引用值 ECMAScript變數可以包含兩種不同類型的數據:原始值和引用值。原始值(primitive value)就是最簡單的數據,引用值(reference value)則是由多個值構成的對象。 在把一個值賦給變 ...
  • 前言 這是疫情可視化最開始的文章,有需要瞭解的可前往查看:https://www.cnblogs.com/xi12/p/16690119.html。 本來說有時間就把這個項目完結了的,結果後面一直有事拖著,直到現在十一月份了才搞完。老樣子,先看成果。 瀏覽鏈接:https://xi1213.gite ...
  • call,apply,bind都是一種方法。 一,call() ①:call() 是可以 調用函數的。 1 function fn() { 2 console.log(12) 3 } 4 5 fn.call() // 12 ②:通過給call() 內部傳參,可以改變 this指向。 1 let Do ...
  • React 全家桶-React基礎 用於構建用戶界面的JavaScript庫。 facebook開源、組件化、聲明式編碼、React Native移動端開發、虛擬DOM+Diffing演算法 官網:https://react.docschina.org/ 第一章:React的基本使用 1.相關js庫 ...
  • 具體需求 在我的疫情可視化項目中有一個功能需要導出word文檔,在頁面點擊按鈕後處理數據生成word文件,然後自動下載文檔。 實現步驟 多番查詢後發現前端導出word,使用docxtemplater較為方便。具體使用步驟如下: 安裝docxtemplater:npm i docxtemplater ...
  • 導讀:對於錯誤碼的設計,不同的開發團隊有不同的風格習慣。本文分享阿裡文娛技術專家長統對於錯誤碼的看法,希望從錯誤碼使用的不同場景討論得到一個合理的錯誤碼規約,得到一個面嚮日志錯誤碼標準和一個面向外部傳遞的錯誤碼標準。 ...
  • 1、UML統一建模語言 定義:用於軟體系統設計與分析的語言工具 目的:幫助開發人員更好的梳理邏輯、思路 學習地址:UML概述_w3cschool 官網:https://www.omg.org/spec/UML 1.1、UML組成結構 flowchart TD; UML圖 --> 結構圖 & 行為圖; ...
  • 一、人狗大戰 1、需求 用代碼模擬人、狗打架的小游戲 人和狗種類不同,因此雙方的屬性各不相同 推導一: 人和狗各有不同屬性 使用字典方式儲存屬性較為方便,並可儲存多種屬性 # 1、在字典內儲存‘人’屬性 person = { 'name': '阿拉蕾', 'age': 18, 'gender': ' ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...