Stream流

本文详细介绍了Java 8的Stream API,包括其概述、使用准备、快速入门示例和常用操作。通过实例展示了如何创建流、过滤、映射、去重、排序、聚合等操作,以及注意事项,帮助读者掌握Stream API的高效数据处理能力。
摘要由CSDN通过智能技术生成

Stream流

3.1 概述

Stream是Java8 API的新成员,它允许以声明性方式处理数据集合 。

特点:

  • 代码简洁函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环。
  • 多核友好:Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下方法。

3.2准备阶段

book.java(书籍类)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author 尹稳健~
 * @version 1.0
 * @time 2022/8/25
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    private Long id;
    private String name;
    private String category;
    private Integer score;
    private String intro;
}

author.java (作者类)

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
 * @author 尹稳健~
 * @version 1.0
 * @time 2022/8/25
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Author {
    private Long id;
    private String name;
    private Integer age;
    private String intro;
    private List<Book> books;
}

生成简单数据的方法

private static List<Author> getAuthors(){
    Author author1 = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);
    Author author2 = new Author(2L, "亚索", 15, "狂风也追逐不上他的思考速度", null);
    Author author3 = new Author(3L, "易", 14, "是这个世界限制了他的思维", null);
    Author author4 = new Author(4L, "易", 14, "是这个世界限制了他的思维", null);

    List<Book> book1 = new ArrayList<>();
    List<Book> book2 = new ArrayList<>();
    List<Book> book3 = new ArrayList<>();

    book1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀划分爱恨"));
    book1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述如何从失败到成功"));

    book2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
    book2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
    book2.add(new Book(4L,"吹或不吹","个人传记,爱情",56,"一个哲学家的恋爱观注定很难把他"));

    book3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"无法想象一个武者能对他的伴侣"));
    book3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家的灵魂和肉体的碰撞会激起怎么样的"));
    book3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家的灵魂和肉体的碰撞会激起怎么样的"));

    author1.setBooks(book1);
    author2.setBooks(book2);
    author3.setBooks(book3);
    author4.setBooks(book3);

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

3.3快速入门

3.3.1 需求

从getAuthors方法获取到的集合,进行筛选过滤,获取所有年龄小于18岁的作者,去重

3.3.2实现

使用普通方法实现:

List<Author> authors = getAuthors();
ArrayList<Author> authors_lt = new ArrayList<>();  // 新的数组保存作者
for (Author author : authors) {
    if (author.getAge()<18){
        authors_lt.add(author);
    }
}
Set<Author> set = new HashSet<>();	// 使用set去重
for (Author author : authors_lt) {
    set.add(author);
}
System.out.println(set);
}

使用Stream流的方式实现:

考虑到可能会看不懂,所以匿名内部类也留在这:

List<Author> authors = getAuthors();
// 获取所有年龄小于18岁的作者,去重
authors.stream() // 将集合转为流
    .distinct()  // 去重
    .filter(new Predicate<Author>() {
        @Override
        public boolean test(Author author) {
            return author.getAge() < 18;
        }
    }) // 过滤条件 Predicate
    .forEach(new Consumer<Author>() {
        @Override
        public void accept(Author author) {
            System.out.println(author);
        }
    }); //遍历打印 Consumer

简化:

List<Author> authors = getAuthors();
// 获取所有年龄小于18岁的作者,去重
authors.stream() // 将集合转为流
    .distinct()  // 去重
    .filter(author -> author.getAge() < 18) // 过滤条件 Predicate
    .forEach(author -> System.out.println(author)); //遍历打印 Consumer

idea自带的debug:

在这里插入图片描述

点开后不要急,他在计算中

在这里插入图片描述

过了一会就有了

在这里插入图片描述

去重

在这里插入图片描述

过滤:

在这里插入图片描述

3.4常用操作

3.4.1创建流

单列集合(Collection、List):集合对象.stream()

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

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

Integer[] arr = {1,2,3,4};
Stream<Integer> stream = Arrays.stream(arr);

Stream<Integer> stream = Stream.of(arr);

双列集合:转换为单列集合后在创建

Stream<Map.Entry<String, Object>> stream = map.entrySet().stream();
3.4.2中间操作
filter

​ 可以对流中的数据进行过滤,符合条件的留在流中

