Stream流初体验

250 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

引入:

需求:查找集合中符合条件的人员

public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("Luke");
    list.add("Josh");
    list.add("Cedric");
    list.add("Chester");
    list.add("Lin");
}

要求:查找出以L开头的并且长度为3的人,并打印出来。
传统使用for循环的时候,我们是这样做的。
将数组先循环一边,找出以L开头的人,再将结果集循环一遍,找出长度为3的。

List<String> list1 = new ArrayList();
for (String s : list) {
    if (s.startsWith("L")) {
        list1.add(s);
    }
}

List<String> list2 = new ArrayList<>();
for (String s : list1) {
    if (s.length()==3) {
        list2.add(s);
    }
}
System.out.println(list2);

此时我们用Stream流实现的话:

list.stream()
        .filter(name -> name.startsWith("L"))
        .filter(name -> name.length() == 3)
        .forEach(name -> System.out.println(name));

1 Stream流的特点

专注于对容器对象的聚合操作

提供串行/并行两种模式

提高编程效率、可读性

使用步骤:

  1. 获取流
  2. 中间操作
  3. 终结操作

2 Stream流常用API简介

2.1 中间操作

  • map 转换流,将一种类型的流转换为另外一种流
  • filter 过滤流,过滤流中的元素,返回一个符合条件的Stream
  • distinct 返回去重的Stream
  • sorted 返回一个排序的Stream
  • peek 主要用来查看流中元素的数据状态
  • limit 返回前n个元素数据组成的Stream
  • skip 返回第n个元素后面数据组成的Stream
  • parallel 并行
  • sequential 串行
  • unordered 不保证有序
  • concat 合成

中间操作可以有0个或者多个打开流过滤/映射返回新流,交给下一个操作使用。

2.2 终结操作

  • forEach 循环操作Stream中数据
  • forEachOrdered
  • toArray 返回流中元素对应的数组对象
  • reduce 聚合操作,用来做统计
  • collect 聚合操作,封装目标数据
  • min 获取最小值
  • max 获取最大值
  • count 统计流中的元素个数
  • iterator 返回此流元素的迭代器
  • findFirst 获取第一个元素
  • findAny 获取任一元素
  • anyMatch 匹配其中一个
  • allMatch 匹配所有元素
  • noneMatch 所有数据都不符合条件返回true 终结操作只能有一个,代表最后的操作

3 Stream流常用API:获取流

获取流的时候,只需要调用集合的stream方法即可将一个集合转换为流对象

List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();

4 Stream流常用API:forEach&filter&map&count

4.1 foreach

forEach可以对Stream流中的数据进行遍历

//获取一个Stream流
Stream<String> stream = Stream.of("Luke", "Josh", "Cedric", "Chester", "Coat");
//使用Stream流中的方法forEach对Stream流中的数据进行遍历
stream.forEach(name -> System.out.println(name));

4.2 filter

创建一个Stream流,对Stream流中的元素进行过滤,只要以L开头的人

Stream.of("Luke", "Josh", "Cedric", "Chester", "Coat")
        .filter(name -> name.startsWith("L"))
        .forEach(name -> System.out.println(name));

4.3 map

获取一个String类型的Stream流,使用map方法,把字符串类型的整数,转换(映射)为Integer类型的整数

Stream.of("1", "2", "3", "4")
        .map(s -> Integer.parseInt(s))
        .forEach(i -> System.out.println(i));

4.4 count

获取一个Stream流,统计元素个数

long count = list.stream().count();

5 Stream流常用API:collect

Stream流的收集方法
R collect(Collector collector)

它是通过工具类Collectors提供了具体的收集方式
public static <T> Collector toList():把元素收集到List集合中
public static <T> Collector toSet():把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Map集合中

5.1 List

首先我们创建List集合对象

List<String> list = new ArrayList<String>();
list.add("Luke");
list.add("Lin");
list.add("Beth");
list.add("Donna");

得到名字为3个字母的流,并收集到List集合中

List<String> names = list.stream()
        .filter(s -> s.length() == 3)
        .collect(Collectors.toList());

5.2 Set

创建一个Set集合对象

Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(20);
set.add(30);
set.add(33);
set.add(35);

得出大于25的数,并收集到Set集合中

Set<Integer> set1 = set.stream()
        .filter(age -> age > 25)
        .collect(Collectors.toSet());

5.3 Map

定义一个字符串数组,每一个字符串数据由姓名数据和年龄数据组合而成

String[] strArray = {"林青霞,30", "张曼玉,35", "王祖贤,33", "柳岩,25"};

得到字符串中年龄数据大于28的流并将操作完毕的数据收集到Map集合中

Stream.of(strArray)
        .filter(s -> Integer.parseInt(s.split(",")[1]) > 28)
        .collect(Collectors.toMap(
            s -> s.split(",")[0],
            s -> Integer.parseInt(s.split(",")[1])
));

6 Stream流常用API:skip&concat

6.1 skip

获取一个Stream流,并跳过前三个元素

String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼"};
Stream.of(arr)
        .skip(3)
        .forEach(name -> System.out.println(name));

6.2 concat

//创建一个Stream流
Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
//获取一个Stream流
String[] arr = {"美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼"};
Stream<String> stream2 = Stream.of(arr);
//把以上两个流组合为一个流
Stream.concat(stream1, stream2).forEach(name -> System.out.println(name));