日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

lambda表達式和Stream

作者:有什么奇怪! 更新時間: 2022-07-11 編程語言

文章目錄

  • 1、關于Lambda表達式
    • 1.1 概述
    • 1.2 基本格式
    • 1.3 省略規則
    • 1.4 小細節
  • 2、Stream流
    • 2.1 數據準備
    • 2.2 創建流的方式
    • 2.3 中間操作
      • filter
      • map
      • distinct
      • sorted
      • limit
      • skip
      • flatMap
    • 2.4 終結操作
      • forEach
      • count
      • max&min
      • collect
      • 查找與匹配
        • anyMatch
        • allMatch
        • noneMatch
        • findAny
        • findFirst
      • reduce歸并
    • 2.5 注意事項

提到lambda表達式,就不得不得不說到一個叫做函數式編程思想的東西,這樣說肯定是懵懵的。我們可以把他理解為一個數學函數,只關心入參和出參,而不去關注方法名,這樣就可以淺略的理解函數式編程。

函數式編程思想就類似于我們數學中的函數。它主要關注的是對數據進行了什么操作。

1、關于Lambda表達式

1.1 概述

? Lambda是JDK8中一個語法糖。他可以對某些匿名內部類的寫法進行簡化。它是函數式編程思想的一個重要體現。讓我們不用關注是什么對象。而是更關注我們對數據進行了什么操作。

1.2 基本格式

(參數列表)->{代碼}

例一:

在創建線程并啟動時可以使用匿名內部類的寫法:

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("1001001");
    }
}).start();

可以將其轉換為Lambda格式

new Thread(()->{
    System.out.println("1001001");
}).start();
// 沒有參數,所以參數列表可以省略
// Runnable接口的匿名方法只有一個run方法,所以也可以省略

例二:

現有方法定義如下,其中IntPredicate是一個接口。先使用匿名內部類的寫法調用該方法。

    public static void printNum(IntPredicate predicate){
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        for (int i : arr) {
            if(predicate.test(i)){
                System.out.println(i);
            }
        }
    }
    public static void main(String[] args) {
        printNum(new IntPredicate() {
            @Override
            public boolean test(int value) {
                return value%2==0;
            }
        });
    }

lambda寫法:

    public static void main(String[] args) {
        printNum((int value)-> {
            return value%2==0;
        });
    }
    public static void printNum(IntPredicate predicate){
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        for (int i : arr) {
            if(predicate.test(i)){
                System.out.println(i);
            }
        }
    }

1.3 省略規則

  • 參數類型可以省略
  • 方法體只有一句代碼時大括號return和唯一一句代碼的分號可以省略
  • 方法只有一個參數時小括號可以省略
  • 以上這些規則都記不住也可以省略不記

1.4 小細節

我們在寫匿名內部類時,不熟悉的化,沒必要直接寫為lambda表達式。而是可以直接寫成匿名內部類,然后在IDEA中 ALT + Enter自動補全為匿名內部類。

2、Stream流

Java8的Stream使用的是函數式編程模式,如同它的名字一樣,它可以被用來對集合或數組進行鏈狀流式的操作。可以更方便的讓我們對集合或數組操作。

在這里插入圖片描述

2.1 數據準備

