«

Java8 的 Stream 流式操作之王者归来

南京雨花吴彦祖 发布于 阅读:974


相对于Java8之前的Java的相关操作简直是天差地别,Java8 的流式操作的出现,也很大程度上改变了开发者对于Java的繁琐的操作的印象,从此,Java也走向了函数式编程的道路!

1 流的创建

1.1 流的创建方法

既然需要聊聊流的操作,那么,首先还是先看看怎么创建流。

创建流的方法有三种,分别是:Stream.of()、Stream.iterate()、Stream.generate(),然后,分别看一下这三个方法的声明。

static  Stream of(T... values)

static  Stream iterate(T seed, UnaryOperator f)

static  Stream generate(Supplier s)

Stream.of():参数很简单,就是一系列的泛型参数。Stream.iterate():第一个参数是一个初始值,第二个参数是一个操作。Stream.generate():参数就是一个Supplier的供给型的参数。

1.2 流的创建方法举例

/*
     * @Author 欧阳思海
     * @Description  创建流
     * @Date 11:05 2019/8/26
     * @Param []
     * @return void
     **/
    @Test
    public void testCreateStream() {
        //利用Stream.of方法创建流
        Stream stream = Stream.of("hello", "world", "Java8");
        stream.forEach(System.out::println);
        System.out.println("##################");
        //利用Stream.iterate方法创建流
        Stream.iterate(10, n -> n + 1)
                .limit(5)
                .collect(Collectors.toList())
                .forEach(System.out::println);
        System.out.println("##################");
        //利用Stream.generate方法创建流
        Stream.generate(Math::random)
                .limit(5)
                .forEach(System.out::println);
        System.out.println("##################");
        //从现有的集合中创建流
        List strings = Arrays.asList("hello", "world", "Java8");
        String string = strings.stream().collect(Collectors.joining(","));
        System.out.println(string);
    }

Java8 的 Stream 流式操作之王者归来

在上面的例子中,Stream.of()方法的参数是几个字符串,Stream.iterate()方法的第一个参数是初始值 10,第二个参数是在10 的基础上每次加 1 的操作,Stream.generate()的参数是用 Random 方法产生随机数。

1.3 流的创建总结

流的创建有三种方法,分别是Stream.of()、Stream.iterate()、Stream.generate(),这几个都是 Stream 类的静态方法,所以,使用起来非常的方便。

2 流的操作

在上一节中,我们知道怎么创建流了,接下来,我们就看看对流可以进行哪些操作,使用了 Stream 流之后,是否会比 Java8 之前方便很多呢?

2.1 装箱流

在处理对象流的时候,可以利用 Collectors 类的静态方法转换为集合,例如,将字符串流转换为 List ,这种方式是没有问题的。

但是,如果遇到 double流想要转换为 List 时,这是就会报错。

DoubleStream.of(1.0, 2.0, 3.0)
                .collect(Collectors.toList());//错误的写法

这种方式就是错误的,编译是不能通过的。

别慌,对于这种问题,有 3 种比较好的解决方法。

利用 boxed 方法

利用 boxed 方法,可以将 DoubleStream 转换为 Stream ,例如;

DoubleStream.of(1.0, 2.0, 3.0)
                .boxed()
                .collect(Collectors.toList());

这样就解决了上面的问题。

利用 mapToObj 方法

利用 mapToObj 方法也可以实现上面的功能,另外,也提供了 mapToInt、mapToLong、mapToDouble 等方法将基本类型流转换为相关包装类型。

DoubleStream.of(1.0, 2.0, 3.0)
                .mapToObj(Double::valueOf)
                .collect(Collectors.toList());
collect 方法

一般情况下,我们利用 collect 方法的时候,都是用于将流的数据收集为基本类型的集合,例如;

stream.collect(Collectors.toList())

然而,collect 方法其实还有一种更加一般化的形式,如下;

 R collect(Supplier supplier,
                        ObjIntConsumer accumulator,
                        BiCnsumer combiner)

上面这种方法的第一个参数是一个供给器,相当于初始化一个容器,第二个参数是累加器,相当于给初始化的容器赋值,第三个参数是组合器,相当于将这些元素全部组合到一个容器

下面,我们通过一个简单的例子来看看到底是怎么使用的!

List list = DoubleStream.of(1.0, 2.0, 3.0)
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

上面的例子我们可以看到,第一个参数:使用一个静态方法初始化一个 List 容器,第二个参数:使用静态方法 add ,添加元素,第三个参数:使用静态方法 addAll ,用于联合所有的元素。

从最后的返回值为 List,我们也可以看出,全部组合成一个初始化的 List 集合中了。

2.2 字符串与流之间的转换

这一小节主要讲解一下字符串与流之间的转换,将 String 转为流有两种方法,分别是 java.lang.CharSequence 接口定义的默认方法 charscodePoints ,而将流转为字符串就是我们前面已经讲解到的方法 collect

/*
     * @Author 欧阳思海
     * @Description  字符串与流之间的转换
     * @Date 9:41 2019/9/2
     * @Param []
     * @return void
     **/
    @Test
    public void testString2Stream() {
        String s = "hello world Java8".codePoints()//转换成流
                .collect(StringBuffer::new,
                        StringBuffer::appendCodePoint,
                        StringBuffer::append)//将流转换为字符串
                .toString();

        String s1 = "hello world Java8".chars()//转换成流
                .collect(StringBuffer::new,
                        StringBuffer::appendCodePoint,
                        StringBuffer::append)//将流转换为字符串
                .toString();
    }

在上面的例子中,先用charscodePoints 方法转换为流,然后都是利用 collect 方法再转回字符串。

2.3 流的映射 map 与 flatMap

流的映射是什么意思呢,我们先将一个在 Java8 之前的例子,我们常常需要将一个集合的对象的某一个字段取出来,然后再存到另外一个集合中,这种场景我们在 Java8 之前我们会这样实现。

/*
     * @Author 欧阳思海
     * @Description  Java8之前的用法
     * @Date 19:31 2019/9/2
     * @Param []
     * @return void
     **/
    @Test
    public void testList() {
        List list = new ArrayList();
        List friends = new ArrayList();
        friends.add(new Friend("Java5"));
        friends.add(new Friend("Java6"));
        friends.add(new Friend("Java7"));
        Person person = new Person();
        person.setFriends(friends);
        list.add(person);

        List strings = new ArrayList();

        for(Person p : list){
            strings.add(p.getName());
        }
    }

是不是这样很麻烦,这也就是以前大家一直所说的 Python 用一招,Java 需要用花招!

但是,Java8 却改变了这种现实,我们来看一看怎么使用 mapflatMap

首先,我们先看一下这俩个方法的声明

 Stream map(Function

Java8 的 Stream 流式操作之王者归来
Java8 的 Stream 流式操作之王者归来
Java8 的 Stream 流式操作之王者归来
Java8 的 Stream 流式操作之王者归来