面向对象的编程-Application 22

Previously on OOP:

Besides forEach loop, findAny() related functions can also be used as Stream termination process. findAny() will search whether there is an element within the Stream, satisfying certain conditions.

还有一种termination process是count(),顾名思义是统计Stream中数据的个数。下面一段代码应用了count()函数:

txta是一个存放了好几个字符串的数组,用Stream.of()把它转化为Stream。在没有执行任何intermediate process的情况下,直接进入termination process,调用count()函数,统计Stream中数据的个数,即txta数组中的元素个数。

需要注意的是,count()返回值的类型是long,不是int。

另外,count()函数的功能可以被forEach()循环所代替:

forEach()循环cannot operator on a primitive type,也就是说声明一个临时变量作为计数器是不行的。必须要像上段代码一样,先创建一个class,不管是inner class或者是ordinary class都可以,名字叫做Counter,然后里面包含一个成员变量,名字叫做count,功能是计数器。再创建Counter类的实例。最后在forEach()循环里面用Lambda expression表示调用,往attribute count里面累加。

细心的宝宝们可能会产生一个疑问,既然primitive type肯定不行,那么wrapper class可不可以呢?答案是可以的,不过最好还是新创建一个类。

剩下的且(最)常用的一类termination process就是collectors。在理论部分我们曾经学过,collectors可以自定义,也可以直接选用库类中已经定义好的三大类。在这里,本黄鸭先举一个自定义collector的例子。

把txta数组转化为Stream之后,先调用了一个叫做distinct()的函数,去掉Stream中的重复元素,接下来sort in reverse order,最后就是本例的重头戏,自定义一个collector,把数据整合到一个String中。

第一步supplier,创建一个空的容器,以便于存放Stream中的数据。本段代码中选择了ArrayList作为数据结构,那么就新建一个ArrayList。

第二步accumulator,把Stream中的数据依次加入到ArrayList中,可以调用add()函数。

第三步是combiner,当有多个线程同时执行collect操作时,他们的结果应该如何合并成最终结果。这里使用了Lambda expression来表示行为,假设有a和b两个线程,已经各自收集了一部分的ArrayList,那么就把b中的全部元素加入到a中,得到最终结果。

显然,现在我们还没有进入到multiply threads的例子的学习,所以用多线程来执行collect操作是不可能的。那么combiner这一步能不能为空呢?答案是不能,否则自定义的collector就不完整了。

最后一步是finisher,可以在这里把ArrayList再稍微处理一下,作为collect操作的最终结果。在本段代码中,finisher这一步把ArrayList转化为一个字符串。所以,这个字符串的值能被赋予一个名叫listOfWords的String类型的变量。打印出来的字符串是:

之所以最外层有一对方括号,是ArrayList中的toString()函数引入的。此外,最后一行有可能可以用method reference来写,因为只调用了List中的一个toString()函数。但是编译器很可能没有办法识别出正确的数据类型,所以写Lambda expression表示调用更好一些。

欢迎使用本黄鸭编写的小程序~

微信公众号二维码:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181024G1EPN600?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券