Java8 Stream

ref:http://crazy-j.iteye.com/blog/2041400

JDK8不久前正式发布了,这一次更新为我们带来了相当多的东西,其中一个非常庞大也是非常复杂的框架Stream,特别值得一提,他可以将一些让人烦躁的事情变得简洁,好,进入正题。

 

现在需要除去一个无序数组中大于800的数

 

传统方法:

Java代码   收藏代码
  1. for(int i = 0; i < list.size(); i++) {  
  2.     if(list.get(i) > 800) {  
  3.         list.remove(i);  
  4.     }  
  5. }  

 使用Stream与lambda

Java代码   收藏代码
  1. list.stream().filter((n) -> n <= 800);  

 

如此痛快已经显而易见了,但对于没有了解lambda表达式的童鞋们对类似代码有些抵触,接下来我们还使用传统的Java代码介绍几个比较常用的API。

Java代码   收藏代码
  1. public static void learnMore(List<Integer> list) {  
  2.     // 创建流式调用对象  
  3.     list.stream()  
  4.       
  5.     // 过滤,只保留值大于800的元素。  
  6.     .filter(new Predicate<Integer>() {  
  7.   
  8.         @Override  
  9.         public boolean test(Integer t) {  
  10.             return t > 800;  
  11.         }  
  12.           
  13.     })  
  14.       
  15.     // 排序,默认升序,可传入Comparator。  
  16.     .sorted()  
  17.       
  18.     // 通过map方法将集合中的对象转换为String类型  
  19.     .map(new Function<Integer, String>() {  
  20.         @Override  
  21.         public String apply(Integer t) {  
  22.             return new StringBuilder("String[").append(t).append("]").toString();  
  23.         }  
  24.     })  
  25.       
  26.     // 获取集合中最多n个元素。  
  27.     .limit(10)  
  28.       
  29.     .forEach(new Consumer<String>() {  
  30.         @Override  
  31.         public void accept(String t) {  
  32.             System.out.println(t);  
  33.         }  
  34.     });  
  35.       
  36.     System.out.println("List size:" + list.size());  
  37. }  

 程序输出:

String[801]

String[802]

String[803]

String[804]

String[805]

String[806]

String[807]

String[808]

String[809]

String[810]

List size:1000

通过输出我们可以看到整个流程中所有的操作得到了处理,且所有操作均没有涉及对原集合的变动,探查源代码发现stream对象是靠原集合创建迭代器进行所有操作,因此不对原集合内容进行改动。

 

接下来我们看一个比较有意思的事情:

Java代码   收藏代码
  1. public static void whyNoPrint(List<Integer> list) {  
  2.     list.stream()  
  3.       
  4.     .filter(new Predicate<Integer>() {  
  5.   
  6.         @Override  
  7.         public boolean test(Integer t) {  
  8.             System.out.println(t);  
  9.             return true;  
  10.         }  
  11.     });  
  12. }  

该方法执行过后程序没有任何输出,其实本人最初并不知道这个细节,而是在研究另外一个事情的时候发现的,稍微想一想就能看出这个程序有问题,流对象在filter后就不做任何事情了,所以这个筛选操作也失去了意义,应该是JDK在设计时考虑到的细节,非常值得我们学习。

 

接下来的东西实在是让人太兴奋了:并行流

这个东西是在研究stream.reduce方法时候发现的,reduce提供三个方法的重载,分别为1个参数,两个参数与三个参数,在尝试使用三个参数的reduce方法时候我发现了一个问题,就是最后一个参数传入的BinaryOperator.apply方法根本没有被调用!通过一番苦苦的读源代码工作后我发现reduce方法的第三个参数仅仅在stream以并行模式工作时才会生效!为什么?他是做什么的?我们来看下面的代码:

