Java 8 Stream 使用

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/106389071
本文出自【赵彦军的博客】

1、基础概念

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

如果你用过 rxjava ,入门就很简单。

2、常见操作符

filter 过滤

var list = mutableListOf("b", "a", "d", "c")

ist.stream()
    .filter {   
        it != "a"  //输出元素不是 a 的元素
    }
   .forEach {
        Log.d("yanjun", it)
    }

输出结果:

 D/yanjun: b
 D/yanjun: d
 D/yanjun: c

findFirst 查找第一个

var list = mutableListOf("b", "a", "d", "c")

var first = list.stream()
            .findFirst()  //查找第一个元素
            .get()
            
Log.d("yanjun", first)

输出结果:

 D/yanjun: b

sorted 从小到大排序

var list2 = listOf(3, 1, 2)

list2.stream()
            .sorted()  //默认从小到大排序
            .forEach {
                Log.d("yanjun", it.toString())
            }

输出结果:

 D/yanjun: 1
 D/yanjun: 2
 D/yanjun: 3

map 方法用于映射每个元素到对应的结果

var list = listOf(3, 1, 2)

list.stream()
     .map {
         it * 2   //所有元素都乘以 2 
     }
     .forEach {
          Log.d("yanjun", it.toString())
    }

输出结果:

 D/yanjun: 6
 D/yanjun: 2
 D/yanjun: 4

limit 获取指定数量的流

var list = listOf(3, 1, 2)

list.stream()
    .limit(2)  //只输出前2个数据
    .forEach {
        Log.d("yanjun", it.toString())
    }

输出结果:

 D/yanjun: 3
 D/yanjun: 1

collect 将流转换成集合和聚合元素

var list = listOf(3, 1, 2)

var list2 = list.stream()
                .sorted()   //排序 结果为:1 2 3 
                .collect(Collectors.toList())  //把流数据转换成 list 

list2.forEach {
        Log.d("yanjun", it.toString())
     }                

输出结果:

 D/yanjun: 1
 D/yanjun: 2
 D/yanjun: 3

average 求平均值

var list = listOf(3, 1, 2)

var value = list.average()  //求平均值
 
Log.d("yanjun", value.toString())               

输出结果:

 D/yanjun: 2.0

3、Stream 执行顺序

数据流的链式调用是垂直执行的, 但并不是每个操作符都是垂直的,sorted是水平执行的。
为什么要设计成这样呢?原因是出于性能的考虑。

例子1

var list = mutableListOf("b", "a", "d", "c")

list.stream()
     .map {
         Log.d("yanjun map", it)
         it
     }
     .forEach {
         Log.d("yanjun forEach", it)
     }  

输出结果:

D/yanjun map: b
D/yanjun forEach: b
D/yanjun map: a
D/yanjun forEach: a
D/yanjun map: d
D/yanjun forEach: d
D/yanjun map: c
D/yanjun forEach: c

例子2

var list = mutableListOf("b", "a", "d", "c")

list.stream()
     .map {
         Log.d("yanjun map", it)
         it
     }
     .sorted()   //排序
     .forEach {
         Log.d("yanjun forEach", it)
     }  

输出结果:

D/yanjun map: b
D/yanjun map: a
D/yanjun map: d
D/yanjun map: c
D/yanjun forEach: a
D/yanjun forEach: b
D/yanjun forEach: c
D/yanjun forEach: d

4、数据流复用问题

Java8 Stream 流是不能被复用的,一旦你调用任何终端操作,流就会关闭:

var list = mutableListOf("b", "a", "d", "c")

var stream = list.stream()
        
//流第一次被使用,使用完毕后,流被关闭,不能重复使用
stream.forEach {
   Log.d("yanjun", it)
}

//流第二次被使用,会报异常
stream.forEach {
   Log.d("yanjun", it)
 }

报异常,程序出错
在这里插入图片描述

5、并行流

集合支持parallelStream()方法来创建元素的并行流。或者你可以在已存在的数据流上调用中间方法parallel(),将串行流转换为并行流,这也是可以的。

var list = mutableListOf("b", "a", "d", "c")

list.parallelStream()   //创建并行流
     .map {
         Thread.sleep(5000)  //模拟耗时操作
         Log.d("yanjun map", Thread.currentThread().name + " " + it)
         it
     }
     .forEach {
         Log.d("yanjun forEach", Thread.currentThread().name + " " + it)
     }

输出结果:

D/yanjun map: main d
D/yanjun forEach: main d
D/yanjun map: ForkJoinPool.commonPool-worker-1 a
D/yanjun map: ForkJoinPool.commonPool-worker-2 b
D/yanjun forEach: ForkJoinPool.commonPool-worker-1 a
D/yanjun forEach: ForkJoinPool.commonPool-worker-2 b
D/yanjun map: ForkJoinPool.commonPool-worker-3 c
D/yanjun forEach: ForkJoinPool.commonPool-worker-3 c

如您所见,并行流使用了所有的ForkJoinPool中的可用线程来执行流式操作。在持续的运行中,输出结果可能有所不同,因为所使用的特定线程是非特定的。

总结

  • 无存储:Stream是基于数据源的对象,它本身不存储数据元素,而是通过管道将数据源的元素传递给操作。
  • 函数式编程:对Stream的任何修改都不会修改背后的数据源,比如对Stream执行filter操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新的Stream。
  • 延迟执行:Stream的操作由零个或多个中间操作(intermediate operation)和一个结束操作(terminal operation)两部分组成。只有执行了结束操作,Stream定义的中间操作才会依次执行,这就是Stream的延迟特性。
  • 可消费性:Stream只能被“消费”一次,一旦消费就会失效。就像容器的迭代器那样,想要再次遍历必须重新生成一个新的Stream。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值