匿名内部类、lambda、stream的使用

266 阅读32分钟

微信技术群:Day9884125

一 匿名内部类

   我们在针对多态的时候,一般是使用接口和实现类来使用的。但是当某一些实现类只使用一次的时候,就可以使用内部类来减少代码量。
   匿名内部类,主要是对接口的使用。它是对接口的一种实现。

具体代码如下

// 接口
package com.example.demo.testDemo;
public interface TestInterface {
    String getName(String name);
    String getResult();
}

// 实现类
package com.example.demo.testDemo;
public class MainTest {
    public static void main(String[] args) {
        MainTest mainTest = new MainTest();
        // 匿名内部类的使用
        String res = mainTest.test(new TestInterface() {
            @Override
            public String getName(String name) {
                String result = "";
                if (name.equals("zhangsan")) {
                    result = "符合";
                }
                return result;
            }
            //如果两个以上的话,可以只实现一个,也可以都实现
            @Override
            public String getResult() {
                return null;
            }
        });
        System.out.println("结果{}"+res);
    }

    public String test(TestInterface testInterface){
        String name = "zhangsan";
        return testInterface.getName(name);
    }
}

//输出结果:
结果{}符合

二 函数式编程

2.1 优点

  • 大数据量下处理集合效率高
  • 代码可读性高
  • 消灭嵌套

消灭嵌套的代码示例:

//下面是伪代码,参考逻辑就可以
//查询未成年作家的评分在七十岁以上的书籍,由于业务原因,作家和书籍可能会出现重复,需要去重
List<Book> bookList = new ArrayList<>();
// 去重书名
Set<Book> bookSet = new HashSet<>();
// 去重作者
Set<Author> authorSet = new HashSet<>();
for(Author author : authors){
    if(authorSet.add(author)){
        if(author.getAge() < 18){
            List<Book> books = author.getBooks();
            for(Book book : books){
                if(book.getScore()>70){
                    if(bookSet.add(book)){
                        bookList.add(book);
                    }
                }
            }
        }
    }
}
System.out.println(bookList);

// 用stream流的优化
List<Book> collect = author.stream()
                           .distinct()
                           .filter(author -> author.getAge()<18)
                           .map(author -> author.getBooks())
                           .flatMap(Collection::stream)
                           .filter(book -> book.getScore()>70)
                           .distinct()
                           .collect(Collections.toList());
System.out.println(collect);

2.2 函数式编程思想

2.2.1 概念

   面向对象思想需要关注用什么对象完成什么事。而函数式编程思想关注数据进行了什么操作

2.2.2 优点

  • 代码简洁,开发快速
  • 接近自然语言,易于理解
  • 易于“并发编程”

2.3 lambda表达式

2.3.1 概述

   lambda是jdk8的语法,它可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什么对象,而是关注对数据做了什么操作。

2.3.2 基本格式

(参数列表) -> {代码}

2.3.2.1 代码示例:

   lambda可以使用idea的alt+回车,注意光标要停在右小括号后面,可以lambda和匿名内部类之间的互相转化

例一
package com.example.demo.testDemo;

public class LambdaTest {
    public static void main(String[] args) {
        // 创建线程并启动时,使用匿名内部类的写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类的写法");
            }
        }).start();
        
        /**
         * lambda写法
         * 函数式编程:
         * 不关注哪个对象,不关注类名和方法名。只关注操作什么数据做了什么事
         * 所以下面类名和方法名都没有,只保留小括号和大括号,小括号和大括号之间加->就可以了,结果如下
         */
        new Thread(() -> {
                System.out.println("lambda的写法");
        }).start();
    }
}

// 输出结果为:
匿名内部类的写法
lambda的写法
例二
// 匿名内部类的使用示例
package com.example.demo.testDemo;
import java.util.function.IntBinaryOperator;
public class LambdaTest {
    public static void main(String[] args) {
        /**
         * IntBinaryOperator这个东西不知道,点进去是一个接口
         * 并且接口中只有一个抽象方法,所以可以选择使用匿名内部类的写法,
         * 去传入它的实现类对象
         */
        int i = calculateNum(new IntBinaryOperator() {
            @Override
            public int applyAsInt(int left, int right) {
                return left + right;
            }
        });
        System.out.println(i);
    }

    public static int calculateNum(IntBinaryOperator operator){
        int a = 10;
        int b = 20;
        return operator.applyAsInt(a, b);
    }
}

// lambda表达式的使用示例
package com.example.demo.testDemo;
import java.util.function.IntBinaryOperator;
public class LambdaTest {
    public static void main(String[] args) {
        /**
         * 函数式编程:
         * 只关注函数列表和方法体
         */
        int i = calculateNum((int left, int right) ->{
            return left + right;
        });
        System.out.println(i);
    }

