继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

java8 stream

xpbob
关注TA
已关注
手记 152
粉丝 1.6万
获赞 380

java8 stream的提出可以说改变了编程的一种思维。

sql化的表达

sql的表达是一种比较容易上手的语法结构,一直维护做什么的动作。
例如

select avg(num) from table1 where sum>5

对table里的num字段筛选,选出大于5的数字然后求平均值。
对于没有stream的java语言想表达这个。

    public static int cal(int[] data) {
        int totalNum = 0;
        int count = 0;
        for (int datum : data) {
            if (datum > 5) {
                count++;
                totalNum += datum;
            }
        }
        return totalNum / count;
    }

我们先得明白如何求平均,那是总数除以总个数,有筛选条件要以一个过滤,先去求出个数和总和。最后再来计算出平均值。
换成stream表达呢

    public static int calStream(int[] data) {
        double asDouble = Arrays.stream(data).filter((num) -> num > 5).average().getAsDouble();
        return new Double(asDouble).intValue();
    }

这里可能说是用了average这种内置的方法。所以显得很简洁了。如果抽象出一个方法来,也可以这样。我们来看看average的实现。

    public final OptionalDouble average() {
        long[] avg = collect(() -> new long[2],
                             (ll, i) -> {
                                 ll[0]++;
                                 ll[1] += i;
                             },
                             (ll, rr) -> {
                                 ll[0] += rr[0];
                                 ll[1] += rr[1];
                             });
        return avg[0] > 0
               ? OptionalDouble.of((double) avg[1] / avg[0])
               : OptionalDouble.empty();
    }

底层是一个collect的实现,第一个参数表示最终返回一个long的数组,里面有两个元素。第二个表示对于过来的元素的操作。和我们上面的代码表意是相同的。

              count++;
              totalNum += datum;

第三个操作,就是说我们要如何进行每个小的模块的组合。对于我们的用例来说,第三个步骤似乎是没有必要的。
现在如何说我们改动并行的程序来做这个事情呢,

    public static int calStream(int[] data) {
        double asDouble = Arrays.stream(data).parallel().filter((num) -> num > 5).average().getAsDouble();
        return new Double(asDouble).intValue();
    }

想并行化的话,直接加个parallel就可以了。
如果原来的java的写法。得先把数据平均分散多分,最好一个线程一段数据,然后每个数据进行过滤,然后求各自的sum和count。最后合并的时候,组合一下,每个的数据再一起加一下。
看看操作是不是和collect描述的一样的。
通过stream的编写方式不断的编写每个步骤要做什么,而且在大的框架下,保证了每个任务操作的并发性,最终保证了代码从串行到并行的转化。

stream的缺陷

上面提到sql的表达。我们也发现。下面是无法实现的。

select avg(num),max(num) from table1 where sum>5

目前的stream只是针对一份数据的操作。如果结果有多个,例如上面的有均值,有最大值,同时操作多个结果,目前是无法做到的。单纯的依靠sql并不能解决stream的所有的问题。

方便的转化操作

stream还带来了一个好处就是转化非常方便。例如我们用dbutil的工具,传入参数是一个Object[][]的二维数组。自己写还要先计算大小等等。如果用stream就很方便。

  int[][] ints = stringList.stream().map(s -> Integer.parseInt(s)).map(s -> new int[]{s}).toArray(int[][]::new);

这里把stream转化成对应的int,然后把每个元素作为一位数组,最终所有的一维数组组合成一个二维数组。
这里把非常复杂的代码转化成了一行。

小结

stream可以理解为单一结构的sql语法。这样可以快速的帮我们在stream的框架下进行求解操作。但是无法针对多结果的情况。
利用stream可以很快的把一个单线程程序,转化为多线程,加速的并发编程的效率。
数据的转化等操作,stream带来了极大的方便。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP