1中间与最终方法
流作用是提供了一种操作大数据接口,让数据操作更容易和更快。它具有过滤、映射以及减少遍历数等方法,这些方法分两种:中间方法和终端方法,“流”抽象天生就该是持续的,中间方法永远返回的是Stream,因此如果我们要获取最终结果的话,必须使用最终操作才能收集流产生的最终结果。区分这两个方法是看他的返回值,如果是Stream则是中间方法,否则是终点方法。
· Intermediate:
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、sequential、 unordered
· Terminal:
forEach、 forEachOrdered、 toArray、 reduce、collect、 min、 max、 count、 anyMatch、allMatch、 noneMatch、 findFirst、 findAny、 iterator
简单介绍下几个中间方法(filter、map)以及终点方法(collect、sum、reduce)
1.1Filter
在数据流中实现过滤功能是首先我们可以想到的最自然的操作了。Stream接口暴露了一个filter方法,它可以接受表示操作的Predicate实现来使用定义了过滤条件的lambda表达式。
List persons = …
Stream personsOver18 = persons.stream().filter(p -> p.getAge() > 18);//过滤18岁以上的人
1.2Map
假使我们现在过滤了一些数据,比如转换对象的时候。Map操作允许我们执行一个Function的实现(Function<T,R>的泛型T,R分别表示执行输入和执行结果),它接受入参并返回。
首先,让我们来看看怎样以匿名内部类的方式来描述它:
|
|
现在,把上述例子转换成使用lambda表达式的写法:
|
|
1.3Count
count方法是一个流的终点方法,可使流的结果最终统计,返回int,比如我们计算一下满足18岁的总人数
|
|
1.4Collect
collect方法也是一个流的终点方法,可收集最终的结果
|
|
或者,如果我们想使用特定的实现类来收集结果:
|
|
1.5reduce
reduce方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。
例如
//
求和
Integersum = integers.reduce(0, (a, b) -> a+b);
或
Integersum = integers.reduce(0, Integer::sum);
//
字符串连接,
concat = "ABCD"
Stringconcat = Stream.of("A", "B", "C","D").reduce("", String::concat);
//
求最小值,
minValue = -3.0
doubleminValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE,Double::min);
/
/
求和,
sumValue = 10,
有起始值
intsumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
//
求和,
sumValue = 10,
无起始值
sumValue= Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
也有没有起始值的情况,这时会把Stream 的前面两个元素组合起来,返回的是 Optional。
2顺序流与并行流
每个Stream都有两种模式:顺序执行和并行执行。
顺序流:
|
并行流:
|
顾名思义,当使用顺序方式去遍历时,每个item读完后再读下一个item。而使用并行去遍历时,数组会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。
2.1并行流原理:
|
|
Stream则是利用多核技术可将大数据通过多核并行处理。
2.2顺序与并行性能测试对比
如果是多核机器,理论上并行流则会比顺序流快上一倍,下面是测试代码
|
|
方法引用
其实是lambda表达式的一个简化写法,所引用的方法其实是lambda表达式的方法体实现,语法也很简单,左边是容器(可以是类名,实例名),中间是”::”,右边是相应的方法名(不需要写括号)。
格式有以下:
· ClassName::new //构造方法
· objectName::instanceMethod //对象的实例方法
· ClassName::staticMethod //类的静态方法
· ClassName::instanceMethod //特定类的实例方法
第一种是构造器引用,请注意构造器没有参数。
Person::new等同于new Person ()
中间两种方式类似,等同于把lambda表达式的参数直接当成instanceMethod|staticMethod的参数来调用。比如
Person::eat等同于person->person.eat();
System.out::println等同于x->System.out.println(x);
Math::max等同于(x,y)->Math.max(x,y)。
最后一种方式,某个类的实例方法,等同于把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。
比如String::toLowerCase等同于x->x.toLowerCase()。
String::compareTo 等同于(s1, s2)-> s1.compareTo(s2)
参考文章:
http://www.importnew.com/20331.html
http://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/index.html