Java-Lambda的实现原理
函数接口(Functional Interface)
并不能在代码的任何地方任意写Lambda表达式。
Lambda的类型,是对应函数接口的类型。
省略了接口名、方法名、参数类型(基于类型推断)。
将功能视为方法参数。
匿名内部类与Lambda实现对比
匿名内部类会产生额外的class文件
Lambda被封装成主类的一个私有方法,并通过invokedynamic指令进行调用。
自定义函数接口
编写一个只有一个抽象方法的接口。
@FunctionalInterface
是可选的,加上注解编译器会帮忙检查是否符合函数接口的规范。(类似@Override
会帮助检查是否重载)
函数式数据处理
使用流
筛选和切片
- filter 谓词筛选
- distinct 筛选各异的元素,去重
- limit 截断流,返回前n个元素
- skip 跳过元素,跳过前n个元素
映射
- map
- flatMap 扁平化流
查找和匹配
- anyMatch 至少一个匹配
- allMatch 完全匹配
- noneMatch 都不匹配
- findAny 返回任意元素
- findFirst 返回第一个元素
规约
- reduce (折叠,fold)
- 最大值
.reduce(Integer::max)
- 最小值
.reduce(Integer::min)
原始类型流特化
IntStream、DoubleStream、LongStream,分别将流中的元素转化为int、long、double,避免暗含的装箱成本
mapToInt.. 将Stream转换为数值流
boxed() 装箱,将数值流转为Stream
1
2IntStream intstream = menu.stream().mapToInt(Dish::getCalories);// 将Stream转换为数值流
Stream<Integer> stream = intStream.boxed(); // 将数值流转为Stream
常用数值规约
- sum
- max
- min
- OptionalInt
数值范围
rangeClosed 闭区间,起始值,结束值
range 开区间,起始值,结束值(开区间)
从多个源创建流
- 集合、值、数组、文件,以及5里的迭代和生成
无限流,没有固定的大小
迭代
1
Stream.iterate(0,n->n+2).limit(10).forEach(System.out::println);
生成
1
Stream.generate(Math::random).limit(5).forEach(System.out::println);
收集数据
- counting 统计个数
- maxBy minBy 最大值、最小值
- 汇总 summingInt/summingLong/summingDouble
- 平均值 averagingInt/…
- 连接字符串 joining
- 广义规约 reducing,有三个参数
- 起始值
- 提供数值的函数
- BinaryOperator 进行规约的二元操作
- groupingBy 分组
- 按子组收集数据
Map<Dish.Type, Long> typesCount = ...(groupingBy(Dish::getTyype, counting()))
Optional
isPresent()
Optional存在值时返回true,否则falseifPresent(Consumer<T> block)
会在值存在时执行给定代码块T get()
会在值存在时返回值,否则抛出一个NoSuchElement
异常T orElse(T other)
会在值存在时返回值,否则返回一个默认值