例如:打印所有姓名长度大于1的作者的名字

List<Author> authors = getAuthors();
// 打印所有姓名长度大于1的作者的名字
authors.stream()    // 将数据放入stream流中
    .filter(author -> {return author.getName().length()>1;})     // 过滤姓名长度大于1的作者的名字
    .forEach(author -> System.out.println(author.getName()));     // 终结操作
map

​ 可以对流进行计算或者转换

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

List<Author> authors = getAuthors();
// 打印所有作家的名字
authors.stream()
    .map(new Function<Author, String>() {
        @Override
        public String apply(Author author) {	
            return author.getName();
        }
    })    // 取出所有的名字
    .forEach(s -> System.out.println(s));   // 进行打印

在这里插入图片描述

使用简化的lambda表达式:

List<Author> authors = getAuthors();
// 打印所有作家的名字
authors.stream()
    .map(author -> author.getName())    // 取出所有的名字
    .forEach(s -> System.out.println(s));   // 进行打印
distinct

​ 去除流中重复的数据

例如:打印所有作家的名字,要求其中不能有重复的数据

List<Author> authors = getAuthors();
// 打印所有作家的名字,要求其中不能有重复的数据
authors.stream()
    .distinct()	// 去重
    .forEach(author -> System.out.println(author.getName()));	// 遍历打印

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

sorted

​ 可以对流中的数据进行排序

例如:对流中的数据进行年龄降序排序,且不能有相同重复的数据

List<Author> authors = getAuthors();
authors.stream()
    .distinct()
    .sorted(new Comparator<Author>() {  
        @Override
        public int compare(Author o1, Author o2) {
            return o2.getAge() - o1.getAge();	// o1 - o2 升序 , o2 - o1 降序
        }
    })
    .forEach(author -> System.out.println(author));

使用lambda表达式:

List<Author> authors = getAuthors();
authors.stream()
    .distinct()
    .sorted((o1, o2) -> o2.getAge() - o1.getAge())
    .forEach(author -> System.out.println(author));

注意:如果调用空参的sorted方法需要实现Comparator接口,重写方法

limit

​ 可以设置流的最大长度,超过的部分被抛弃

例如:对流中的数据按照年龄降序排序,且不能有重复的数据,然后打印其中年龄最大的2个作家的姓名

List<Author> authors = getAuthors();
authors.stream()
    .distinct()
    .sorted((o1, o2) -> o2.getAge() - o1.getAge())
    .limit(2)
    .forEach(author -> System.out.println(author));
skip

​ 跳过流中的前n个数据,返回剩下的数据

例如:打印除了年龄最大的作家外的所有作家,不能有重复的数据,且按照年龄的降序排序

List<Author> authors = getAuthors();
authors.stream()
    .distinct()
    .sorted((o1, o2) -> o2.getAge() - o1.getAge())
    .skip(1)
    .forEach(author -> System.out.println(author));
flatMap

​ map只能把一个对象转换成另一个对象来作为流中的数据,而flatMap可以把一个对象转化为多个对象作为流中的数据

例一:打印所有书籍的名称,要求重复数据去重

// 打印所有书籍的名称,要求重复数据去重
authors.stream()
    .distinct()
    .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);
        }
    });

使用简化的lambda表达式:

// 打印所有书籍的名称,要求重复数据去重
authors.stream()
    .distinct()
    .flatMap(author -> author.getBooks().stream())
    .distinct()
    .forEach(book -> System.out.println(book));

例二:打印数据的所有分类,按分类去重,不能出现这种格式:哲学,爱情

List<Author> authors = getAuthors();
authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .distinct()
    .flatMap(book -> Arrays.asList(book.getCategory().split(",")).stream())
    .distinct()
    .forEach(s -> System.out.println(s));
3.4.3终结操作
forEach

​ 对流中的数据进行遍历操作,我们通过传入的参数去指定对遍历到的数据进行具体操作

例子:列出所有作家的名字

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

​ 可以用来获取当前流中数据的个数

例子:打印这些作家的所出书籍的数量,去重

List<Author> authors = getAuthors();
authors.stream()
    .distinct()
    .map(author -> author.getBooks())
    .distinct()
    .count();
max&min

​ 可以用来获取流中的最值

