Java_8_特性_–_终极手册(二)

4.2 Stream

新增加的Stream API (java.util.stream)引入了在Java里可以工作的函数式编程。这是目前为止对java库最大的一次功能添加,希望程序员通过编写有效、整洁和简明的代码,能够大大提高生产率。

Stream API让集合处理简化了很多(我们后面会看到不仅限于Java集合类)。让我们从一个简单的类Task开始来看看Stream的用法。

01
public class Streams {
02
private enum Status {
03
OPEN, CLOSED
04
};
05

06
private static final class Task {
07
private final Status status;
08
private final Integer points;
09

10
Task( final Status status, final Integer points ) {
11
this.status = status;
12
this.points = points;
13
}
14

15
public Integer getPoints() {
16
return points;
17
}
18

19
public Status getStatus() {
20
return status;
21
}
22

23
@Override
24
public String toString() {
25
return String.format( "[%s, %d]", status, points );
26
}
27
}
28
}
Task类有一个分数的概念(或者说是伪复杂度),其次是还有一个值可以为OPEN或CLOSED的状态.让我们引入一个Task的小集合作为演示例子:

1
final Collection< Task > tasks = Arrays.asList(
2
    new Task( Status.OPEN, 5 ),
3
    new Task( Status.OPEN, 13 ),
4
    new Task( Status.CLOSED, 8 )
5
);
第一个问题是所有的开放的Task的点数是多少?在java 8 之前,通常的做法是用foreach迭代。但是Java8里头我们会用Stream。Stream是多个元素的序列,支持串行和并行操作。

1
// Calculate total points of all active tasks using sum()
2
final long totalPointsOfOpenTasks = tasks
3
    .stream()
4
    .filter( task -> task.getStatus() == Status.OPEN )
5
    .mapToInt( Task::getPoints )
6
    .sum();
7
         
8
System.out.println( "Total points: " + totalPointsOfOpenTasks );
控制台的输出将会是:

Total points: 18
上面代码执行的流程是这样的,首先Task集合会被转化为Stream表示,然后filter操作会过滤掉所有关闭的Task,接下来使用Task::getPoints 方法取得每个Task实例的点数,mapToInt方法会把Task Stream转换成Integer Stream,最后使用Sum方法将所有的点数加起来得到最终的结果。

在我们看下一个例子之前,我们要记住一些关于Stream的说明。Stream操作被分为中间操作和终点操作。

中间操作返回一个新的Stream。这些中间操作是延迟的,执行一个中间操作比如filter实际上不会真的做过滤操作,而是创建一个新的Stream,当这个新的Stream被遍历的时候,它里头会包含有原来Stream里符合过滤条件的元素。

终点操作比如说forEach或者sum会遍历Stream从而产生最终结果或附带结果。终点操作执行完之后,Stream管道就被消费完了,不再可用。在几乎所有的情况下,终点操作都是即时完成对数据的遍历操作。

Stream的另外一个价值是Stream创造性地支持并行处理。让我们看看下面这个例子,这个例子把所有task的点数加起来。

1
// Calculate total points of all tasks
2
final double totalPoints = tasks
3
   .stream()
4
   .parallel()
5
   .map( task -> task.getPoints() ) // or map( Task::getPoints )
6
   .reduce( 0, Integer::sum );
7
    
8
System.out.println( "Total points (all tasks): " + totalPoints );
这个例子跟上面那个非常像,除了这个例子里使用了parallel()方法       并且计算最终结果的时候使用了reduce方法。

输出如下:

Total points (all tasks): 26.0
经常会有这个一个需求:我们需要按照某种准则来对集合中的元素进行分组。Stream也可以处理这样的需求,下面是一个例子:

1
// Group tasks by their status
2
final Map< Status, List< Task > > map = tasks
3
    .stream()
4
    .collect( Collectors.groupingBy( Task::getStatus ) );
5
System.out.println( map );
控制台的输出如下:

阅读全文 http://click.aliyun.com/m/21831/

猜你喜欢

转载自liangyan9966.iteye.com/blog/2377788