### 1. 什么是stream API
Java8提供的stream API可以让程序员像操作数据库一样操作集合。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。**通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。**常用的stream API有如下;
```
+--------------------+ +------+ +------+ +---+ +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+ +------+ +------+ +---+ +-------+
```
**简而言之,Stream API是一个非常高效的数据处理框架。**
### 2. stream的几个特点
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源的来源。 可以是集合,数组,I/O channel, 产生器generator 和IntStream等
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
### 3. Stream API使用列子
#### 3.1 Stream分类
可以从不同的数据源创建stream。java collection包中的Collections,Lists,Sets这些类中新增stream()和parallelStream()方法,通过这些方法可以创建一个顺序stream(sequential streams)或者一个并发的stream(Parallel streams)。并发stream(Parallel streams)更适合在多线程中使用,本文先介绍顺序流(sequential streams)在结尾会描述并发stream(Parallel streams),
```
Arrays.asList("a1", "a2", "a3")
.stream()
.findFirst()
.ifPresent(System.out::println); // a1
1234
```
List对象上调用stream()方法可以返回一个常规的对象流。在下面的例子中我们不需要创建一个collection对象也可以使用stream:
```
Stream.of("a1", "a2", "a3")
.findFirst()
.ifPresent(System.out::println); // a1
123
```
直接使用Stream.of()方法就能从一组对象创建一个stream对象,
除了常规的对象流,JAVA 8中的IntStream,LongStream,DoubleStream这些流能够处理基本数据类型如:int,long,double。比如:IntStream可以使用range()方法能够替换掉传统的for循环
```
IntStream.range(1, 4)
.forEach(System.out::println);
12
```
基本类型流(primitive streams)使用方式与常规对象流类型(regular object streams)大部分相同,但是基本类型流(primitive streams)能使用一些特殊的lambda表达式,比如:用IntFunction代替Function,用IntPredicate代替Predicate,同时`基本类型流(primitive streams)中可以支持一些聚合方法`,如:sum(),average()等。
```
Arrays.stream(new int[] {1, 2, 3})
.map(n -> 2 * n + 1)
.average()
.ifPresent(System.out::println); // 5.0
1234
```
可以通过常规对象流(regular object stream)的mapToInt(), mapToLong(),mapToDouble(),基本类型对象流(primitive streams)中的mapToObj()等方法完成常规对象流和基本类型流之间的`相互转换`
```
IntStream.range(1, 4)
.mapToObj(i -> "a" + i)
.forEach(System.out::println);
123
```
下面这个例子中doubles stream先被映射成int stream,然后又被映射成String类型的对象流:
```
Stream.of(1.0, 2.0, 3.0)
.mapToInt(Double::intValue)
.mapToObj(i -> "a" + i)
.forEach(System.out::println);
// a1
// a2
// a
```
#### 3.2 Stream API的处理顺序
我们用下面的一个列子来引入Stream的处理顺序:
```
Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> {
System.out.println("filter: " + s);
return true;
});
```
想象中,上面的列子会输出下面的内容:
```
filter: d2
filter: a2
filter: b1
filter: b3
filter: c
```
但是当我们执行这段代码的时候,控制台没有输出任何内容。下面会来讲下出现这个现象的原因。在讲这个原因之前我们先来引入两个Stream相关的概念,能帮助我们更好的理解Stream API:
**中间操作和最终操作**
> stream包含`中间(intermediate operations)`和`最终(terminal operation)`两种形式的操作。`中间操作(intermediate operations)的返回值还是一个stream`,因此可以通过链式调用将中间操作(intermediate operations)串联起来。`最终操作(terminal operation)只能返回void或者一个非stream的结果。`在上述例子中:filter, map ,sorted是中间操作,而forEach是一个最终操作。更多关于stream的中可用的操作可以查看java doc。上面例子中的链式调用也被称为操作管道流。
>
> 大多stream操作接受某种形式的lambda表达式作为参数,通过方法接口的形式指定操作的具体行为,这些方法接口的行为基本上都是无干扰(non-interfering)和无状态(stateless)。无干扰(non-interfering)的方法的定义是:该方法不修改stream的底层数据源,比如上述例子中:没有lambda表达式添加或者删除myList中的元素。无状态(stateless)方法的定义:操作的执行是独立的,比如上述例子中,没有lambda表达式在执行中依赖可能发生变化的外部变量或状态。
**简单粗浅的总结下上面那段话:返回值是还是Stream类型的操作是中间操作,返回值是void或者是非Stream类型的操作的最终操作。Stream的API不会改变原始数据。**
下面是Stream的接口,我们通过返回值就可以清楚的判断哪些是中间操作哪些是最终操作。像我们平时常用的操作filter、map、distinct、sort和limit等都是中间操作。
```
public interface Stream
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~