@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Author {
    //id
    private Long id;
    //姓名
    private String name;
    //年齡
    private Integer age;
    //簡介
    private String intro;
    //作品
    private List<Book> books;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode//用于后期的去重使用
public class Book {
    //id
    private Long id;
    //書名
    private String name;

    //分類
    private String category;

    //評分
    private Integer score;

    //簡介
    private String intro;

}


private static List<Author> getAuthors() {
        //數據初始化
        Author author = new Author(1L,"蒙多",33,"一個從菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亞拉索",15,"狂風也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是這個世界在限制他的思維",null);
        Author author4 = new Author(3L,"易",14,"是這個世界在限制他的思維",null);

        //書籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的兩側是光明與黑暗","哲學,愛情",88,"用一把刀劃分了愛恨"));
        books1.add(new Book(2L,"一個人不能死在同一把刀下","個人成長,愛情",99,"講述如何從失敗中明悟真理"));

        books2.add(new Book(3L,"那風吹不到的地方","哲學",85,"帶你用思維去領略世界的盡頭"));
        books2.add(new Book(3L,"那風吹不到的地方","哲學",85,"帶你用思維去領略世界的盡頭"));
        books2.add(new Book(4L,"吹或不吹","愛情,個人傳記",56,"一個哲學家的戀愛觀注定很難把他所在的時代理解"));

        books3.add(new Book(5L,"你的劍就是我的劍","愛情",56,"無法想象一個武者能對他的伴侶這么的寬容"));
        books3.add(new Book(6L,"風與劍","個人傳記",100,"兩個哲學家靈魂和肉體的碰撞會激起怎么樣的火花呢?"));
        books3.add(new Book(6L,"風與劍","個人傳記",100,"兩個哲學家靈魂和肉體的碰撞會激起怎么樣的火花呢?"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4));
        return authorList;
    }

2.2 創建流的方式

  • 單列集合:集合對象.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();
    

2.3 中間操作

所謂中間操作,就是在流輸出最終結果前,進行的一系列操作。

filter

可以對流中的元素進行條件過濾,類似于SQL中的where符合過濾條件的才能繼續留在流中。

例如:打印所有姓名長度大于1的作家的姓名

List<Author> authors = getAuthors();
authors.stream()
    .filter(author -> author.getName().length()>1)
    .forEach(author -> System.out.println(author.getName()));

map

map 操作可以做轉換(或者說投影),類似 SQL 中的 select。可以把對流中的元素進行計算或轉換。

例如:打印所有作家的姓名

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

對流中重復的元素進行過濾,類似于SQL中的distinct

例如:打印所有作家的姓名,并且要求其中不能有重復元素。

List<Author> authors = getAuthors();
authors.stream()
    .distinct()
    .forEach(author -> System.out.println(author.getName()));

注意:distinct方法是依賴Object的equals方法來判斷是否是相同對象的。所以需要注意重寫equals方法。

sorted

可以對流中的元素進行排序。

例如:對流中的元素按照年齡進行降序排序,并且要求不能有重復的元素。

List<Author> authors = getAuthors();
//        對流中的元素按照年齡進行降序排序,并且要求不能有重復的元素。
authors.stream()
    .distinct()
    .sorted() // Author類需要實現Comparable接口
    .forEach(author -> System.out.println(author.getAge()));


authors.stream()
    .distinct()
    .sorted((o1, o2) -> o2.getAge()-o1.getAge())
    .forEach(author -> System.out.println(author.getAge()));

注意:如果調用空參的sorted()方法,需要流中的元素是實現了Comparable。

limit

可以設置流的最大長度,超出的部分將被拋棄。

例如:對流中的元素按照年齡進行降序排序,并且要求不能有重復的元素,然后打印其中年齡最大的兩個作家的姓名。

List<Author> authors = getAuthors();
authors.stream()
    .distinct()
    .sorted()
    .limit(2)
    .forEach(author -> System.out.println(author.getName()));

skip

跳過流中的前n個元素,返回剩下的元素

例如:打印除了年齡最大的作家外的其他作家,要求不能有重復元素,并且按照年齡降序排序。

List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .skip(1)
                .forEach(author -> System.out.println(author.getName()));

flatMap

map只能把一個對象轉換成另一個對象來作為流中的元素。而flatMap可以把一個對象轉換成多個對象作為流中的元素。

例一:打印所有書籍的名字。要求對重復的元素進行去重。

List<Author> authors = getAuthors();

        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book.getName()));

例二:打印現有數據的所有分類。要求對分類進行去重。不能出現這種格式:哲學,愛情

List<Author> authors = getAuthors();

authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .distinct()
    .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
    .distinct()
    .forEach(category-> System.out.println(category));

2.4 終結操作

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.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);

