日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

函数式编程[Lambda 表达式,Optional,Stream流]从入门到精通(一)

發布時間:2023/12/9 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 函数式编程[Lambda 表达式,Optional,Stream流]从入门到精通(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 函數式編程、stream流
      • 1.概述
        • 1.1 學習目的
        • 1.2 函數式編程思想
      • 2.lambda表達式
        • 2.1 概述
        • 2.2 省略規則
      • 3. stream流
        • 3.1 概述
        • 3.2 功能
        • 3.3 常用方法說明 com/jonny/stream/StreamDemo.java
        • 3.4 常用操作
          • 3.4.1 創建流
          • 3.4.2 中間操作
          • 3.4.3 終結操作
        • 3.5 注意事項

函數式編程、stream流

1.概述

1.1 學習目的

  • 代碼可讀性
  • 避免過分嵌套
  • 看懂別人寫的代碼
  • 大數據量下集合處理效率
  • 底層使用多線程處理并線程安全可以保障?

1.2 函數式編程思想

  • 面向對象思想主要是關注對象能完成什么事情,函數式編程思想就像函數式,主要是針對數據操作;
  • 代碼簡潔容易理解,方便于并發編程,不需要過分關注線程安全問題

2.lambda表達式

2.1 概述

  • lambda是JDK8中的一個語法糖,可以對某些匿名內部類的寫法進行優化,讓函數式編程只關注數據而不是對象。
  • 基本格式:(參數列表)->{方法體}

2.2 省略規則

  • 參數類型可以省略
  • 方法體只有一句代碼時,大括號和 return 以及 唯一代碼的分號可以省略
  • 方法只有一個參數時[即,參數列表只有一個參數時] 小括號可以省略
  • 如果上面這些記不住,可以不省略也行

3. stream流

3.1 概述

  • stream使用的是函數式編程模式,可以被用來對集合或數組進行鏈狀流式的操作
  • 有別于其他輸入輸出流,這里是針對集合操作數據的流哦
  • 創建流實戰:com.jonny.stream.StreamDemo
    • 練習一:
      • 打印年齡小于18歲的作者名字,并去重
      • /** 練習一: 打印年齡小于18的作者姓名,并且去重*/getAuthors().stream().distinct().filter(new Predicate<Author>() {@Overridepublic boolean test(Author author) {return author.getAge() < 18;}}).forEach(new Consumer<Author>() {@Overridepublic void accept(Author author) {System.out.println(author.getName());}});

3.2 功能

  • 流不存儲元素。它只是通過計算操作的流水線從數據結構, 數組或I/O通道等源中傳遞元素。
  • 流本質上是功能性的。對流執行的操作不會修改其源。例如, 對從集合中獲取的流進行過濾會產生一個新的不帶過濾元素的流, 而不是從源集合中刪除元素。
  • Stream是惰性的, 僅在需要時才評估代碼。
  • 在流的生存期內, 流的元素只能訪問一次。像Iterator一樣, 必須生成新的流以重新訪問源中的相同元素。

3.3 常用方法說明 com/jonny/stream/StreamDemo.java

抽取方法快捷鍵: Mac:[? + ? + M] Win: ctrl + alt + M

顯示方法參數提示快捷鍵 : ? + P

  • map:相當于對數據進行一個操作,可以自定義返回值等
  • distinct:可以去除流中的相同元素,注意(該方法依賴的Object的equals方法來判斷是否是相同對象,所以要重寫equals方法,否則只有對象地址一樣時才會被認為是重復)
  • sorted:可以對流中的元素進行排序,傳入空參時使用的是實體類的比較方法
  • limit:設置流的最大長度,超出部分將被拋棄
  • skip:跳過流中的前n個元素,返回剩下的元素
  • flatMap:map能把一個對象轉換成另外一個對象來作為流中的元素,而flatMap可以把一個對象轉換成多個對象作為流中的元素
  • 中間操作(filter,map,distinct,sorted,limit,skip,flatMap)
  • 終結操作(forEach,collect,count,max,min,reduce歸并,查找與匹配)
  • forEach:遍歷所有元素
  • count:計算元素數量
  • min&max:返回的是option對象,這里和sorted一樣,得指定比較規則
  • collect:把當前流轉換成一個集合(list, set, map)
    • Collectors.toList()
    • Collectors.toSet()
    • Collectors.toMap(key, value)
  • anyMatch:可以用來判斷是否有任意符合匹配條件的元素,結果為boolean類型
  • allMatch:可以用來判斷是否都匹配條件,結果也是boolean類型,都符合則為true
  • noneMatch:是否都不符合,都不符合則為true
  • findAny:獲取流中的任意一個元素,該方法無法保證獲取的是流中的第一個元素,只是匹配到
  • findFirst:獲取流中的第一個元素
  • reduce:對流中的數據按照你制定的計算方式計算出一個結果,并返回一個Optional描述歸約值(如果有)T result = identity; for(T element : this stream) {result = accumulator.apply(result, element); // 執行具體數據操作 } return result; // 還有一種三個方法的重載方法,后面還需要補充

3.4 常用操作

3.4.1 創建流
  • 單列集合:集合對象.stream()
    • List<Author> authors = getAuthors();Stream<Author> stream = authors.stream();
  • 數組: Arrays.stream(數組)或者Stream.of(數組)
    • Integer[] arr = {1,2,3,4,5};Stream<Integer> stream = Arrays.stream(arr);Stream<Integer> stream2 = Stream.of(arr);
  • 雙列集合:轉換成單列集合再創建
    • Map<String, Integer> map = new HashMap<>();map.put("蠟筆小新",19);map.put("黑子",17);map.put("日向翔陽",16);Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
3.4.2 中間操作
  • filter

    • 對流中元素進行過濾,符合條件的元素才可以留在流中
    • // 例如打印作家姓名長度小于 3 的作家名 authors.stream().filter(author -> author.getName().length() < 3).forEach(author -> System.out.println("作家名: " + author.getName()));
  • map

    • 可以對流中的元素進行計算或者轉換
    • // 例如:打印所有作家的姓名List<Author> authors = getAuthors();authors.stream().map(author -> author.getName()).forEach(name -> System.out.println(name));// 將所有的作家年齡?10并輸出authors.stream().map(author -> author.getAge()).map(age -> age+10 ).forEach(age -> System.out.println(age));
  • distinct

    • 可以去除流中的重復元素
      • 注意:
        • distinct方法是依賴于Object 方法的equals 方法來判斷是否相同對象的
        • 而 Object 的equals 方法是 == 判斷的是兩個對象的地址是否相同
        • 所以要看傳入類型是否有重寫 equals 方法,
        • 沒有重寫則是繼承 Object 的 equals 方法,需要手動重寫
    • // 打印所有作家的姓名,并且不能有重復元素List<Author> authors = getAuthors();authors.stream().distinct().forEach(author -> System.out.println(author.getName()));
  • sorted

    • 可以對流中的元素進行排序
    • // 對流中的元素按年齡進行排序,并且去除重復項 List<Author> authors = getAuthors();authors.stream().distinct().sorted((o1, o2) -> {// return o1.getAge() - o2.getAge(); // 升序return o2.getAge() - o1.getAge(); // 降序}).forEach(author -> System.out.println(author.getAge()));
    • 注意
      • 如果調用空參的 sorted 的方法,需要流中的元素實現 Comparable接口
  • limit

    • 可以設置流的最大長度,超出部分將被拋棄
    • 例如:
      對流中的元素按照年齡進行降序排序,并且要求不能有重復的元素,然后打印其中年齡最大的兩個作家的姓名。
      • List<Author> authors = getAuthors();authors.stream().distinct().sorted((o1, o2) -> o2.getAge() - o1.getAge()).limit(2).forEach(author -> System.out.println(author.getName()));}
  • skip

    • 跳過流中的前n個元素,返回剩下的元素
    • 例如:
      打印除了年齡最大的作家外的其他作家,要求不能有重復元素,并且按照年齡降序排序。
      • List<Author> authors = getAuthors();authors.stream().distinct().sorted((o1, o2) -> o2.getAge() - o1.getAge()).skip(1).forEach(author -> System.out.println(author.getName()));
  • flatMap

    • map只能把一個對象轉換成另一個對象來作為流中的元素。
    • 而flatMap可以把一個對象轉換成多個對象作為流中的元素。
    • 例一:
      打印所有書籍的名字。要求對重復的元素進行去重。
      • List<Author> authors = getAuthors();authors.stream().flatMap(author -> author.getBookList().stream()) // 將Author流轉換成Book流.distinct() // 去重.forEach(book -> System.out.println(book.getName()));
    • 例二:
      打印現有數據的所有分類。要求對分類進行去重。不能出現這種格式:哲學,愛情
      • List<Author> authors = getAuthors();authors.stream().flatMap(author -> author.getBookList().stream()).distinct().flatMap(book -> Arrays.stream(book.getCategory().split(","))).distinct().filter(category -> "哲學".equals(category) || "愛情".equals(category) ? false : true).forEach(category -> System.out.println(category));
3.4.3 終結操作
  • forEach

    • 對流中的元素進行遍歷操作,我們通過傳入的參數去指定對遍歷到的元素進行什么具體操作。
    • 例子:輸出所有作家的名字
      • List<Author> authors = getAuthors();authors.stream().map(author -> author.getName()).distinct().forEach(name -> System.out.println(name));
  • count

    • 可以用來獲取當前流中元素的個數。
    • 例子:
      打印這些作家的所出書籍的數目,注意刪除重復元素。
      • List<Author> authors = getAuthors();long count = authors.stream().flatMap(author -> author.getBookList().stream()).distinct().count();System.out.println(count);
  • max & min

    • 可以用來或者流中的最值。
    • 例子:
      分別獲取這些作家的所出書籍的最高分和最低分并打印。
      • // 分別獲取這些作家的所出書籍的最高分和最低分并打印。List<Author> authors = getAuthors();Optional<Integer> max = authors.stream().flatMap(author -> author.getBookList().stream()).map(book -> book.getScore()).max((score1, score2) -> { return score1 - score2; });Optional<Integer> min = authors.stream().flatMap(author -> author.getBookList().stream()).map(book -> book.getScore()).min((score1, score2) -> { return score1 - score2; });System.out.println(max.get());System.out.println(min.get());
  • collectr

    • 把當前流轉換成一個集合。
    • 例子:
      • 獲取一個存放所有作者名字的List集合。
      • // 獲取一個存放所有作者名字的List集合。List<Author> authors = getAuthors();List<String> list = authors.stream().distinct() // 去重.map(author -> author.getName()) // 獲得所有作家的名字.collect(Collectors.toList()); // 轉換成ListSystem.out.println(list);
      • 獲取一個所有書名的Set集合。
      • // 獲取一個所有書名的Set集合。List<Author> authors = getAuthors();Set<Book> set = authors.stream().flatMap(author -> author.getBookList().stream()).collect(Collectors.toSet());// 轉換成Set 集合System.out.println(set);
      • 獲取一個map集合,map的key為作者名,value為List
      • // 獲取一個map集合,map的key為作者名,value為List<Book>List<Author> authors = getAuthors();Map<String, List<Book>> collect = authors.stream().distinct() // 去重.collect(Collectors.toMap(author -> author.getName(), author -> author.getBookList())); // 轉換成Map 集合System.out.println(collect);
  • 查找與匹配

    • anyMatch

      • 可以用來判斷是否有任意符合匹配條件的元素,結果為boolean類型。
      • 例子:
        判斷是否有年齡在17以上的作家
      • List<Author> authors = getAuthors();boolean match = authors.stream().anyMatch(author -> author.getAge() > 17);System.out.println(match);
    • allMatch

      • 可以用來判斷是否都符合匹配條件,結果為boolean類型。如果都符合結果為true,否則結果為false。
      • 例子:
        判斷是否所有的作家都是成年人
      • List<Author> authors = getAuthors();boolean match = authors.stream().allMatch(author -> author.getAge() >= 18);System.out.println(match);
    • noneMatch

      • 可以判斷流中的元素是否都不符合匹配條件。如果都不符合結果為true,否則結果為false
      • 例子:
        判斷作家是否都沒有超過100歲的。
      • List<Author> authors = getAuthors();boolean match = authors.stream().noneMatch(author -> author.getAge() > 100);System.out.println(match);
    • findAny

      • 獲取流中的任意一個元素。該方法沒有辦法保證獲取的一定是流中的第一個元素。
      • 例子:
        獲取任意一個年齡大于18的作家,如果存在就輸出他的名字
      • List<Author> authors = getAuthors();Optional<Author> optionalAuthor = authors.stream().filter(author -> author.getAge() > 18).findAny();optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
    • findFirst

      • 獲取流中的第一個元素。
      • 例子:
        獲取一個年齡最小的作家,并且輸出他的名字
      • List<Author> authors = getAuthors();Optional<Author> optionalAuthor = authors.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).findFirst();optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
  • reduce 歸并

    • 對流中的數據按照你指定的計算方式計算出一個結果。
    • reduce的作用是把stream中的元素給組合起來,我們可以傳入一個初始值,它會按照我們的計算方式依次拿流中的元素和初始化值 的基礎上進行計算,計算結果再和后面的元素計算。
    • reduce 兩個參數內部的重載形式 內部的計算方式如下:
      • T result = identity;for(T element this stream)result = accumulator .apply(result, element)return result;
      • 其中identity就是我們可以通過方法參數傳入的初始值,accumulator的apply具體進行什么計算也是我們通過方法參數來確定的。
    • 例子
      • 使用reduce求所有作者年齡的和
        • List<Author> authors = getAuthors(); Integer sum = authors.stream().distinct().map(author -> author.getAge()).reduce(0, (result, element) -> result + element); System.out.println(sum);
      • 使用reduce求所有作者中年齡的最大值
        • List<Author> authors = getAuthors(); Integer max = authors.stream().distinct().map(author -> author.getAge()).reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result); System.out.println(max);
      • 使用reduce求所有作者中年齡的最小值
        • List<Author> authors = getAuthors(); Integer min = authors.stream().distinct().map(author -> author.getAge()).reduce(Integer.MAX_VALUE, (result, element) -> result < element ? result : element); System.out.println(min);
    • reduce 一個參數的重載形式內部的計算
      • boolean foundAny = false;T result = null;for (T element : this stream) {if (!foundAny) {foundAny = true;result = element;}elseresult = accumulator.apply(result, element);}return foundAny ? Optional.of(result) : Optional.empty();
      • 如果用 reduce 一個參數重載形式,求所有作家年齡的最小值和最大值代碼如下
        • List<Author> authors = getAuthors(); // 使用reduce求所有作者中年齡的最小值 Optional<Integer> minOptional = authors.stream().distinct().map(author -> author.getAge()).reduce((result, element) -> result < element ? result : element); minOptional.ifPresent(age -> System.out.println(age)); // 使用reduce求所有作者中年齡的最大值 Optional<Integer> maxOptional = authors.stream().distinct().map(author -> author.getAge()).reduce((result, element) -> result > element ? result : element); maxOptional.ifPresent(age -> System.out.println(age));

