Java8函数式编程-包教包会系列(八)

作者:曹伟,叩丁狼教育高级讲师。原创文章,转载请注明出处。

强大的Stream API

什么是Stream

Java8中有两大最为重要的特性。

1)Lambda 表达式,已经学习过了;
2)Stream API (java.util.stream.*包下)

说到Stream便容易想到I/O Stream,而实际上我们这里讲的Stream它是Java8中对数据处理的一种抽象描述;

我们可以把它理解为数据的管道,我们可以通过这条管道提供给我们的API很方便的对里面的数据进行复杂的操作!比如查找、过滤和映射(类似于使用SQL);

更厉害的是可以使用Stream API 来并行执行操作;
简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式,解决了已有集合类库操作上的弊端。

●注意:
1.请暂时忘记对传统IO流的固有印象!
2.Stream接口继承关系

Java8函数式编程-包教包会系列(八)_第1张图片
image.png

图中4种stream接口继承自BaseStream,其中IntStream, LongStream, DoubleStream对应三种基本类型(int, long, double,注意不是包装类型),Stream对应所有剩余类型的stream视图。为不同数据类型设置不同stream接口,可以提高性能,并针对不同数据类型提供不同方法实现。那什么不把IntStream等设计成Stream的子接口?毕竟这接口中的方法名大部分是一样的。答案是这些方法的名字虽然相同,但是返回类型不同,如果设计成父子接口关系,这些方法将不能共存,因为Java不允许只有返回类型不同的方法重载。

传统集合操作vs Stream API操作

传统方式遍历集合

几乎所有的集合(如Collection 接口或Map 接口等)都支持直接或间接的遍历操作。而当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。例如:

List list = new ArrayList<>();
list.add("马云");
list.add("马化腾");
list.add("李彦宏");
list.add("雷军");
list.add("刘强东");
for (String name : list) {
    System.out.println(name);
}

这是一段非常简单的集合遍历操作:对集合中的每一个字符串都进行打印输出操作。

循环遍历的弊端

Java 8的Lambda让我们可以更加专注于做什么(What),而不是怎么做(How),这点此前已经结合匿名内部类进行了对比说明。现在,我们仔细体会一下上例代码,可以发现:

for循环的语法就是“怎么做”
for循环的循环体才是“做什么”(这才是我们要完成的目标!)

如果觉得上面那样的for循环也无所谓的话,我们来完成几个需求:

1)找出姓马的;
2)再从姓马的中找到名字长度等于3的。

如何实现?在Java 8之前的做法可能为:

@Test
public void testWithFor() throws Exception {
    List list = new ArrayList<>();
    list.add("马云");
    list.add("马化腾");
    list.add("李彦宏");
    list.add("雷军");
    list.add("刘强东");
    List maList = new ArrayList<>();
    for (String name : list) {
        if (name.startsWith("马")) {
            maList.add(name);
        }
    }
    List length3List = new ArrayList<>();
    for (String name : maList) {
        if (name.length() == 3) {
            length3List.add(name);
        }
    }
    for (String name : length3List) {
        System.out.println(name);
    }
}

这段代码中含有三个循环,每一个作用不同:

1)首先筛选所有姓张的人;
2)然后筛选名字有三个字的人;
3)最后进行对结果进行打印输出。

每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环是做事情的方式,而不是目的。另一方面,使用线性循环就意味着只能遍历一次。如果希望再次遍历,只能再使用另一个循环从头开始。那Stream能给我们带来怎样更加优雅的写法呢?

Stream的优雅写法

下面来看一下如果使用Java 8的Stream API来实现将有多么的优雅:

@Test
public void testWithStream() throws Exception {
    List list = new ArrayList<>();
    list.add("马云");
    list.add("马化腾");
    list.add("李彦宏");
    list.add("雷军");
    list.add("刘强东");
    list.stream()
        .filter(s -> s.startsWith("马"))
        .filter(s -> s.length() == 3)
        .forEach(System.out::println);
}

使用Stream API将我们真正想要做的事情直接体现在代码中。直接阅读代码的字面意思即可完美展示我们要做的事:

获取流、过滤出姓马的、过滤出名字长度为3的、逐一打印。
代码如此简洁,直观,优雅!

Java8函数式编程-包教包会系列(八)_第2张图片
WechatIMG7.jpeg

你可能感兴趣的:(Java8函数式编程-包教包会系列(八))