欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java8处理集合的优雅姿势之Stream

程序员文章站 2024-02-13 20:12:22
前言 在java中,集合和数组是我们经常会用到的数据结构,需要经常对他们做增、删、改、查、聚合、统计、过滤等操作。相比之下,关系型数据库中也同样有这些操作,但是在java...

前言

在java中,集合和数组是我们经常会用到的数据结构,需要经常对他们做增、删、改、查、聚合、统计、过滤等操作。相比之下,关系型数据库中也同样有这些操作,但是在java 8之前,集合和数组的处理并不是很便捷。

不过,这一问题在java 8中得到了改善,java 8 api添加了一个新的抽象称为流stream,可以让你以一种声明的方式处理数据。本文就来介绍下如何使用stream。特别说明一下,关于stream的性能及原理不是本文的重点,如果大家感兴趣后面会出文章单独介绍。

1.stream介绍

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

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

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

stream有以下特性及优点:

  • 无存储。stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,java容器或i/o channel等。
  • 为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
  • 惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
  • 可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。

我们举一个例子,来看一下到底stream可以做什么事情:

Java8处理集合的优雅姿势之Stream

上面的例子中,获取一些带颜色塑料球作为数据源,首先过滤掉红色的、把它们融化成随机的三角形。再过滤器并删除小的三角形。最后计算出剩余图形的周长。

如上图,对于流的处理,主要有三种关键性操作:分别是流的创建、中间操作(intermediate operation)以及最终操作(terminal operation)。

2.stream的创建

在java 8中,可以有多种方法来创建流。

1、通过已有的集合来创建流

在java 8中,除了增加了很多stream相关的类以外,还对集合类自身做了增强,在其中增加了stream方法,可以将一个集合类转换成流。

list<string> strings = arrays.aslist("hollis", "hollischuang", "hollis", "hello", "helloworld", "hollis"); 
stream<string> stream = strings.stream(); 

以上,通过一个已有的list创建一个流。除此以外,还有一个parallelstream方法,可以为集合创建一个并行流。

这种通过集合创建出一个stream的方式也是比较常用的一种方式。

2、通过stream创建流

可以使用stream类提供的方法,直接返回一个由指定元素组成的流。

stream<string> stream = stream.of("hollis", "hollischuang", "hollis", "hello", "helloworld", "hollis"); 

如以上代码,直接通过of方法,创建并返回一个stream。

3.stream中间操作

stream有很多中间操作,多个中间操作可以连接起来形成一个流水线,每一个中间操作就像流水线上的一个工人,每人工人都可以对流进行加工,加工后得到的结果还是一个流。

Java8处理集合的优雅姿势之Stream

以下是常用的中间操作列表:

Java8处理集合的优雅姿势之Stream

filter

filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤掉空字符串:

list<string> strings = arrays.aslist("hollis", "", "hollischuang", "h", "hollis"); 
strings.stream().filter(string -> !string.isempty()).foreach(system.out::println); 
//hollis, , hollischuang, h, hollis 

map

map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

list<integer> numbers = arrays.aslist(3, 2, 2, 3, 7, 3, 5); 
numbers.stream().map( i -> i*i).foreach(system.out::println); 
//9,4,4,9,49,9,25 

limit/skip

limit 返回 stream 的前面 n 个元素;skip 则是扔掉前 n 个元素。以下代码片段使用 limit 方法保理4个元素:

list<integer> numbers = arrays.aslist(3, 2, 2, 3, 7, 3, 5); 
numbers.stream().limit(4).foreach(system.out::println); 
//3,2,2,3 

sorted

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法进行排序:

list<integer> numbers = arrays.aslist(3, 2, 2, 3, 7, 3, 5); 
numbers.stream().sorted().foreach(system.out::println); 
//2,2,3,3,3,5,7 

distinct

distinct主要用来去重,以下代码片段使用 distinct 对元素进行去重:

list<integer> numbers = arrays.aslist(3, 2, 2, 3, 7, 3, 5); 
numbers.stream().distinct().foreach(system.out::println); 
//3,2,7,5 

接下来我们通过一个例子和一张图,来演示下,当一个stream先后通过filter、map、sort、limit以及distinct处理后会发生什么。

代码如下:

list<string> strings = arrays.aslist("hollis", "hollischuang", "hollis", "hello", "helloworld", "hollis"); 
stream s = strings.stream().filter(string -> string.length()<= 6).map(string::length).sorted().limit(3) 
   .distinct(); 

过程及每一步得到的结果如下图:

Java8处理集合的优雅姿势之Stream

4.stream最终操作

stream的中间操作得到的结果还是一个stream,那么如何把一个stream转换成我们需要的类型呢?比如计算出流中元素的个数、将流装换成集合等。这就需要最终操作(terminal operation)

最终操作会消耗流,产生一个最终结果。也就是说,在最终操作之后,不能再次使用流,也不能在使用任何中间操作,否则将抛出异常:

java.lang.illegalstateexception: stream has already been operated upon or closed

俗话说,“你永远不会两次踏入同一条河”也正是这个意思。

常用的最终操作如下图:

Java8处理集合的优雅姿势之Stream

foreach

stream 提供了方法 'foreach' 来迭代流中的每个数据。以下代码片段使用 foreach 输出了10个随机数:

random random = new random(); 
random.ints().limit(10).foreach(system.out::println); 

count

count用来统计流中的元素个数。

list<string> strings = arrays.aslist("hollis", "hollischuang", "hollis","hollis666", "hello", "helloworld", "hollis"); 
system.out.println(strings.stream().count()); 
//7 

collect

collect就是一个归约操作,可以接受各种做法作为参数,将流中的元素累积成一个汇总结果:

list<string> strings = arrays.aslist("hollis", "hollischuang", "hollis","hollis666", "hello", "helloworld", "hollis"); 
strings = strings.stream().filter(string -> string.startswith("hollis")).collect(collectors.tolist()); 
system.out.println(strings); 
//hollis, hollischuang, hollis666, hollis 

接下来,我们还是使用一张图,来演示下,前文的例子中,当一个stream先后通过filter、map、sort、limit以及distinct处理后会,在分别使用不同的最终操作可以得到怎样的结果。

下图,展示了文中介绍的所有操作的位置、输入、输出以及使用一个案例展示了其结果。

Java8处理集合的优雅姿势之Stream

5.总结

本文介绍了java 8中的stream 的用途,优点等。还接受了stream的几种用法,分别是stream创建、中间操作和最终操作。

stream的创建有两种方式,分别是通过集合类的stream方法、通过stream的of方法。

stream的中间操作可以用来处理stream,中间操作的输入和输出都是stream,中间操作可以是过滤、转换、排序等。

stream的最终操作可以将stream转成其他形式,如计算出流中元素的个数、将流装换成集合、以及元素的遍历等。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。