例子:分别获取作家书籍中评分的最高和最低值

List<Author> authors = getAuthors();
Optional<Integer> max = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .distinct()
    .map(book -> book.getScore())
    .max((o1, o2) -> o1 - o2);
System.out.println(max);

Optional<Integer> min = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .distinct()
    .map(book -> book.getScore())
    .min((o1, o2) -> o1 - o2);
System.out.println(min);
collect

​ 把当前流转换为一个集合

例一:获取一个存放所有作者姓名的List集合,注意去重

List<Author> authors = getAuthors();
//        例一:获取一个存放所有作者姓名的List集合,注意去重
List<String> list = authors.stream()
    .map(author -> author.getName())
    .distinct()
    .collect(Collectors.toList());
System.out.println(list);

例二:获取一个全是书名的集合,去重

List<Author> authors = getAuthors();
//        例二:获取一个全是书名的集合,去重
Set<String> set = authors.stream()
    .flatMap(author -> author.getBooks().stream())
    .map(book -> book.getName())
    .collect(Collectors.toSet());
System.out.println(set);

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

List<Author> authors = getAuthors();
//        例三:获取一个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);

注意collect()参数是传入一个Collectors工具类

查找与匹配
anyMatch

​ 可以用来判断是否任意数据符合匹配条件的数据,结果为Boolean类型

例子:判断是否有年龄在25岁以上的

List<Author> authors = getAuthors();
boolean b = authors.stream()
    .anyMatch(author -> author.getAge() > 25);
System.out.println(b);
allMatch

​ 可以用来判断是否任意数据符合匹配条件的数据,结果为Boolean类型,全符合时为true,有一条数据为false那就是false

例子:判断是否所有作家都是成年人?

List<Author> authors = getAuthors();
boolean b1 = authors.stream()
    .allMatch(author -> author.getAge() > 17);
System.out.println(b1);
noneMatch

​ 可以用来判断是否任意数据符合匹配条件的数据,结果为Boolean类型,全不符合为true,否则false

例子:判断作家是否都没有超过100岁

List<Author> authors = getAuthors();
boolean b2 = authors.stream()
    .noneMatch(author -> author.getAge() > 100);
System.out.println(b2);
findAny

​ 获取流中任意个一条数据,该方法没办法保证获取的一定是流的第一条数据

例子:获取任意个大于18的作家,如果存在就输出他的名字

List<Author> authors = getAuthors();
Optional<Author> any = authors.stream()
    .filter(author -> author.getAge() > 18)
    .findAny();
System.out.println(any);
findFirst

​ 获取流中的第一个条数据

例子:获取年龄最小的作家,并输出他的名字

List<Author> authors = getAuthors();
Optional<Author> first = authors.stream()
    .sorted((o1, o2) -> o1.getAge() - o2.getAge())
    .findFirst();
System.out.println(first);
reduce归并

​ 对流中的数据按照你指定的计算方式计算出一个结果

​ reduce的作用是把stream中的数据组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿到流中的数据和初始化值进行运算,计算结果再和每次遍历的数据计算。

​ Optional reduce(BinaryOperator accumulator);底层实现:

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();

T reduce(T identity, BinaryOperator accumulator);底层实现:

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

U reduce(U identity,
​ BiFunction<U, ? super T, U> accumulator,
​ BinaryOperator combiner);底层源码

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

例一:使用reduce求所有作者的年龄和

List<Author> authors = getAuthors();
// 使用reduce求所有作者的年龄和
Integer reduce = authors.stream()
    .map(author -> author.getAge())
    .reduce(0, (integer, integer2) -> integer + integer2);
System.out.println(reduce);

例二:使用reduce求所有作家年龄最大的

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

例三:使用reduce求所有作者的最小值

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

第二种方式:

Optional<Integer> min1 = authors.stream()
    .map(author -> author.getAge())
    .reduce((integer, integer2) -> integer < integer2 ? integer : integer2);
System.out.println(min1);
3.5注意事项:
  • 惰性求值(如果没有终结操作,那么他的中间操作都不会执行)
  • 流是一次性的(一旦这个流使用了终结操作,那么这个流就不会在被使用)
  • 不会影响原数据(我们可以对流进行很多处理,但是正常情况下是不会影响到原来的数据)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕竟尹稳健

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值