3.5 注意事項

  • 惰性求值(如果沒有終結操作沒有中間操作是不會得到執行的)
  • 流是一次性的(一旦一個流對象經過終結操作之后,這個流對象就不能再被使用)
    • 如果再次被使用回報以下異常
    • Exception in thread "main〞 java. 1ang. IllegalStateException: stream has already been operated upon or closed
  • 不會影響元數據(我們在流中可以多數據做很多處理。但是正常情況下是不會影響原來集合中的元素的。這往往也是我們期望的)
    • 示例代碼驗證
      • 正常情況下,不會影響原來元素如下:
      • List<Author> authors = getAuthors();// 正常情況下,不會影響原來元素如下:authors.stream().map(author -> author.getAge()).map(age -> age += 10).forEach(age -> System.out.println(age));authors.forEach(author -> System.out.println(author.getAge()));
      • 非正常情況下會影響原來的元素如下:
      • List<Author> authors = getAuthors();// 非正常情況下會影響原來的元素如下:authors.stream().map(author -> {author.setAge(author.getAge() + 10);return author;}).forEach(author -> System.out.println(author.getAge()));authors.forEach(author -> System.out.println(author.getAge()));
    • 只要不主動修改元素的堆棧地址,就不會改變原數據

總結

以上是生活随笔為你收集整理的函数式编程[Lambda 表达式,Optional,Stream流]从入门到精通(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。