    public static int calculateNum(IntBinaryOperator operator){
        int a = 10;
        int b = 20;
        return operator.applyAsInt(a, b);
    }
}
例三
// 匿名内部类的写法示例
package com.example.demo.testDemo;
import java.util.function.IntBinaryOperator;
import java.util.function.IntPredicate;
public class LambdaTest {
    public static void main(String[] args) {
        /**
         * 匿名内部类的写法
         * 虽然没见过IntPredicate,进去看一下,里面有一个抽象方法test
         * 只需要关注这个方法的入参类型和返回结果类型就可以了
         */
        printNum(new IntPredicate() {
            @Override
            public boolean test(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);
            }
        }
    }
}

// lambda表达式的写法示例
package com.example.demo.testDemo;

import java.util.function.IntBinaryOperator;
import java.util.function.IntPredicate;

public class LambdaTest {
    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);
            }
        }
    }
}

// 输出结果
2
4
6
8
10
例四
// 匿名内部类的写法示例
package com.example.demo.testDemo;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.IntPredicate;
public class LambdaTest {
    public static void main(String[] args) {
        /**
         * 匿名内部类写法
         * 不了解Function,点进去,看到apply是一个抽象方法,
         * 入参是T,返回结果是R
         */
        Integer i = typeConver(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.valueOf(s);
            }
        });
        System.out.println(i);
    }

    public static <R> R typeConver(Function<String, R> function){
        String str = "12345";
        R result = function.apply(str);
        return result;
    }
}

// lambda表达式的写法示例
package com.example.demo.testDemo;
import java.util.function.Function;
import java.util.function.IntBinaryOperator;
import java.util.function.IntPredicate;
public class LambdaTest {
    public static void main(String[] args) {
        /**
         * 函数式编程:
         * 只关注函数列表和方法体
         */
        Integer i = typeConver((String s) -> {
            return Integer.valueOf(s);
        });
        System.out.println(i);
    }

    public static <R> R typeConver(Function<String, R> function){
        String str = "12345";
        R result = function.apply(str);
        return result;
    }
}

// 输出结果
12345
例五
// 匿名内部类的写法
package com.example.demo.testDemo;
import java.util.function.IntConsumer;
public class LambdaTest {
    public static void main(String[] args) {
        /**
         * 匿名内部类写法
         * 不了解IntConsumer,点进去,看到accept是一个抽象方法,
         * 入参是int,返回结果是空
         */
        forearchArr(new IntConsumer() {
            @Override
            public void accept(int value) {
                System.out.println(value);
            }
        });
    }

    public static void forearchArr(IntConsumer consumer){
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        for(int i : arr){
            consumer.accept(i);
        }
    }
}

// lambda表达式的写法
package com.example.demo.testDemo;
import java.util.function.IntConsumer;
public class LambdaTest {
    public static void main(String[] args) {
        /**
         * 函数式编程:
         * 只关注函数列表和方法体
         */
        forearchArr((int value) -> {
            System.out.println(value);
        });
    }

    public static void forearchArr(IntConsumer consumer){
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        for(int i : arr){
            consumer.accept(i);
        }
    }
}

// 输出结果
1
2
3
4
5
6
7
8
9
10

2.3.3 省略规则

  • 方法类型可以省略
  • 方法题只有一行代码时大括号retrun和唯一一句代码的分号可以省略
  • 方法只有一个参数时小括号可以省略
  • 以上方法都记不住也可以省略不记
// lambda表达式写法
package com.example.demo.testDemo;
import java.util.function.IntConsumer;
public class LambdaTest {
    public static void main(String[] args) {
        /**
         * lambda表达式不省略的写法
         */
        forearchArr((int value) -> {
            System.out.println(value);
        });
        
        /**
         * lambda表达式省略的写法
         * 方法类型可以省略
         * 方法题只有一行代码时大括号retrun和唯一一句代码的分号可以省略
         * 方法只有一个参数时小括号可以省略
         * 以上方法都记不住也可以省略不记
         */
        forearchArr(value -> System.out.println(value));
        
    }

    public static void forearchArr(IntConsumer consumer){
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        for(int i : arr){
            consumer.accept(i);
        }
    }
}

2.4 Stream流

2.4.1 概述

   java8的Stream使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合或数组进行链状流式的操作。可以更方便的让我们对集合或数组的操作。 2.4.2 案例准备