Java代码   收藏代码
  1. public static void learnReduce_3(List<Integer> list) {  
  2.     // 并行流  
  3.     Stream<Integer> parallelStream = list.stream().parallel();  
  4.     // 串行流  
  5.     Stream<Integer> sequentialStream = list.stream();  
  6.       
  7.     long start = System.currentTimeMillis();  
  8.     parallelStream.reduce(0new BiFunction<Integer, Integer, Integer>() {  
  9.   
  10.         @Override  
  11.         public Integer apply(Integer t, Integer u) {  
  12.             // 在这里停顿10毫秒来提高并行与串行计算的差异。  
  13.             // 虽然流提供了并行计算支持,但如果你需要处理的问题非常简单,还是推荐使用串行模式。  
  14.             // 因为那样避免了并行计算自身的开销,会更快。  
  15.             try {  
  16.                 Thread.sleep(10);  
  17.             } catch (InterruptedException e) {  
  18.             }  
  19.             return t + u;  
  20.         }  
  21.     }, new BinaryOperator<Integer>() {  
  22.   
  23.         @Override  
  24.         public Integer apply(Integer left, Integer right) {  
  25.             System.out.println(Thread.currentThread().getName());  
  26.             return left + right;  
  27.         }  
  28.     });  
  29.     System.out.println("Parallel stream processed with " + (System.currentTimeMillis() - start) + "ms.");  
  30.       
  31.     start = System.currentTimeMillis();  
  32.     sequentialStream.reduce(0new BiFunction<Integer, Integer, Integer>() {  
  33.   
  34.         @Override  
  35.         public Integer apply(Integer t, Integer u) {  
  36.             try {  
  37.                 Thread.sleep(10);  
  38.             } catch (InterruptedException e) {  
  39.             }  
  40.             return t + u;  
  41.         }  
  42.     }, new BinaryOperator<Integer>() {  
  43.   
  44.         @Override  
  45.         public Integer apply(Integer t, Integer u) {  
  46.             System.out.println("Can't print this line.");  
  47.             return 0;  
  48.         }  
  49.     });  
  50.     System.out.println("Sequential stream processed with " + (System.currentTimeMillis() - start) + "ms.");  
  51. }  

 程序输出:

ForkJoinPool.commonPool-worker-3

ForkJoinPool.commonPool-worker-7

ForkJoinPool.commonPool-worker-2

main

ForkJoinPool.commonPool-worker-6

ForkJoinPool.commonPool-worker-4

ForkJoinPool.commonPool-worker-1

ForkJoinPool.commonPool-worker-1

ForkJoinPool.commonPool-worker-5

ForkJoinPool.commonPool-worker-3

ForkJoinPool.commonPool-worker-3

ForkJoinPool.commonPool-worker-7

ForkJoinPool.commonPool-worker-7

ForkJoinPool.commonPool-worker-2

ForkJoinPool.commonPool-worker-2

ForkJoinPool.commonPool-worker-2

ForkJoinPool.commonPool-worker-5

ForkJoinPool.commonPool-worker-5

ForkJoinPool.commonPool-worker-5

ForkJoinPool.commonPool-worker-5

ForkJoinPool.commonPool-worker-4

ForkJoinPool.commonPool-worker-4

ForkJoinPool.commonPool-worker-4

main

main

ForkJoinPool.commonPool-worker-6

ForkJoinPool.commonPool-worker-7

ForkJoinPool.commonPool-worker-7

ForkJoinPool.commonPool-worker-7

ForkJoinPool.commonPool-worker-7

ForkJoinPool.commonPool-worker-7

Parallel stream processed with 1350ms.

 

Sequential stream processed with 10003ms.

 

通过线程名称可以看出,流以并行模式运行的时候使用到了ForkJoin框架。

那么就更加明确了,当流在并行模式下工作时,JDK使用了多个线程进行并行处理,这将牵扯到多个计算结果合并的问题,所以reduce方法的第三个参数(BinaryOperator.apply)作用是将两个线程的计算结果合并。

 

更多信息参考:http://www.infoq.com/cn/articles/forkjoin-to-parallel-streams

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值