java8-lambda
Java 8中的Stream API可以让你写出这样的代码:
声明性——更简洁,更易读4.1 流是什么 71
可复合——更灵活
可并行——性能更好
1.方法引用
方法引用主要有三类。
(1) 指向静态方法的方法引用(例如Integer的parseInt方法,写作Integer::parseInt)。你 的 第 一 个
方法引用!
(2) 指 向 任 意 类 型 实 例 方 法 的 方 法 引 用 ( 例 如 String 的 length 方 法 , 写 作
String::length)。
(3) 指向现有对象的实例方法的方法引用(假设你有一个局部变量expensiveTransaction用于存放Transaction类型的对象,它支持实例方法getValue,那么你就可以写expensiveTransaction::getValue)。
2:(arg0,test)->arg0.instanceMethod(test)
ClassName::instanceMethod ClassName是arg0的class
3:test->expr.instanceMethod(test)
axpr::instanceMethod
2.构造函数引用
public class Apple {
private String color;
private int weight;
public Apple(String color, int weight) {
this.color = color;
this.weight = weight;
}
public Apple(String color) {
this.color = color;
}
public Apple(int weight) {
this.weight = weight;
}
public void test() {
Supplier<Apple> p = Apple::new;
Function<Integer, Apple> p2 = Apple::new;
Function<String, Apple> p3 = Apple::new;
BiFunction<String, Integer, Apple> p4 = Apple::new;
}
}
3.复合方法
Predicate 有negate、 and和or三个默认实现,对应的非,与,或的意思很好理解
Function 有andThen和compose两个默认方法
例如f.andThen(g)就是g(f(x)) f.compose就是f(g(x))
4.内部外部迭代
Streams库的内部迭代可以自动选择一种适合你硬件的数据表示和并行实现。与此相反,一旦通过写for-each而选择了外部迭代,那你基本上就要自己管理所有的并行问题了(自己管理实际上意味着“某个良辰吉日我们会把它并行化”或 “ 开 始 了 关 于 任 务 和synchronized 的 漫 长 而 艰 苦 的 斗 争 ”)
5.使用流
filter predicate 过滤元素
distinct 流所生成元素的hashCode和equals方法实现 筛选各异元素
limit int 截断流
skip int 跳过头几个元素
map function<T,U> 这个函数会被应用到每个元素上,并将其映射成一个新的元素
flatmap function<T,U> 方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。流的扁平化。
anyMatch predicate 流中是否有一个元素能匹配给定的谓词
allMatch predicate 它会看看流中的元素是否都能匹配给定的谓词
noneMatch predicate 它可以确保流中没有任何元素与给定的谓词匹配。
findAny void 返回当前流中的任意元素
findFirst void 查找第一个元素
归约
reduce
Optional<T> reduce(BinaryOperator<T> accumulator);
不接受初始值,但是会返回一个Optional对象
T reduce(T identity, BinaryOperator<T> accumulator)
接受两个参数:
一个初始值
一个BinaryOperator来将两个元素结合起来产生一个新值。
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner);
combiner用于并行计算的时候 操作两个结果集的函数
Collect
Collectors.groupingBy Function<T,K> Map<K,List>
Collectors.toList() List
Collectors.counting() long 总和
Collectors.maxBy Optional 最大值
Collectors.summingInt
Collectors.averagingInt 均值
joining() 将对象toString连接
joining(", ") 入参分隔符
public static <T, U> Collector<T, ?, U> reducing(U identity,Function<? super T, ? extends U> mapper,BinaryOperator<U> op)
它需要三个参数。
第一个参数是归约操作的起始值,也是流中没有元素时的返回值.
第二个参数就是转换函数
第三个参数是一个BinaryOperator,将两个项目累积成一个同类型的值。
public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op)
你可以把单参数reducing工厂方法创建的收集器看作三参数方法的特殊情况,它把流中的第一个项目作为起点,把恒等函数(即一个函数仅仅是返回其输入参数)作为一个转换函数。
Stream接口的collect和reduce方法有何不同,因为两种方法通常会获得相同的结果。语义问题在于, reduce方法旨在把两个值结合起来生成一个新值,它是一个不可变的归约。与此相反, collect方法的设计就是要改变容器,从而累积要输出的结果。以错误的语义使用reduce方法还会造成一个实际问题:这个归约过程不能并行工作,因为由多个线程并发修改同一个数据结构可能会破坏List本身。在这种情况下,如果你想要线程安全,就需要每次分配一个新的List,而对象分配又会影响性能。这就是collect方法特别适合表达可变容器上的归约的原因。
groupingBy(f)(其中f是分类函数)实际上是groupingBy(f,Collects.toList())的简便写法
partitioningBy
分区是分组的特殊情况:由一个谓词(返回一个布尔值的函数)作为分类函数。分区函数返回一个布尔值,这意味着得到的分组Map的键类型是Boolean。