suninf 's blog

Enjoy From Programming And Technique

Java8 之Stream

Catalog

本文整理下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());

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

高阶函数

高阶函数是指接受另外一个函数作为参数,或返回一个函数的函数。

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

Comments