package com.example.demo.streamTest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Objects;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Author {
    private Long id;
    // 姓名
    private String name;
    // 年龄
    private Integer age;
    // 简介
    private String intro;
    // 作品
    private List<Book> books;

    // 重写equals和hashCode方法,用于后面的去重
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Author author = (Author) o;
        return Objects.equals(id, author.id) &&
                Objects.equals(name, author.name) &&
                Objects.equals(age, author.age) &&
                Objects.equals(intro, author.intro) &&
                Objects.equals(books, author.books);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, age, intro, books);
    }
}
// ==============================================================================
package com.example.demo.streamTest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Objects;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    private Long id;
    // 书名
    private String name;
    // 分类
    private String category;
    // 评分
    private Integer score;
    // 简介
    private String intro;

    // 重写equals和hashCode方法,用于后面的去重
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return Objects.equals(id, book.id) &&
                Objects.equals(name, book.name) &&
                Objects.equals(category, book.category) &&
                Objects.equals(score, book.score) &&
                Objects.equals(intro, book.intro);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, category, score, intro);
    }
}
//=================================================================================
package com.example.demo.streamTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        System.out.println(authors);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "lisi", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(4L, "wangwu", 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.4.2 快速入门

2.4.2.1 需求

   我们可以调用getAuthors方法获取到作家的集合。现在需要打印所有年龄小于18的作家的名字,并且去重。

2.4.2.2 实现

   注意:流的操作要有终结方法,才会起效果,否则不会执行。

// 匿名内部类的写法
package com.example.demo.streamTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()//把集合转化成stream流
                .distinct()//去重
                .filter(new Predicate<Author>() {//如果结果小于18会被留到stream流里面
                    @Override
                    public boolean test(Author author) {
                        return author.getAge()<18;
                    }
                })
                .forEach(new Consumer<Author>() {
                    @Override
                    public void accept(Author author) {
                        System.out.println(author);
                    }
                });
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "lisi", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

// lambda表达式的写法
package com.example.demo.streamTest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        //如果结果小于18会被留到stream流里面
        authors.stream()//把集合转化成stream流
                .distinct()//去重
                .filter(author -> author.getAge()<18)
                .forEach(author -> System.out.println(author));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "lisi", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

// 输出结果:
Author(id=2, name=lisi, age=15, intro=流浪猫的快乐, books=[Book(id=3, name=流浪猫的爱情, category=心理学,爱情, score=85, intro=美好的日子), Book(id=3, name=流浪猫的爱情, category=心理学,爱情, score=85, intro=美好的日子), Book(id=4, name=流浪猫的成长, category=心理学,哲学, score=56, intro=猫的世界)])
Author(id=3, name=wangwu, age=14, intro=猪八戒的烦恼, books=[Book(id=5, name=猪八戒的工作, category=哲学,社会学, score=56, intro=摸鱼的日子), Book(id=6, name=猪八戒的爱情, category=心理学,爱情, score=100, intro=美好愿望), Book(id=6, name=猪八戒的爱情, category=心理学,爱情, score=100, intro=美好愿望)])

debug对流的调试 image.png

2.4.3 常规操作

2.4.3.1 创建流

2.4.3.1.1 单列集合

集合对象.stream()

List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();
2.4.3.1.2 数组

Arrays.stream(数组)或者使用Stream.of来创建

Integer[] arr = {1, 2, 3, 4, 5};
Stream<Integer> stream1 = Arrays.stream(arr);
Stream<Integer> arr1 = Stream.of(arr);
2.4.3.1.3 双列集合

转换成单列集合再创建

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.4.4 中间操作

2.4.4.1 filter

   可以对流中的元素进行过滤,符合过滤条件的才能继续留在流中。
例如:
   打印所有姓名长度大于1的作家的姓名

// 匿名内部类的使用
package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .filter(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getName().length()>1;
                    }
                })
                .forEach(new Consumer<Author>() {
                    @Override
                    public void accept(Author author) {
                        System.out.println(author.getName());
                    }
                });
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

// lambda表达式用法
package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .filter(author -> author.getName().length()>1)
                .forEach(author -> System.out.println(author.getName()));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

// 输出结果
zhangsan
wangwu
wangwu

2.4.4.2 map

   可以把对流中的元素进行计算或转换
例如
   打印所有作家的姓名

// 匿名内部类的使用
package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName();
                    }
                })
                .forEach(new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        System.out.println(s);
                    }
                });
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

//==================================================================================================
// lambda的使用
package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getName())
                .forEach(s -> System.out.println(s));

    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.4.3 distinct

   可以去重流中的重复元素
例如
   打印所有作家的姓名,并且不能有重复元素

// 匿名内部类的写法
package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .forEach(new Consumer<Author>() {
                    @Override
                    public void accept(Author author) {
                        System.out.println(author.getName());
                    }
                });
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

//====================================================================================================
// lambda的写法
package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .forEach(author -> System.out.println(author.getName()));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

   注意distinct方法是依赖Object的equals方法来判断是否相同对象的。所以需要注意重写equals方法。

2.4.4.4 sorted

   可以对流中的元素进行排序
例如
   对流中的元素进行降序排序,并且不能有重复的数据

// 实体类  stream使用sort方法,实体类需要实现Comparable类重写compareTo方法
package com.example.demo.streamTest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Objects;

