博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 8 Stream介绍及使用1
阅读量:6698 次
发布时间:2019-06-25

本文共 8494 字,大约阅读时间需要 28 分钟。

(原)

stream的内容比较多,先简单看一下它的说明:

A sequence of elements supporting sequential and parallel aggregate* operations.  The following example illustrates an aggregate operation using* {@link Stream} and {@link IntStream}:** 
{@code*     int sum = widgets.stream()*                      .filter(w -> w.getColor() == RED)*                      .mapToInt(w -> w.getWeight())*                      .sum();* }
* In this example, {@code widgets} is a {@code Collection
}. We create* a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},* filter it to produce a stream containing only the red widgets, and then* transform it into a stream of {@code int} values representing the weight of* each red widget. Then this stream is summed to produce a total weight.

一个元素的序列,它支持一个串行和并行的聚合操作。下面的例子介绍了使用stream和intstream进行聚合操作。

这个例子里,widgets是一个集合,我们通过Collection.stream()创建了一个Widget的Stream对象。然后过滤了Color属性为RED的对象,然后将其转换成一个int值的Stream,它表示每个红色的重量,然后通过 sum将这些值累加起来。

通过文档能让我们大概的了解stream是怎样操作的。

* 

In addition to {@code Stream}, which is a stream of object references,* there are primitive specializations for {@link IntStream}, {@link LongStream},* and {@link DoubleStream}, all of which are referred to as "streams" and* conform to the characteristics and restrictions described here.

除了Stream之外(它是一种对象引用流),除此之外,还有一些针对于原生类型的聚化,例如IntStream、LongStream、DoubleStream,它们都被称作为“Stream”,并且它们都遵循这里所描述的stream的特性和限制。

* 

