Java8函数之旅 (二) --Java8中的流

4 篇文章 0 订阅

流与集合

   众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦。这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起。

  • 计算从伦敦来的艺术家的人数
  • 请注意这个问题例子在本篇博客中会经常提到,希望你能记住这个简单的例子

这个问题看起来相当的简单,那么使用for循环进行计算

 int count = 0;
    for(Artist artist: allArtists){
        if(artisst.isFrom("London")){
            count++;
        }
    }

标准的写法如上图,当然是没有问题的了,尽管这样的操作是可以的,但依旧存在着问题。

  • 每次需要迭代集合类的的时候,我都要写这样的5行代码或者更多,并且将这样的代码想要改成并行运行的方式也十分的麻烦,需要修改每个for循环才能够实现。
  • 第二个问题就是在于这样的写法本身就是阅读性很差的,什么?我很容易就看的懂呀,但事实上,你不得不承认,其他人必须要阅读了整个循环体,然后再思考一会,才能得出:哦!这段代码是做这个的,当然了,这个例子相当简单,你可能几秒钟就看理解了,但是面对一个多层循环嵌套的集合迭代操作,想看明白,那就相当头疼了。
  • 第三个问题在于,for循环从本质上来讲是一种串行化的操作,从总体来看的话,使用for循环会将行为和方法混为一谈

外部迭代与内部迭代

   上文所用到的for循环是来自java5的增强for循环,本质上是属于iterator迭代器的语法糖,这种使用迭代器的迭代集合的方式,称之为外部迭代,说的通俗一点,就是需要我们程序猿手动的对这个集合进行种种操作才能得到想要结果的迭代方式,叫做外部迭代。
   与外部迭代所对应的,则是内部迭代,内部迭代与之相反,是集合本身内部通过流进行了处理之后,程序猿们只需要直接取结果就行了,这种迭代称为内部迭代。
   那么问题来了,用内部迭代怎么解决上面的问题呢?

long count = allArtists.stream()//进行流操作
                           .filter(artist -> artist.isFrom("London"))//选出所有来自伦敦的艺术家
                           .count();//统计他们的数量

ok,也许你还暂时还不了解关于stream()流的相关操作,别着急,下文会对这些api语法作说明。与上文对应,这里同样针对上文列举出三条好处。

  • 每次需要迭代的时候,并不需要写同样的代码块,说出来你可能不信,这样的代码只有一行,分成三行来表示只是为了方便阅读,改成并行操作的方式也简单的惊人,只需要将第一行的stream()改为parallelStream()就可以了
  • 第二个好处就是可阅读性,相信即使你现在暂时不懂得流的相关api,也能看懂上文的操作,仔细想想这个问题:计算从伦敦来的艺术家的人数,那不就是两步吗?第一步筛选出所有来自伦敦的艺术家,第二步统计他们的人数,现在你回头看上文的代码,第一行使用流对集合进行内部操作,第二步筛选出来自伦敦的艺术家,第三步计数,简单明了,没有令人头疼的循环,也不需要看完整段代码才理解这一行是做什么的。
  • 第三个好处其实第一点已经提到的,轻松的并行化,并且既然是涉及到集合的相关操作,就让集合自己去完成,何必劳驾宝贵的程序员的其他时间呢?
  •  
  • 常用流的api

    1.获取流对象、

    要进行相应的流操作,必然要先获得流对象,首先介绍的就是如何获得一个流的对象。

  • 对于集合来说,直接通过stream()方法即可获取流对象
  • List<Person> list = new ArrayList<Person>(); 
    Stream<Person> stream = list.stream();

     

  • 对于数组来说,通过Arrays类提供的静态函数stream()获取数组的流对象
String[] names = {"chaimm","peter","john"};
Stream<String> stream = Arrays.stream(names);
  • 直接将几个普通的数值变成流对象
Stream<String> stream = Stream.of("chaimm","peter","john");

2.collect(toList())

  collect(Collectors.toList())方法是将stream里的值生成一个列表,也就是将流再转化成为集合,是一个及早求值的操作。
  关于惰性求值与及早求值,这里简单说明一下,这两者最重要的区别就在于看操作有没有具体的返回值(或者说是否产生了具体的数值),比如上文的的统计来自英国艺术家人数的代码,第二行代码的操作是首先筛选出来自英国的艺术家,这个操作并没有实际的数值产生,因此这个操作就是惰性求值,而最后的count计数方法,产生了实际的数值,因此是及早求值。惰性求值是用于描述stream流的,因此返回值是stream,而几乎所有对于流的链式操作都是进行各种惰性求值的链式操作,最后加上一个及早求值的方法返回想要的结果。
  你可以用建造者的设计模式去理解他,建造者模式通过一系列的操作进行设置与配置操作,最后调用一个build方法,创建出相应的对象。对于这里也是同样,调用各种惰性求值的方法,返回一个stream流,最后一步调用一个及早求值的方法,得到最终的结果。
那么现在对于这个collect(toList()),使用方法就十分明了了。

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值