关于最近使用java8 lamda表达式的随机 (关于Stream)
流(Stream)仅仅代表着数据流,并没有数据结构,所以他遍历完一次之后便再也无法遍历(这点在编程时候需要注意,不像Collection,遍历多少次里面都还有数据),它的来源可以是Collection、array、io等等。
3.1中间与终点方法
流作用是提供了一种操作大数据接口,让数据操作更容易和更快。它具有过滤、映射以及减少遍历数等方法,这些方法分两种:中间方法和终端方法,“流”抽象天生就该是持续的,中间方法永远返回的是Stream,因此如果我们要获取最终结果的话,必须使用终点操作才能收集流产生的最终结果。区分这两个方法是看他的返回值,如果是Stream则是中间方法,否则是终点方法。具体请参照Stream的api。
简单介绍下几个中间方法(filter、map)以及终点方法(collect、sum)
3.1.1Filter
在数据流中实现过滤功能是首先我们可以想到的最自然的操作了。Stream接口暴露了一个filter方法,它可以接受表示操作的Predicate实现来使用定义了过滤条件的lambda表达式。
1 List persons = …
2 Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);//过滤18岁以上的人
3.1.2Map
假使我们现在过滤了一些数据,比如转换对象的时候。Map操作允许我们执行一个Function的实现(Function<T,R>的泛型T,R分别表示执行输入和执行结果),它接受入参并返回。首先,让我们来看看怎样以匿名内部类的方式来描述它:
1
2
3
4
5
6
7
8
9
|
1 Stream adult= persons 2 .stream() 3 .filter(p -> p.getAge() > 18) 4 .map(new Function() { 5 @Override 6 public Adult apply(Person person) { 7 return new Adult(person);//将大于18岁的人转为成年人 8 } 9 });
|
现在,把上述例子转换成使用lambda表达式的写法:
1
2
3
|
Stream map = persons.stream() .filter(p -> p.getAge() > 18 ) .map(person -> new Adult(person)); |
3.1.3Count
count方法是一个流的终点方法,可使流的结果最终统计,返回int,比如我们计算一下满足18岁的总人数
1
2
3
4
|
int countOfAdult=persons.stream() .filter(p -> p.getAge() > 18 ) .map(person -> new Adult(person)) .count(); |
3.1.4Collect
collect方法也是一个流的终点方法,可收集最终的结果
1
2
3
4
|
List adultList= persons.stream() .filter(p -> p.getAge() > 18 ) .map(person -> new Adult(person)) .collect(Collectors.toList()); |
或者,如果我们想使用特定的实现类来收集结果:
1
2
3
4
5
|
List adultList = persons .stream() .filter(p -> p.getAge() > 18 ) .map(person -> new Adult(person)) .collect(Collectors.toCollection(ArrayList:: new )); |
篇幅有限,其他的中间方法和终点方法就不一一介绍了,看了上面几个例子,大家明白这两种方法的区别即可,后面可根据需求来决定使用。
3.2顺序流与并行流
每个Stream都有两种模式:顺序执行和并行执行。
顺序流:
1
|
List <Person> people = list.getStream.collect(Collectors.toList()); |
并行流:
1
|
List <Person> people = list.getStream.parallel().collect(Collectors.toList()); |
顾名思义,当使用顺序方式去遍历时,每个item读完后再读下一个item。而使用并行去遍历时,数组会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。
3.2.1并行流原理:
1
2
3
4
5
6
|
List originalList = someData; split1 = originalList( 0 , mid); //将数据分小部分 split2 = originalList(mid,end); new Runnable(split1.process()); //小部分执行操作 new Runnable(split2.process()); List revisedList = split1 + split2; //将结果合并 |
大家对hadoop有稍微了解就知道,里面的 MapReduce 本身就是用于并行处理大数据集的软件框架,其 处理大数据的核心思想就是大而化小,分配到不同机器去运行map,最终通过reduce将所有机器的结果结合起来得到一个最终结果,与MapReduce不同,Stream则是利用多核技术可将大数据通过多核并行处理,而MapReduce则可以分布式的。
3.2.2顺序与并行性能测试对比
如果是多核机器,理论上并行流则会比顺序流快上一倍,下面是测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
long t0 = System.nanoTime(); //初始化一个范围100万整数流,求能被2整除的数字,toArray()是终点方法 int a[]=IntStream.range( 0 , 1_000_000).filter(p -> p % 2 == 0 ).toArray(); long t1 = System.nanoTime(); //和上面功能一样,这里是用并行流来计算 int b[]=IntStream.range( 0 , 1_000_000).parallel().filter(p -> p % 2 == 0 ).toArray(); long t2 = System.nanoTime(); //我本机的结果是serial: 0.06s, parallel 0.02s,证明并行流确实比顺序流快 System.out.printf( "serial: %.2fs, parallel %.2fs%n" , (t1 - t0) * 1e- 9 , (t2 - t1) * 1e- 9 ); |