JAVA 8函数式编程(六):怎样复用Stream对象

在JAVA 8的Stream方法中,分为两大类,一类是惰性求值,另一类是立刻求值,只要Stream调用了立刻求值,Stream就会自动关闭,如果再次调用,将会提示如下错误:

java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)
    at java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:479)
    at com.mirana.stream.FlatMapReduceTest.testFlatMap(FlatMapReduceTest.java:49)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

这样的情况,就给我们摆出了一个难题,如果我们既要进行元素个数统计,又要对元素进行求和,两个立刻求值的函数,必然只能执行一个,怎么办呢?

查遍了Stream的官方接口,发现并没有解决此问题的方法,但是我们可以采用封装的方式解决此问题,即通过调用函数来获取新的Stream对象,从而分离Stream实例,如下:

private  List<String> joins = Lists.newArrayList("1, 2, 3", "2, 3, 4", "3, 4, 5");
// 通过函数每次返回新的Stream对象
public Stream<Integer> getStream() {
    // 将字符转换为数字Stream
    return joins.stream().flatMap(str -> {
        String[] nums = str.split(",");
        // 将字符转换为数字
        return Arrays.asList(nums).stream().map(num -> {
            return Integer.parseInt(num.trim());
        });
    });
}

从上面的例子可以看出:
1. Stream并没有依赖于可迭代对象的并发锁,只要调用stream()方法就会新的Stream实例,如上例中的joins对象可多次创建Stream实例,实例之间并没有相互影响;
2. flatMap方法与map方法的区别在于函数接口的返回值(注意,是函数接口,而不是方法自身,即Function.apply方法),flatMap必须返回Stream,而Map没有此限制;

如果要在函数内定义内调用,上述的方法还可以采用lambda的样式,如下:

@Test
public void testReStream() {
    // 直接在函数内定义函数
    Supplier<Stream<Integer>> supplier = () ->              joins.stream().flatMap(str -> {
        String[] nums = str.split(",");
        return Arrays.asList(nums).stream().map(num -> {
            return Integer.parseInt(num.trim());
        });
     });
    // 计数
    assertThat(supplier.get().count(), IsEqual.equalTo(9L));
    // 求和
    int sum = supplier.get().reduce((a, b) -> a + b).get();
    assertThat(sum, IsEqual.equalTo(27));
}

结论

JAVA 8的Stream类并没有直接提供复用的方法,只能采用封装的方式进行复用,所以也只是代码的复用,性能并没有提升。

    原文作者:蚁方阵
    原文地址: https://blog.csdn.net/yiifaa/article/details/78118342
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