To perform a computation, stream* operations are composed into a* stream pipeline. A stream pipeline consists of a source (which* might be an array, a collection, a generator function, an I/O channel,* etc), zero or more intermediate operations (which transform a* stream into another stream, such as {@link Stream#filter(Predicate)}), and a* terminal operation (which produces a result or side-effect, such* as {@link Stream#count()} or {@link Stream#forEach(Consumer)}).* Streams are lazy; computation on the source data is only performed when the* terminal operation is initiated, and source elements are consumed only* as needed.

通过Stream的计算,它的操作会将它组合到一个Stream管道中(Stream特别像Linux里面管道的概念),一个流的管道包含的源可能是一个数组、一个集合、一个函数或是IO channel,在Stream的计算中可能会包括一个或多个中间操作(这些中间操作会将这个Stream转换成另一个Stream,例如通过Stream#filter(Predicate)),和一个中止操作(它会产生一个结果,如Stream#count()),Stream是惰性和,它的源数据只有在终止操作初始化的时候才执行,源数据只有被需要的时候才会被消费。

上面的意思是说,比如。Stream.aaa().bbb().ccc().count();

aaa,bbb,ccc方法为Stream的中间操作。在最的一个count未被调用时,这些中间操作是不会被执行的,这意味这count是一个终止操作。

根据文档的描述,Stream的计算由三部分组中:

1、     源数据

2、     中间操作

3、     终止操作

这里的中间操作属于惰性求值,而终止操作属于及早求值。

那么Stream要怎样创建呢?

看这个方法:

/** * Returns a sequential ordered stream whose elements are the specified values. * * @param 
the type of stream elements * @param values the elements of the new stream * @return the new stream */
@SafeVarargs @SuppressWarnings("varargs") // Creating a stream from an array is safe public static
Stream
of(T... values) { return Arrays.stream(values); }

根据指定的元素返回一个有序有Stream

于是我们可以这样创建:

Stream stream1 = Stream.of("zhangsan", "lisi", "wangwu");

或者

String[] str2 = {"zhangsan", "lisi", "wangwu"};Stream stream2 = Stream.of(str2);

或者通过List.stream()

List list3 = Arrays.asList("zhangsan", "lisi", "wangwu");Stream stream3 = list3.stream();

我们通过IntStream创建流并将其输出:

IntStream.of(3,1,4,9).forEach(System.out::println);

在IntStream中有range和rangeClosed二个方法,接收二个参数,代表着一个整数区间范围,range表示不包含最后一位,rangeClosed表示包含最后一位。

IntStream.range(1,4).forEach(System.out::println);System.out.println("---");IntStream.rangeClosed(1,4).forEach(System.out::println);

如果现在有一个Int集合,要让集合里面的所有数值乘以2再相加得到最后的结果,用以前的写法不得不用循环的方式这么写:

List
partList3 = Arrays.asList(1,2,3);Integer sum3 = 0;for (Integer o : partList3) { sum3 += o * 2;}

而通过Stream可以化成一行代码:

Integer sum33 = partList3.stream().map(integer -> integer * 2).reduce(0,Integer::sum);
/** * Returns a stream consisting of the results of applying the given * function to the elements of this stream. * * 

This is an intermediate * operation. * * @param

The element type of the new stream * @param mapper a
non-interfering, *
stateless * function to apply to each element * @return the new stream */

Stream
map(Function
mapper);

这里的map方法接收一个Function参数,最后会返回一个Stream对象,记住,这里是一个中间操作。Map方法中的Function函数会传入一个参数,然后返回把这个参数经过处理后的结果,reduce方法是一个终止操作,将这些值都通过方法引用Integer::sum的方式加起来。其中reduce接收二个参数:

T reduce(T identity, BinaryOperator
accumulator);

第一个参数可以认为是初始值,第二个参数是计算方式的函数,计算结果等价于:

T result = identity;for (T element : this stream)    result = accumulator.apply(result, element)    return result;}

如果将一个Stream对象转成一数组?

Stream
stream4 = Stream.of("a", "k", "g", "b");

Stream中有一个toArray方法。

/** * Returns an array containing the elements of this stream, using the * provided {
@code generator} function to allocate the returned array, as * well as any additional arrays that might be required for a partitioned * execution or for resizing. * *

This is a terminal * operation. * * @apiNote * The generator function takes an integer, which is the size of the * desired array, and produces an array of the desired size. This can be * concisely expressed with an array constructor reference: *

{
@code * Person[] men = people.stream() * .filter(p -> p.getGender() == MALE) * .toArray(Person[]::new); * }
* * @param the element type of the resulting array * @param generator a function which produces a new array of the desired * type and the provided length * @return an array containing the elements in this stream * @throws ArrayStoreException if the runtime type of the array returned * from the array generator is not a supertype of the runtime type of every * element in this stream */ A[] toArray(IntFunction
generator)

这里除了使用之前说过的这种方式。

String[] streamArr1 = stream4.toArray(len -> new String[len]);

因为IntFunction这个函数接收一个Int类型为数组长度,返回一个数组的类型,我们也可以用文档中提供的例子这种方法。

String[] streamArr2 = stream4.toArray(String[]::new);

如果将一个Stream转换成List

Stream中提供了2个重载的方法

R collect(Supplier
supplier, BiConsumer
accumulator, BiConsumer
combiner);
R collect(Collector
collector);

下面一个方法可以看作是上面的缩写形式,

第一个方法中,文档中如此描述:

Performs a mutable* reduction operation on the elements of this stream.  A mutable* reduction is one in which the reduced value is a mutable result container,* such as an {@code ArrayList}, and elements are incorporated by updating* the state of the result rather than by replacing the result.  This* produces a result equivalent to:* 
{@code*     R result = supplier.get();*     for (T element : this stream)*         accumulator.accept(result, element);*     return result;* }

对这个流中的元素执行一个可变的汇聚的操作,一个可变的汇聚的操作指的是被汇聚的值是一个可变的结果容器,比如ArrayList, 这个集合是通过更新结果状态来合并的,而不是通过替换这个结果来合并的,这个结果等同于:

R result = supplier.get();   for (T element : this stream)        accumulator.accept(result, element);   return result; }

参数1:Supplier,返回的对象是该方法返回的对象类型。

参数2:BiConsumer,接收的第一个参数可以理解是一个需要汇聚的对象,第二个参数是stream中的某一个元素。

参数3:BiConsumer,相当于是一个合并器,将上一次的结果和装进同一个对象中,用于最后的返回。当然这个对象的类型就是Supplier返回的对象类型。

例如这样:

Stream
stream5 = Stream.of("hello", "world", "good", "morning");List
list5 = stream5.collect(() -> new ArrayList<>(),(list1,item) -> list1.add(item),(list2,list1) -> list2.addAll(list1));list5.forEach(System.out::println);

这里有个简单的方法可以替代以上的代码

Stream
stream444 = Stream.of("list1", "list2", "list3");List
list444 = stream444.collect(Collectors.toList());list444.forEach(System.out::println);

Collectors中有很多方法,toList()只是将stream中的值存入ArrayList中返回。

如果想要换成LinkedList,可以用

Collectors.toCollection(LinkedList::new)

如果要将里面的值拼接成一个字符串返回,可以用

Collectors.joining()

在stream中,map作为一个映射方法,可以将集合中的无素作相处理,但如果集合中的每个元素都是一个list,要将这些list中的元素合并成一个集合,以前的做法就是用list.addAll()这个方法,现在可以利用stream中的另一个映射方法,floatMap.

Stream
flatMap(Function
> mapper);

它接收一个 Function函数,返回值为stream

于是可以这样写:

Stream
> stream7 = Stream.of(Arrays.asList(1,2), Arrays.asList(3), Arrays.asList(4,5));List
list7 = stream7.flatMap(list -> list.stream()).collect(Collectors.toList());System.out.println(list7);

将每个stream中的元素都展开,放在一个stream中,最后用collect方法放一个集合中输出。

 例子请看这里:

转载于:https://www.cnblogs.com/LeeScofiled/p/9941674.html

你可能感兴趣的文章
WEB/H5性能优化总结
查看>>
js转换字符串为base64位
查看>>
弹性布局
查看>>
Laravel5.5之事件监听、任务调度、队列
查看>>
前端性能优化之Lazyload
查看>>
vue-i18n使用及踩坑记录
查看>>
@Java | Thread & synchronized - [ 线程同步锁 基本使用]
查看>>
从拿到班车手册.xls到搜索附近班车地点
查看>>
Python学习之路20-数据模型
查看>>
黄文俊:Serverless小程序后端技术分享
查看>>
《netty实战》阅读笔记(2)——Netty 的数据容器ByteBuf
查看>>
Vue 教程第四篇—— Vue 实例化时基本属性
查看>>
3分钟学会SVN:SVN快速上手
查看>>
ZooKeeper(二)ZooKeeper能做什么?
查看>>
【Java学习】JDBC可以再深一点理解
查看>>
阿里云上Kubernetes集群联邦
查看>>
react 项目总结
查看>>
Go编程技巧--io.Reader/Writer
查看>>
WordPress插件开发-创建、停用、删除插件
查看>>
从MapReduce的执行来看如何优化MaxCompute(原ODPS) SQL
查看>>