@Data
@NoArgsConstructor
@AllArgsConstructor
// 需要比较的时候,实现Comparable
public class Author implements Comparable<Author>{
    private Long id;
    // 姓名
    private String name;
    // 年龄
    private Integer age;
    // 简介
    private String intro;
    // 作品
    private List<Book> books;

    // 重写equals和hashCode方法,用于后面的去重
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Author author = (Author) o;
        return Objects.equals(id, author.id) &&
                Objects.equals(name, author.name) &&
                Objects.equals(age, author.age) &&
                Objects.equals(intro, author.intro) &&
                Objects.equals(books, author.books);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, age, intro, books);
    }

    @Override
    public int compareTo(Author o) {
        // 如果前面的大是正的
        return this.getAge()-o.getAge();
    }
}

// 测试类  调用无参的sort方法
package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .forEach(author -> System.out.println(author.getAge()));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}
//=======================================================================================================
// 调用有参的sort方法
package com.example.demo.streamTest;
import java.util.*;

public class StreamDataTest {

    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted(new Comparator<Author>() {
                    @Override
                    public int compare(Author o1, Author o2) {
                        return o2.getAge()-o1.getAge();
                    }
                })
                .forEach(author -> System.out.println(author.getAge()));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

   注意调用空参的sorted方法,需要流中的元素实现Comparable

2.4.4.5 limit

   可以设置流的最大长度,超出的部分将被抛弃
例如:
   对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名。

package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
public class StreamDataTest {
    public static void main(String[] args) {
        // 匿名内部类的写法
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .limit(2)
                .forEach(new Consumer<Author>(){
                    @Override
                    public void accept(Author author) {
                        System.out.println(author.getName());
                    }
                });
                
        // lambda表达式写法
        /**
          *  List<Author> authors = getAuthors();
          *  authors.stream()
          *         .distinct()
          *         .sorted()
          *         .limit(2)
          *         .forEach(author -> System.out.println(author.getName()));
          */
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.4.7 skip

   跳过流中的前n个元素,返回剩下的元素
例如:
   打印除了年龄最大的作家外的其他作家,要求不能有重复元素,并且按照年龄降序排序。

package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .skip(1)
                .forEach(author -> System.out.println(author.getName()));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.4.8 flatMap

   map只能把一个对象转换成另一个对象来作为流中的元素,而flatMap可以把一个对象转换成多个对象作为流中的元素
例一:
   打印所有书籍的名字,要求对重复的元素进行去重。

package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(new Function<Author, Stream<Book>>() {
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                })
                .distinct()
                .forEach(new Consumer<Book>() {
                    @Override
                    public void accept(Book book) {
                        System.out.println(book.getName());
                    }
                });
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

例二:
   打印现有书籍的所有分类。要求对分类进行去重,不能出现这种格式:哲学,爱情

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        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));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5 终结操作

2.4.5.1 forEach

   对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历的元素进行什么具体操作
例子:
输出所有作家的名字

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getName())
                .distinct()
                .forEach(name -> System.out.println(name));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.2 count

   可以用来获取当前流中元素的个数
例子:
打印这些作家的所出书籍的数目,注意删除重复元素

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        long count = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.3 max&min

   可以用来或者流中的最值
例子:
分别获取这些作家的所出书籍的最高分和最低分并打印。

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .max(new Comparator<Integer>() {
                    @Override
                    public int compare(Integer score1, Integer score2) {
                        return score1 - score2;
                    }
                });
        System.out.println(max.get());
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.4 collect

   把当前流转换成一个集合
例子:
获取一个存放所有作者名字的List集合

package com.example.demo.streamTest;
import java.util.*;
import java.util.stream.Collectors;

public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        List<String> nameList = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(nameList);        
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

获取一个所有书名的set集合

package com.example.demo.streamTest;
import java.util.*;
import java.util.stream.Collectors;

public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Set<Book> books = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .collect(Collectors.toSet());
        System.out.println(books);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

获取一个map集合,map的key为作者名,value为List

package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Map<String, List<Book>> map = authors.stream()
                .distinct()
                .collect(Collectors.toMap(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName();
                    }
                }, new Function<Author, List<Book>>() {
                    @Override
                    public List<Book> apply(Author author) {
                        return author.getBooks();
                    }
                }));
        System.out.println(map);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.5 查找与匹配

2.4.5.5.1 anyMatch

   可以用来判断是否有任意符合匹配条件的元素,结果为boolean类型.
例子:
判断是否有年龄在29以上的作家

package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Predicate;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .anyMatch(new Predicate<Author>() {
                    @Override
                    public boolean test(Author author) {
                        return author.getAge() > 29;
                    }
                });
        System.out.println(flag);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.5.2 allMatch

   可以用来判断是否都符合匹配条件,结果为boolean类型,如果都符合结果为true,否则结果为false。