max&min

可以用來或者流中的最值。

例子:分別獲取這些作家的所出書籍的最高分和最低分并打印。

List<Author> authors = getAuthors();
Optional<Integer> max = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .map(book -> book.getScore())
    .max((score1, score2) -> score1 - score2);

Optional<Integer> min = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .map(book -> book.getScore())
    .min((score1, score2) -> score1 - score2);
System.out.println(max.get());
System.out.println(min.get());

collect

把當前流轉換成一個集合。

例如:獲取一個存放所有作者名字的List集合。

List<Author> authors = getAuthors();

// 獲取一個存放所有作者名字的List集合。
List<String> nameList = authors.stream()
    .map(author -> author.getName())
    .collect(Collectors.toList());
System.out.println(nameList);

// 獲取一個所有書名的Set集合。
Set<Book> books = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .collect(Collectors.toSet());

System.out.println(books);

// 獲取一個Map集合,map的key為作者名,value為List<Book>
Map<String, List<Book>> map = authors.stream()
    .distinct()
    .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));

System.out.println(map);

在這里插入圖片描述

查找與匹配

anyMatch

? 可以用來判斷是否有任意符合匹配條件的元素,結果為boolean類型。

例子:

? 判斷是否有年齡在29以上的作家

//        判斷是否有年齡在29以上的作家
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .anyMatch(author -> author.getAge() > 29);
        System.out.println(flag);

allMatch

? 可以用來判斷是否都符合匹配條件,結果為boolean類型。如果都符合結果為true,否則結果為false。

例子:

? 判斷是否所有的作家都是成年人

//        判斷是否所有的作家都是成年人
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .allMatch(author -> author.getAge() >= 18);
        System.out.println(flag);

noneMatch

? 可以判斷流中的元素是否都不符合匹配條件。如果都不符合結果為true,否則結果為false

例子:

? 判斷作家是否都沒有超過100歲的。

//        判斷作家是否都沒有超過100歲的。
        List<Author> authors = getAuthors();

        boolean b = authors.stream()
                .noneMatch(author -> author.getAge() > 100);

        System.out.println(b);

findAny

? 獲取流中的任意一個元素。該方法沒有辦法保證獲取的一定是流中的第一個元素。

例子:

? 獲取任意一個年齡大于18的作家,如果存在就輸出他的名字

//        獲取任意一個年齡大于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> first = authors.stream()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .findFirst();

        first.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求所有作者年齡的和

//        使用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求所有作者中年齡的最大值

//        使用reduce求所有作者中年齡的最大值
        List<Author> authors = getAuthors();
        Integer max = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);

        System.out.println(max);

? 使用reduce求所有作者中年齡的最小值

//        使用reduce求所有作者中年齡的最小值
        List<Author> authors = getAuthors();
        Integer min = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
        System.out.println(min);

? reduce一個參數的重載形式內部的計算

 	 boolean foundAny = false;
     T result = null;
     for (T element : this stream) {
         if (!foundAny) {
             foundAny = true;
             result = element;
         }
         else
             result = accumulator.apply(result, element);
     }
     return foundAny ? Optional.of(result) : Optional.empty();

? 如果用一個參數的重載方法去求最小值代碼如下:

//        使用reduce求所有作者中年齡的最小值
List<Author> authors = getAuthors();
Optional<Integer> minOptional = authors.stream()
    .map(author -> author.getAge())
    .reduce((result, element) -> result > element ? element : result);
minOptional.ifPresent(age-> System.out.println(age));

2.5 注意事項

  • 惰性求值(如果沒有終結操作,沒有中間操作是不會得到執行的)
  • 流是一次性的(一旦一個流對象經過一個終結操作后。這個流就不能再被使用)
  • 不會影響原數據(我們在流中可以多數據做很多處理。但是正常情況下是不會影響原來集合中的元素的。這往往也是我們期望的)

原文鏈接:https://blog.csdn.net/weixin_45483328/article/details/125687830

欄目分類
最近更新