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

来源:互联网 发布:北京it外包 编辑:程序博客网 时间:2024/06/06 16:24

在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的样式,如下:

@Testpublic 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类并没有直接提供复用的方法,只能采用封装的方式进行复用,所以也只是代码的复用,性能并没有提升。

原创粉丝点击