本文整理下Java8引入的Stream流,能大大简化集合类的操作,同时引入了常用的filter, map, reduce等高阶函数的操作类型。
Stream有点类似C++库boost.Range的概念,是基于容器的迭代范围的一个视图,并能够给予视图做各种算法。
Stream的引入
先看一个例子:
Integer [] ary = {1,2,3,4,5,6,7,8,9};
ArrayList<Integer> al = new ArrayList<Integer>(Arrays.asList(ary));
al.stream()
.filter( x -> x%2==1 )
.forEach(x -> System.out.println(x));
long count = al.stream()
.filter( x -> x%2==0 )
.count();
输出:
1
3
5
7
9
惰性求值 和 及早求值
- 像 filter 这样只描述 Stream,最终不产生新集合的方法叫作 惰性求值 方法
- 像 count 这样 最终会从 Stream 产生值的方法叫作 及早求值 方法
如果返回值是Stream,那么是惰性求值; 如果返回值是另一个值或为空,那么就是及早求值
使用这些操作的理想方式就是形成一个惰性求值的链,最后用一个及早求值的操作返回想要的结果,这正是它的合理之处。
常用操作
collect(toList())
由 Stream 里的值生成一个列表
List<String> collected =
Stream.of("a", "b", "c").collect(Collectors.toList());
System.out.println(
names.stream()
.filter(name ‑> name.startsWith("J"))
.filter(name ‑> name.length() > 3)
.map(name ‑> name.toUpperCase())
.collect(Collectors.joining(", ")));
map
如果有一个函数可以将一种类型的值转换成另外一种类型,map 操作就可以使用该函数,将一个流中的值转换成一个新的流。
List<Integer> collected = Stream.of("12", "34", "56")
.map( x -> Integer.parseInt(x) )
.collect( Collectors.toList() );
filter
遍历数据并检查其中的元素来过滤产生新的Stream
List<String> beginningWithNumbers = Stream.of("a", "1abc", "abc1")
.filter(value -> Character.isDigit(value.charAt(0)))
.collect(Collectors.toList());
flatMap
用多个集合生成相应的Stream,最后把Stream的内容平铺成一个大的Stream
List<String> together = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4))
.flatMap(numbers -> numbers.stream().map( x -> ""+x ))
.collect(Collectors.toList());
// {"1","2","3","4"}
max和min
提取Stream中的最大/最小值,支持传递一个比较函数,返回一个Optional对象
int m = Stream.of(1,5,3)
.max((x,y) -> {
if (x>y) {
return 1;
} else if ( x<y ) {
return -1;
} else {
return 0;
}
})
.get();
// m: 5
reduce
reduce 操作可以实现从一组值中针对每个参数迭代的生成一个值
int count = Stream.of(1, 2, 3)
.reduce(0, (acc, element) -> acc + element);
// count: 6
sorted
我们能够以自然序或着用Comparator 接口定义的排序规则来排序一个流。
Comparator 能用lambada表达式来初始化,我们还能够逆序一个已经排序的流。
sorted()
默认使用自然序排序, 其中的元素必须实现Comparable 接口sorted(Comparator<? super T> comparator)
:我们可以使用lambada 来创建一个Comparator 实例。可以按照升序或着降序来排序元素。
public static List<String> getModelsAfter2000UsingPipeline(
List<Car> cars) {
return
cars.stream()
.filter(car ‑> car.getYear() > 2000)
.sorted(Comparator.comparing(Car::getYear))
.map(Car::getModel)
.collect(toList());
}
并行处理
numbers.stream()
.parallel()
.map(Sample::simulateTimeConsumingComputation)
高阶函数
高阶函数是指接受另外一个函数作为参数,或返回一个函数的函数。
Stream支持的操作大部分都是高阶函数。
// 对谓词函数取非操作
private static <T> Predicate<T> not(Predicate<? super T> predicate) {
return x -> !predicate.test(x);
}
boolean r = not( (Integer x) -> {return x>5;} ).test( 10 );
// r: false