例子:
判断是否所有的作家都是成年人

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .allMatch(author -> author.getAge()>=18);
        System.out.println(flag);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.5.3 noneMatch

   可以判断流中的元素是否都不符合怕匹配条件。如果都不符合结果为true,否则结果为false
例子:
判断作家是否都没有超过100岁的

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .noneMatch(author -> author.getAge()>100);
        System.out.println(flag);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.5.4 findAny

   获取流中的任意一个元素,该方法没有办法保证获取的一定是流中的第一个元素
例子:
获取任意一个年龄大于18的作家,如果存在就输出它的名字

package com.example.demo.streamTest;
import java.util.*;
import java.util.function.Consumer;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Optional<Author> author = authors.stream()
                .filter(author1 -> author1.getAge()>18)
                .findAny();
        author.ifPresent(new Consumer<Author>() {
            @Override
            public void accept(Author author) {
                System.out.println(author.getName());
            }
        });
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.5.5 findFirst

   获取流中的第一个元素
例子:
获取一个年龄最小的作家,并输出它的姓名

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Optional<Author> first = authors.stream()
                .sorted(new Comparator<Author>() {
                    @Override
                    public int compare(Author o1, Author o2) {
                        return o2.getAge() - o1.getAge();
                    }
                })
                .findFirst();
        first.ifPresent(author -> System.out.println(author.getName()));
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.5.6 reduce归并

   对流中的数据按照你制定的计算方式计算出一个结果
   reduce的作用是把stream中的元素给组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和在初始化值得基础上进行计算,计算结果再和后面的元素计算。
   他内部的计算方式如下:

T result = identity;
for(T element : this stream)
    result = accumulator.apply(result, element)
return result;

   其中identity就是我们可以通过方法参数传入的初始值,accumulator的apply具体进行什么计算也是我们通过方法参数来确定的。
例子:
使用reduce求所有作者年龄的和。

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Integer sum = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce(0, (result, element) -> result+element);
        System.out.println(sum);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

使用reduce求所有作者中年龄的最大值

package com.example.demo.streamTest;
import java.util.*;
import java.util.function.BinaryOperator;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Integer max = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result<element?element:result;
                    }
                });
        System.out.println(max);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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;
    }
}

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

package com.example.demo.streamTest;
import java.util.*;
import java.util.function.BinaryOperator;
public class StreamDataTest {
    public static void main(String[] args) {
        List<Author> authors = getAuthors();
        Integer min = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result>element?element:result;
                    }
                });
        System.out.println(min);
    }

    private static List<Author> getAuthors(){
        //数据初始化
        Author author = new Author(1L, "zhangsan", 33, "一个小白的生活", null);
        Author author2 = new Author(2L, "白", 15, "流浪猫的快乐", null);
        Author author3 = new Author(3L, "wangwu", 14, "猪八戒的烦恼", null);
        Author author4 = new Author(3L, "wangwu", 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.4.6 注意事项

  • 惰性求值(如果没有终结操作,没有中间操作时不会得到执行的)
  • 流是一次性的(一旦一个流对象经过一个终结操作后。这个流就不能再被使用)
  • 不会影响原数据(我们在流中可以多数据做很多处理。但是正常情况下是不会影响原来集合中的元素的。这往往也是我们期望的。)

2.5 Optional

2.5.1 概述

   我们在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断。
例如:

Author author = new Author();
if(author != null){
    System.out.println(author.getName());
}

   尤其是对象中的属性,还是一个对象的情况下。这种判断会更多。
   而过多的判断语句会让我们的代码显得臃肿不堪。
   所以在JDK8中引入了Optional,养成使用Optional的习惯后你可以写出更优雅的代码来避免空指针异常。
   并且在很多函数式编程相关的API中也都用到了Optional,如果不会使用Optional也会对函数式编程的学习造成影响。

2.5.2 使用

2.5.2.1 创建对象

   Optional就好像是包装类,可以把我们的具体数据封装成Optional对象内部。然后我们去使用Optional中封装好的方法操作封装进去的数据就可以非常优雅的避免空指针异常。
   我们一般使用Optional的静态方法ofNullable来把数据封装成一个Optional对象。无论传入的参数是否为null都不会出现问题。

// 这是最简单的使用Optional
package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        Author author = getAuthor();
        // 用ofNullable创建Optional对象
        Optional<Author> authorOptional = Optional.ofNullable(author);
        // 输出作者author1的名字
        authorOptional.ifPresent(author1 -> System.out.println(author1.getName()));
    }

    private static Author getAuthor(){
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", null);
        return null;
    }
}
    
