1 Lambda 表达式
1.1介绍
Lambda表达式是一种没有名字的函数,也可称为闭包,是Java 8 发布的最重要新特性。
本质上是一段匿名内部类,也可以是一段可以传递的代码。
还有叫箭头函数的
1.2 特点
允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。
1.3 和匿名内部类对比
Integer[] arr = { 1, 5, 9, 7, 3, 6, 54 };
// asList : 把数组 转换为List集合
List<Integer> integers = Arrays.asList(arr);
// 匿名内部类写法
Collections.sort(integers, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
// lambda
Collections.sort(integers, (i1, i2) -> i2 - i1);
System.out.println(integers);
1.4 应用场景
列表迭代
Map映射
Reduce聚合
代替一个不想命名的函数或是类,该函数或类往往并不复杂。
想尽量缩短代码量的各个场景均可以
1.5 代码实现
1.5.1 具体语法
1、(parameters) -> expression
2、(parameters) ->{ statements; }
1.5.2 语法特点
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值
如果只有一条语句,并且是返回值语句,就可以不写return 不写 {}
如果写上{} 就必须写return 和 ;
如果有 多条语句,必须写{} return 和 ; 也必须写
1.5.3 集合遍历
// jdk1.7-老版写法
for (String ele : list) {
System.out.println(ele);
}
// jdk1.8-新版写法
list.forEach(x -> {
System.out.println(x);
});
1.5.4 集合排序
把数组转换为list
List<Integer> list = Arrays.asList(arr);
jdk1.7-旧版写法,使用比较器进行排序
list.sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println(list);
// jdk1.8-新版写法
// 把数组转换为list
list = Arrays.asList(arr);
list.sort((x, y) -> x - y);
System.out.println(list);
}
2 函数式接口
2.1 介绍
英文称为Functional Interface
其本质是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
核心目标是为了给Lambda表达式的使用提供更好的支持,进一步达到函数式编程的目标,可通过运用函数式编程极大地提高编程效率。
其可以被隐式转换为 lambda 表达式。
2.2 特点
函数式接口是仅制定一个抽象方法的接口
可以包含一个或多个静态或默认方法
回调函数:简单来说就是回调函数,方法的参数是一个方法,在这个方法中对传递的方法进行调用
2.3 应用场景
想通过函数式编程,提高编程效率的各种场景均可。
2.4 JDK自带常用的函数式接口
2.4.1 Supplier<T>接口
Supplier 接口 有一个get方法 用于获取数据
2.4.2 Consumer<T>接口
Consumer void accept(T t); 有参 无返回值
2.4.3 Function<T,R>接口
2.4.4 Predicate<T>接口
3 方法引用和构造器调用
3.1 概念说明
Lambda表达式的另外一种表现形式,提高方法复用率和灵活性。
3.2 特点
更简单、代码量更少、复用性、扩展性更高。
3.3 应用场景
若Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用。
不需要再复写已有API的Lambda的实现。
3.4 代码实现
3.4.1 方法引用
3.4.1.1 对象的引用::实例方法名
对象引用::成员方法
要求 : 使用接口的抽象方法的入参和出参 必须和调用方法的入参出参一致
Supplier<String> su1 = i1::toString;
System.out.println(su1.get());
3.4.1.2 类名::静态方法名
Integer::max
3.4.1.3 类名::实例方法名
类名::成员方法
String::equals
3.4.2 构造器调用
3.4.3 数组调用
4 stream API
4.1 概念说明
数据渠道、管道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算
即一组用来处理数组,集合的API。
4.2 特点
Stream 不是数据结构,没有内部存储,自己不会存储元素。
Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
不支持索引访问。
延迟计算
支持并行
很容易生成数据或集合
支持过滤,查找,转换,汇总,聚合等操作。
4.3 应用场景
流式计算处理,需要延迟计算、更方便的并行计算
更灵活、简洁的集合处理方式场景
4.4 代码实现
4.4.1 运行机制说明
Stream分为源source,中间操作,终止操作。
流的源可以是一个数组,集合,生成器方法,I/O通道等等。
一个流可以有零个或多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用,一个流只会有一个终止操作。
中间操作也称为转换算子-transformation
Stream只有遇到终止操作,它的数据源会开始执行遍历操作。
终止操作也称为动作算子-action
因为动作算子的返回值不再是 stream,所以这个计算就终止了
只有碰到动作算子的时候,才会真正的计算
4.4.2 代码实现
4.4.2.1 生成stream流的5种方式说明
1)数组 , 通过stream类的of方法即可
String[] strings = { "a", "b", "c", "d" };
Stream<String> stream1 = Stream.of(strings);
2)集合 通过集合对象的stream方法即可
List<String> strings2 = Arrays.asList(strings);
Stream<String> stream2 = strings2.stream();
3)通过 Stream的generate方法创建无限流
该流无限大,建议使用limit限制条数
参数是一个Supplier接口,有一个get方法,无参,有返回值
返回的数据就会被放到这个无限流中,也就是,目前这个流中的数据都是1
Stream<Integer> stream3 = Stream.generate(() -> 1);
stream3.limit(10).forEach(x -> System.out.println(x));
4)通过Stream.iterate方法创建无限流
第一个参数是起始值,第二个参数 是一个UnaryOperator,是function的子类,所以是有参有返回值
x->x+2 : 等于步长为2, 那么此时 数据流中的内容为 1,3,5,7,9,11.....
Stream<Integer> stream4 = Stream.iterate(1, x -> x + 2);
stream4.limit(5).forEach(x -> System.out.println(x));
5)已有类的streamAPI
String string = "asdh";
IntStream is = string.chars();
is.forEach(x -> System.out.println(x));
4.4.2.2 常用转换算子
中间操作 又称为转换算子,对数据源进行处理
一个流可以有N个中间操作,每一个中间操作都会返回一个新的流,方便下一个操作使用,可以做到链式调用
但是一个流只能有一个终止操作
如果不执行终止操作,中间操作也不会执行
filter : 对元素进行筛选,不符合条件的就不要了
distinct : 去掉重复的元素
limit : 取一个数据集合的前几条数据
skip : 跳过多少元素
sorted : 排序
map : 在遍历集合的过程中对数据进行操作
注意只用此算子是不会真正进行计算的,只有后边调用动作算子才会真正计算
4.4.2.3 常用动作算子
循环 forEach
计算 min、max、count、average
匹配 anyMatch、allMatch、noneMatch、findFirst、findAny
汇聚 reduce
收集器 collect