在Java中,集合和数组是我们经常使用的数据结构,我们需要进行增、删、改、查、聚合、计数、过滤等操作.相比之下,这些操作在关系型数据库中也有,但是在Java8之前,集合和数组的处理不是很方便。不过,这个问题在Java8中得到了改善,Java8API增加了一个新的抽象,叫做Stream,它允许你以声明的方式处理数据。本文将介绍如何使用Stream。特别是Stream的性能和原理不是本文的重点。如果大家感兴趣,后面会单独写一篇介绍。一、Stream简介Stream使用一种类似于用SQL语句从数据库中查询数据的直观方式,提供了Java集合操作和表达式的高级抽象。StreamAPI可以大大提高Java程序员的生产力,让程序员写出高效、干净、简洁的代码。这种风格把待处理元素的集合看成一个流,在管道中传输,可以在管道的节点上进行处理,如过滤、排序、聚合等。Stream有以下特点和优势:无贮存。Stream不是数据结构,它只是某种数据源的视图,数据源可以是数组、Java容器或I/O通道等。为函数式编程而生。对Stream的任何修改都不会修改其背后的数据源。例如,对Stream进行过滤操作,不会删除过滤后的元素,而是会生成一个新的不包含过滤后元素的Stream。惰性执行。对Stream的操作不会立即执行,只有在用户真正需要结果时才会执行。消耗品。Stream只能被“消费”一次,遍历一次就失效了,就像容器的迭代器一样,要想再次遍历就必须重新生成。我们举个例子看看Stream能做什么:在上面的例子中,获取一些彩色的塑料球作为数据源,先过滤掉红色的,熔化成随机的三角形。再次过滤并删除小三角形。***计算剩余图形的周长。如上图所示,流处理有3个关键操作:流创建、中间操作、终端操作。2.Stream的创建在Java8中,创建流的方式有很多种。1、通过已有的集合创建流在Java8中,除了加入了很多Stream相关的类之外,还增强了集合类本身,加入了一个stream方法,可以将一个集合类转化为流。Liststrings=Arrays.asList("Hollis","HollisChuang","hollis","Hello","HelloWorld","Hollis");Streamstream=strings.stream();上面,通过CreateastreamfromanexistingList。此外,还有一个parallelStream方法可以为集合创建并行流。这种通过集合来创建Stream的方式也是一种常见的方式。2.通过Stream创建流可以使用Stream类提供的方法直接返回一个由指定元素组成的流。Streamstream=Stream.of("Hollis","HollisChuang","hollis","Hello","HelloWorld","Hollis");如上面代码,直接通过of方法创建并返回一个Stream。3.Stream中间操作Stream有很多中间操作,多个中间操作可以连接起来形成一个管道,每个中间操作就像管道上的一个worker,每个worker都可以对stream进行处理,处理后的结果仍然是一个flow。下面列出了常用的中间操作:filterfilter方法用于通过设置的条件过滤出元素。以下代码片段使用filter方法过滤掉空字符串:Liststrings=Arrays.asList("Hollis","","HollisChuang","H","hollis");strings.stream()。filter(string->!string.isEmpty()).forEach(System.out::println);//hollis,,HollisChuang,H,hollismapmap方法用于将每个元素映射到对应的结果,下面的代码片段使用map输出元素对应的平方数:Listnumbers=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,25limit/skiplimit返回Stream的前n个元素;skip表示丢弃前n个元素。以下代码片段使用limit方法分解4个元素:Listnumbers=Arrays.asList(3,2,2,3,7,3,5);numbers.stream().limit(4).forEach(System.out::println);//3,2,2,3sortedsorted方法用于对流进行排序。以下代码片段使用sorted方法进行排序:Listnumbers=Arrays.asList(3,2,2,3,7,3,5);numbers.stream().sorted().forEach(System.out::println);//2,2,3,3,3,5,7distinctdistinct主要用于去重,下面的代码片段使用distinct去重元素:Listnumbers=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处理时会发生什么。代码如下:Liststrings=Arrays.asList("Hollis","HollisChuang","hollis","Hello","HelloWorld","Hollis");Streams=strings.stream().filter(string->string.length()<=6).map(String::length).sorted().limit(3).distinct();每一步的过程和结果如下:4.Stream中间最终操作Stream操作的结果仍然是一个Stream,那么如何将一个Stream转换成我们需要的类型呢?比如计算流中的元素个数,将流转化为集合等等。这需要一个终端操作,它消耗流并产生最终结果。即最后一次操作后,流不能再次使用,也不能使用任何中间操作,否则会抛出异常:java.lang.IllegalStateException:streamhasalreadybeenoperationedorclosed俗话说,”你永远不会两次踏入同一条河流“这正是它的意思。常用的最终操作如下:?forEachStream提供了方法'forEach'来迭代流中的每个数据。下面的代码片段使用forEach输出10个随机数:Randomrandom=newRandom();random.ints().limit(10).forEach(System.out::println);countcount用于统计溪流。Liststrings=Arrays.asList("Hollis","HollisChuang","hollis","Hollis666","Hello","HelloWorld","Hollis");System.out.println(strings.stream().count());//7collectcollect是一个归约操作,可以接受各种方法作为参数,将流中的元素累加成一个汇总结果:Liststrings=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被处理,分别使用不同的final操作可以得到什么结果。下图展示了本文描述的所有操作的位置、输入和输出,并用一个案例展示了结果。5.小结本文介绍了Java8中Stream的用途和优势,Stream的几种用法也被大家所接受,即Stream的创建、中间操作和最终操作。创建Stream有两种方式,一种是通过集合类的stream方法,另一种是通过Stream的of方法。Stream的中间操作可以用来处理Stream,中间操作的输入和输出都是Stream,中间操作可以是过滤、转换、排序等,Stream的最终操作可以将Stream转换成其他形式,比如计算流中的元素个数,将流转化为集合,遍历元素等。【本文为专栏作家霍利斯原创文章,作者微信公众号Hollis(ID:hollishuang)】点此阅读更多本作者好文