// 上面使用Optional看着也比较复杂,可以进行下面的改造
package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        Optional<Author> author = getAuthor();
        // 输出作者author1的名字
        author.ifPresent(author1 -> System.out.println(author1.getName()));
    }

    private static Optional<Author> getAuthor(){
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", null);
        return Optional.ofNullable(author);
    }
}

   你可能会觉得还要加一行代码来封装数据比较麻烦。但是如果改造下getAuthor方法,让其的返回值就是封装好的Optional的话,我们在使用时就会方便很多。
   而且在实际开发中我们的数据很多是从数据库获取的。mybatis从3.5版本可以也已经支持Optional了。我们可以直接把dao方法的返回值类型定义成Optional类型。mybatis会自己把数据封装成Optional对象返回。封装的过程也不需要我们自己操作。
   如果你确定一个对象不是空的则可以使用Optional的静态方法of来把数据封装成Optional对象。

package com.example.demo.streamTest;
import java.util.*;
public class StreamDataTest {
    public static void main(String[] args) {
        Author author = getAuthor();
        // 用ofNullable创建Optional对象,author对象不能为空
        Optional<Author> authorOptional = Optional.of(author);
        // 输出作者author1的名字
        authorOptional.ifPresent(author1 -> System.out.println(author1.getName()));
    }

    private static Author getAuthor(){
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", null);
        return null;
    }
}

   但是一定要注意,如果使用of的时候传入的参数必须不为null。(尝试下传入null会出现什么结果)
   如果一个方法的返回类型是Optional类型。而如果我们经判断发现某次计算得到的返回值为null,这个时候就需要把null封装成Optional对象返回。这时则可以使用Optional的静态方法empty来进行封装。

Optional.empty(); 

   所以最后你觉得哪种方式会更便宜呢?

2.5.2.2 安全消费值

   我们获取到一个Optional对象后肯定需要对其中的数据进行使用。这时候我们可以使用其ifPresent方法对来消费其中的值。
   这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码。这样使用起来就更加安全了。
   例如,以下写法就优雅的避免了空指针异常

// 将author对象封装到Optional中
Optional<Author> author = Optional.ofNullable(getAuthor());
// 输出作者的名字
author.ifPresent(author1 -> System.out.println(author1.getName()));

2.5.2.3 获取值

   如果我们想获取值自己进行处理可以使用get方法获取,但是不推荐。因为当Optional内部的数据为空的时候会出现异常。

package com.example.demo.testDemo;

import com.example.demo.streamTest.Author;

import java.util.Optional;

public class OptionalDemo {
    public static void main(String[] args) {
        Optional<Author> author = getAuthor();
        // get获取optional中的内容,当里面的内容为null时,会报错。所以不推荐使用get方法
        Author aut = author.get();

    }

    private static Optional<Author> getAuthor(){
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", null);
        return null;
    }
}

2.5.2.4 安全获取值

   如果我们期望安全的获取值。我们不推荐使用get方法,而是使用optional提供的以下方法。

  • orElseGet
       获取数据并且设置数据为空时的默认值,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建对象作为默认值返回。
package com.example.demo.testDemo;

import com.example.demo.streamTest.Author;

import java.util.Optional;
import java.util.function.Supplier;

public class OptionalDemo {
    public static void main(String[] args) {
        Optional<Author> author = getAuthor();
        Author author1 = author.orElseGet(new Supplier<Author>() {
            @Override
            public Author get() {
                return new Author();
            }
        });
        System.out.println(author1.getName());

    }

    private static Optional<Author> getAuthor(){
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", null);
        return Optional.ofNullable(author);
    }
}
  • orElseThrow
       获取数据,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建异常抛出。
package com.example.demo.testDemo;
import com.example.demo.streamTest.Author;
import java.util.Optional;
import java.util.function.Supplier;

