Stream API – 流式编程的优雅

479次阅读
没有评论

今天要讲的内容非常重要 – Stream 流。这个 ” 流 ” 可不是我们认为的 ”IO 流 ”,它能够让我们对集合,数组等数据在不改变数据源的情况下,做一些连续性丝滑的操作。你可以理解为,Stream 流它就像是工厂中的流水线一样,一个产品的生成过程,它是需要经过一道道的工序,最后才能完工。而每一道工序,就是在上一道工序的基础上完成的。而且 Stream 流内部大量使用了函数式接口,所以它还能与 Lambda 表达式配合使用,非常强大,高效简洁。

在正式讲之前,为了让大家感受下 Stream 流与 Lambda 表达式配合使用的强大之处,我先给大家写一个应用例子。

Stream 流的初体验

假设,我们现在有一种人员 List 表,这张表储存了每个人的姓名,然后我现在要提三个需求。

  • 需求 1:筛选出姓吴的人
  • 需求 2: 筛选出名字长度为 3 的人
  • 需求 3: 遍历输出所有人的名字
// 人员表
ArrayList<String> peoples = new ArrayList<>();
peoples.add("张柯");
peoples.add("吴耿伟");
peoples.add("张小三");
peoples.add("李四");
peoples.add("刘德华");
peoples.add("吴亦凡");
peoples.add("杨幂");
peoples.add("吴能");

不使用 Stream 流的实现方式:

ArrayList<String> peoples1 = new ArrayList<String>();
        for (String people : peoples) {
            // 名字姓吴且长度为 3
            if (people.startsWith("吴") && people.length() == 3) 
                peoples1.add(people);
        }
        for (String people : peoples1) { //
            System.out.println(people);
        }

使用 Stream 流的实现方式:

peoples.stream()
   .filter(s -> s.startsWith("吴") && s.length() == 3)
   .forEach(s -> System.out.println(s));

运行结果:

吴耿伟
 吴亦凡

可以看到,使用 Stream 流的实现方式,代码非常简洁。

Stream 流的操作通常分为两种: 中间操作 和 终端操作。中间操作可以返回多种流,每种流只能使用一次;终端操作就是对流进行使用,使用完之后返回一个新的集合或数组。且中间操作是惰性执行的,只有终端操作开始时,它才会被执行。

2,获取 Stream 流

在使用 Stream 流之前,我们需要先获取 Stream 流,对于集合和数组来说,它们获取流的方式各不相同。

对于数组,获取 Stream 可以使用:

Arrays.stream();
Stream.of();

对于集合,则可以直接调用 stream()方法。且其内部也是调用的 Arrays.stream();

ArrayList<String> peoples = new ArrayList<>();
        peoples.add("张柯");
..........
        peoples.stream(); // 获取 Stream 流

3, 操作 Stream 流

Stream 流给我们提供了很多操作方法,如 filter,count, distinct, concat, limit, skip, max, min, findFirst, findAny 等方法。下面我会介绍部分方法使用方式。

a. filter()方法

filter()方法可以对流中的元素进行过滤,筛选出我们想要的元素。

Stream<String> datas = Stream.of("张三", "李四", "卢本伟", "张开成", "李文斌", "张杨叶");
// 使用 filter 方法筛选出姓李的人
datas.filter(s -> s.startsWith("李"))
     .forEach(s -> System.out.println(s));

运行结果 : 李四, 李文斌

b. count()方法

count()方法可以对流内的元素的个数进行统计,使用方法也非常简单。

Stream<String> datas = Stream.of("张三", "李四", "卢本伟", "张开成", "李文斌", "张杨叶");
long countResult = datas.filter(s -> s.startsWith("李")).count();
System.out.println(countResult);

运行结果: 2。即两个姓李的人

c. max()和 min()方法

max()和 min()这个相信大家都不陌生,从字面上的意思就是获取流中元素的最大最小元素。

Optional<T> max(Comparator<? super T> comparator);
Optional<T> min(Comparator<? super T> comparator);

可以看到,max()和 min()都是根据 Comparator 返回流中的最大最小元素。

Comparator比较器

这里可以顺便讲一下 comparator 比较器,comparator 是一个自定义比较器,比较逻辑在抽象方法 compare 中实现。compare 对 o1 和 o2 进行比较,返回三种状态:

若 compare 返回 0,则 o1=o2;

若 compare 小于 0,则 o1<o2;

若 compare 大于 0,则 o1>o2;

int compare(T o1, T o2);

comparator 会对前两个元素进行比较,然后每次取最大的那个值跟下一个元素进行比较。

此外,comparator 还提供了默认方法 comparing()。comparing 方法可以从给定函数中提取出要比较的字段,然后生成并返回一个新的 comparator 比较器。

Stream<Student> datas1 = Stream.of( //
                new Student("Lujia",20,"男"),
                new Student("Jacker",17,"女"),
                new Student("Killer",34,"男")
        );
        Optional<Student> max = datas1.max(Comparator.comparing((s) -> { //
            return s.getAge();  //}));
        System.out.println(max.get().getAge());

d. limit()和 skip()方法

这两个简单讲一下。limit()方法可以对流元素进行截取,取出前 N 个元素,而 skip()方法则是跳过前 N 个元素。下面给大家看一下使用例子。

Stream<String> datas = Stream.of("张三", "李四", "卢本伟", "张开成", "李文斌", "张杨叶");
datas.limit(3).forEach(s -> System.out.println(s));

运行结果: “ 张三 ”, “ 李四 ”, “ 卢本伟 ”

e. concat()方法

concat()是 Stream 中的一个方法。如果你有多个流并且希望都合并成一个流,那你可以使用 concat()实现。

Stream<String> datas = Stream.of("张三", "李四", "卢本伟", "张开成", "李文斌", "张杨叶");
Stream<String> datas2 = Stream.of("文在闫","丽里","凯文");
Stream<String> newStream = Stream.concat(datas, datas2);
newStream.forEach(System.out::println);

f. distinct()方法

distinct()方法可以对流中的元素进行去重操作,它是通过调用对象中的 hashcode 和 equals 方法实现的去重。

Stream<String> datas = Stream.of("张三", "李四", "卢本伟", "张开成", "李文斌", "张杨叶","李文斌");
datas.distinct().forEach(System.out::println);

重复多余的名字 “ 李文斌 ” 会被去除。

若流中的元素是一个对象,则你需要重写类中的 hashcode 和 equals 方法

g. findFirst()和 findAny()方法

findFirst()和 findAny()方法可以查找流中的元素。findFirst()查找的是流中的第一个元素,而 findAny()从流中取出任意一个元素。

Stream<String> datas = Stream.of("张三", "李四", "卢本伟", "张开成", "李文斌", "张杨叶","李文斌");
Optional<String> first = datas.findFirst();
System.out.println(first);

运行结果: Optional[张三]

本博文今天就讲这么多吧!如果你有任何问题,欢迎在评论区提问。

Stream API - 流式编程的优雅

正文完
 2
lujia
版权声明:本站原创文章,由 lujia 于2024-12-15发表,共计3607字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)