public class OptionalDemo {
    public static void main(String[] args) {
        Optional<Author> author = getAuthor();
        try {
            Author auth1 = author.orElseThrow(new Supplier<Throwable>() {
                @Override
                public Throwable get() {
                    return new RuntimeException("数据为null");
                }
            });
            System.out.println(auth1);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    private static Optional<Author> getAuthor(){
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", null);
        return Optional.ofNullable(null);
    }
}   

2.5.2.5 过滤

   我们可以使用filter方法对数据进行过滤。如果原本是有数据的,但是不符合判断,也会变成一个无数的Optional对象。

package com.example.demo.testDemo;
import com.example.demo.streamTest.Author;
import java.util.Optional;
import java.util.function.Supplier;
public class OptionalDemo {
    public static void main(String[] args) {
        Optional<Author> author = getAuthor();
        // 大于18并且不为空
        Optional<Author> optional = author.filter(author1 -> author1.getAge()> 18);
        System.out.println(optional.orElseGet(new Supplier<Author>() {
            @Override
            public Author get() {
                return new Author();
            }
        }));
    }

    private static Optional<Author> getAuthor(){
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", null);
        return Optional.ofNullable(author);
    }
}

2.5.2.6 判断

   我们可以使用isPresent方法进行是否存在数据的判断。如果为空返回值为false,如果不为空,返回值为true。但是这种方式并不能体现Optional的好处,更推荐使用isPresent方法。

package com.example.demo.testDemo;
import com.example.demo.streamTest.Author;
import java.util.Optional;
public class OptionalDemo {
    public static void main(String[] args) {
        Optional<Author> author = getAuthor();
        if(author.isPresent()){
            // 这里可以使用get了,因为使用了判断
            System.out.println(author.get().getName());
        }
    }

    private static Optional<Author> getAuthor(){
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", null);
        return Optional.ofNullable(author);
    }
}

2.5.2.7 数据转换

   Optional还提供了map可以让我们的对数据进行转换,并且转换得到的数据还是被Optional包装好的,保证了我们的使用安全。例如我们想获取作家的数据集合。

package com.example.demo.testDemo;
import com.example.demo.streamTest.Author;
import com.example.demo.streamTest.Book;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class OptionalDemo {
    public static void main(String[] args) {
        Optional<Author> author = getAuthor();
        Optional<List<Book>> books1 = author.map(author1 -> author1.getBooks());
        books1.ifPresent(books -> System.out.println(books));
    }

    private static Optional<Author> getAuthor(){
        List<Book> list = new ArrayList<>();
        list.add(new Book(1L, "李白", "诗", 70, "还行"));
        list.add(new Book(2L, "杜甫", "词", 60, "可以"));
        Author author = new Author(1L, "小灰", 33, "一只胖胖的猫头鹰", list);
        return Optional.ofNullable(author);
    }
}

2.6 函数式接口

2.6.1 概述

   只有一个抽象方法的接口我们称之为函数接口。
   JDK的函数式接口都加上了@Functionallnterface注解进行标识。但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。

2.6.2 常见函数式接口

2.6.2.1 Consumer消费接口

   根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数进行消费

@FunctionalInterface
public interface Consumer<T>{
    void accept(T t);

2.6.2.2 Function计算转换接口

   根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数计算或转换,把结果返回。

@FunctionalInterface
public interface Function<T, R>{
    R apply(T t);

2.6.2.3 Predicate判断接口

   根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中对传入的参数条件判断,返回判断结果。

@FunctionalInterface
public interface Predicate<T>{
    boolean test(T t);

2.6.2.4 Supplier生产型接口

   根据其中抽象方法的参数列表和返回值类型知道,我们可以在方法中创建对象,把创建好的对象返回。

@FunctionalInterface
public interface Supplier<T>{
    T get();

2.7 函数式常用默认方法

2.7.1 and

   我们在使用Predicate接口时候可能需要进行判断条件的拼接。而and方法相当于是使用&&来拼接两个判断条件
   例如:
   打印作家中年龄大于17并且姓名的长度大于1的作家。

List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
authorStream.filter(new Predicate<Author>(){
    @Override
    public boolean test(Author author){
        return author.getAge()>17;
    }
}.and(new Predicate<>(){
    @Override
    public boolean test(Author author){
        return author.getName().length()>1;
    }
})).forEach(author -> System.out.println(author));

2.7.2 or

   我们在使用Predicate接口时候可能需要进行判断条件的拼接。而or方法相当于是使用||来拼接两个判断条件。
   例如:
   打印作家中年龄大于17或者姓名的长度小于2的作家。

List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
authorStream.filter(new Predicate<Author>(){
    @Override
    public boolean test(Author author){
        return author.getAge()>17;
    }
}.or(new Predicate<>(){
    @Override
    public boolean test(Author author){
        return author.getName().length()<2;
    }
})).forEach(author -> System.out.println(author));

2.7.3 negate

   Predicate接口中的方法。negate方法相当于是在判断添加前面加了个!表示取反。
   例如:
   打印作家中年龄不大于17的作家。

List<Author> authors = getAuthors();
authors.stream().filter(new Predicate<Author>(){
    @Override
    public boolean test(Author author){
        return author.getAge()>17;
    }
}.negate()).forEach(author -> System.out.println(author));

2.8 方法引用

   我们在使用lambda时,如果方法体中只有一个方法的调用的话(包括构造函数),我们可以用方法引用进一步简化代码。

2.8.1 推荐用法

   我们在使用lambda时不需要考虑什么时候用方法引用,用哪种方法引用,方法引用的格式是什么。我们需要在写完lambda方法发现方法体只有一行代码,并且是方法的调用时使用快捷键尝试是否能够转换成方法引用即可。
   当我们方法引用使用的多了慢慢的也可以直接写出方法引用。

2.8.2 基本格式

   类名或者对象名::方法名

2.8.3 语法详解(了解)

2.8.3.1 引用类的静态方法

   其实就是引用类的静态方法
格式:

类名::方法名

使用前提:
   如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的静态方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,这个时候我们就可以引用类的静态方法。
例如:
   如下代码就可以用方法引用进行简化。

List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
authorStream.map(author -> author.getAge())
    .map(age -> String.valueOf(age));

   注意,如果我们所重写的方法是没有参数的,调用的方法也是没有参数的也相当于符合以上规则。
   优化后如下:

List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
authorStream.map(author -> author.getAge())
    .map(String::valueOf);

2.8.3.2 引用对象的实例方法

格式:

对象名::方法名

使用前提:
   如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个对象的成员方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用对象的实例方法。
例如:

List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName())
    .forEach(name -> sb.append(name));

优化后:

List<Author> authors = getAuthors();
Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName())
    .forEach(sb::append);

2.8.3.3 引用类的实例方法

格式:

类名::方法名

使用前提:
   如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法,并且我们要把重写的抽象方法中剩余的所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用类的实例方法。
例如:

interface UseString{
    String use(String str, int start, int length);
}
public static String subAuthorName(String str, UseString useString){
    int start = 0;
    int length = 1;
    return useString.use(str, start, length);
}
public static void main(String[] args){
    subAuthorName("三更草堂", new UseString(){
        @Override
        public String use(String str, int start, int length){
            return str.substring(start, length);
        }
    });
}

优化后如下:

interface UseString{
    String use(String str, int start, int length);
}
public static String subAuthorName(String str, UseString useString){
    int start = 0;
    int length = 1;
    return useString.use(str, start, length);
}
public static void main(String[] args){
    subAuthorName("三更草堂", String::substring);
}

2.8.3.4 构造器的引用

   如果方法体中的一行代码是构造器的话就可以使用构造器引用了。
格式:

类名::new

使用前提
   如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的构造方法,并且我们把要重写的抽象方法中的所有的参数都按照顺序传入了这个构造方法中,这个时候我们就可以引用构造器。
例如:

List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getName())
    .map(name -> new StringBuilder(name))
    .map(sb -> sb.append("-三更").toString())
    .forEach(str -> System.out.println(str));

优化后:

List<Author> authors = getAuthors();
authors.stream()
    .map(author -> author.getName())
    .map(StringBuilder::new)
    .map(sb -> sb.append("-三更").toString())
    .forEach(System.out::println);

2.9 高级用法

2.9.1 Stream基本数据类型优化

   我们之前用到的很多Stream的方法由于都使用了泛型。所以涉及到的参数和返回值都是引用数据类型。
   即使我们操作的是整数小数,但是实际用的都是它们的包装类。jdk5中引入的自动装箱和自动拆箱让我们在使用对应的包装类时就好像使用基本数据类型一样方便。但是你一定要知道装箱和拆箱肯定是要消耗时间的。虽然这个时间消耗很小。但是在大量的数据不断的重复装箱拆箱的时候,你就不能无视这个时间损耗了。
   所以为了让我们能够对这部分的时间消耗进行优化。Stream还提供了很多专门针对基本数据类型的方法。
   例如mapToInt、mapToLong、mapToDouble、flatMapToInt、flatMapToDouble等。

private static void test27(){
    List<Author> authors = getAuthors();
    authors.stream()
        .map(author -> author.getAge())
        .map(age -> age + 10)
        .filter(age -> age>18)
        .map(age -> age + 2)
        .forEach(System.out::println);
}

优化后:

private static void test27(){
    List<Author> authors = getAuthors();
    authors.stream()
        .mapToInt(author -> author.getAge())
        .map(age -> age + 10)
        .filter(age -> age>18)
        .map(age -> age + 2)
        .forEach(System.out::println);
}

2.9.2 并行流

   当流中有大量元素时,我们可以使用并行流去提高操作的效率。其实并行流就是把任务分配给多个线程去完成。如果我们自己去用代码实现的话其实会非常的复杂,并且要求你对并发编程有足够的理解和认识。而如果我们使用Stream的话,我们只需要修改一个方法的调用就可以使用并行流来帮我们实现,从而提高效率。
   parallel方法可以把串行流转换成并行流

// 串行流的实现
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = stream.filter(num -> num>5)
    .reduce((result, ele) -> result+ele)
    .get();
System.out.println(sum);
    
// 并行流的实现
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = stream.parallel()
    .filter(num -> num>5)
    .reduce((result, ele) -> result+ele)
    .get();
System.out.println(sum);

// 查看并行流各个线程的情况
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = stream.parallel()
    .peek(new Consumer<Integer>(){
        @Override
        public void accept(Integer num){
            System.out.println(sum + Thread.currentThread().getName());
        }
    })
    .filter(num -> num>5)
    .reduce((result, ele) -> result+ele)
    .get();
System.out.println(sum);

   也可以通过paralleStream直接获取并行流对象。

List<Author> authors = getAuthors();
authors.parallelStream()
    .map(author -> author.getAge())
    .map(age -> age + 10)
    .filter(age -> age >18)
    .map(age -> age + 2)
    .forEach(System.out::println)