一、函数式接口
函数式接口 有且仅有一个抽象方法
1、Java内置的函数式接口
// Function<T, R> -T作为输入,返回的R作为输出
Function<String,String> fun = (x) -> {return "Function";};
System.out.println(fun.apply("hello world")); // 输出: Function
//Predicate<T> -T作为输入,返回的boolean值作为输出
Predicate<String> pre = (x) ->{System.out.print(x);return false;};
System.out.println(": "+pre.test("hello World")); // hello World: false
//Consumer<T> - T作为输入,执行某种动作但没有返回值
Consumer<String> con = (x) -> {System.out.println(x);};
con.accept("hello world"); // hello world
//Supplier<T> - 没有任何输入,返回T
Supplier<String> supp = () -> {return "Supplier";};
System.out.println(supp.get()); // Supplier
//BinaryOperator<T> -两个T作为输入,返回一个T作为输出,对于“reduce”操作很有用
BinaryOperator<String> bina = (x,y) ->{System.out.print(x+" "+y);return "BinaryOperator";};
System.out.println(" "+bina.apply("hello ","world"));
二、Lambda表达式
Lambda表达式的本质: 作为函数式接口的实例对象【接口的匿名实现】,本质是一个匿名函数。
Lambda表达式对应的编译类型: 1、接口; 2、且该接口有且仅有一个抽象方法 即是(函数式接口)
1、Lambda作用
- 简写接口的匿名内部类的写法
2、语法
ArrayList<Integer> list = new ArrayList<>(); // 类型推到,运行类型的<>省略类型
list.add(1);
list.add(2);
list.add(3);
/**
* (o1, o2) -> Integer.compare(o2, o1)
* -> 表示Lambda操作符或者箭头操作符
* -> 左边:Lambda形参列表(即:匿名内部类重新方法的形参列表)
* -> 右边:Lambda体 (即:重写的抽象方法的方法体)
*/
list.sort((o1, o2) -> Integer.compare(o2, o1));
System.out.println(list);
3、Lambda表达式的六种使用
3.1、抽象方法:无参、无返回值
Runnable r = () -> System.out.println("Runnable中的run方法被重写了");
r.run();
3.2、抽象方法:需要传一个参数、无返回值
Consumer<String> con = (String s) -> System.out.println(s);
con.accept("Test");
3.3、抽象方法:需要传一个参数(类型省略,编译器自动推断)、无返回值
Consumer<String> con = (s) -> System.out.println(s);
con.accept("Test");
3.4、抽象方法:只有一个参数时,形参的小括号可以省略、无返回值
Consumer<String> con = s -> System.out.println(s);
con.accept("Test");
3.5、抽象方法:有两个或以上的参数,多条执行语句,并且有返回值
Comparator<Integer> com = (o1, o2) -> {
System.out.println("line one");
return o1 - o2;
};
3.6、抽象方法:Lambda体只有一条语句时, return和大括号都可以省略
Comparator<Integer> com = (o1, o2) -> o1 - o2;
com.compare(12, 6);
三、方法引用/构造器引用/数组引用
方法引用其实就是Lambda表达式的语法糖。
1、方法引用的使用前提:
重写的抽象方法的形参列表和返回值类型与Lambda体方法引用的方法的形参列表和返回值类型相同。
2、Lambda语法糖的写法
- 对象 :: 非静态方法/实例方法名
- 类 :: 静态方法名
- 类 :: 非静态方法名
四、Stream API
Stream 关注的是数据的运算,与CPU打交道。Stream API用于操作集合和数组的
1、Stream特点
- Stream不会存储元素
- 不会改变源对象,会返回一个新Stream
- 操作是延迟的(需要执行完终止操作,才能进行中间的一些列操作)
2、Stream操作流程
- Stream实例化
/**
* 1、通过Collection集合实例化Stream
*/
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
// 顺序流
Stream<Integer> stream = integers.stream();
// 并行流[多线程]
Stream<Integer> integerStream = integers.parallelStream();
/**
* 2、通过数组的Arrays实例化Stream
*/
int[] arr = {1, 2, 3};
IntStream stream1 = Arrays.stream(arr);
/**
* 3、通过Stream类的of方法
*/
Stream<Integer> integerStream1 = Stream.of(1, 2, 3, 4, 5, 6);
- 中间操作链(过滤、计算、排序等)
ArrayList<Integer> integers = new ArrayList<>();
for (int i = 0; i < 10; i++) {
integers.add(i);
}
Stream<Integer> stream = integers.stream();
/**
* 1、Stream的过滤filter方法,接收一个Predicate接口
*/
stream.filter(i -> i < 5).forEach(System.out::println);
// 调用终止操作forEach后 需要重写实例化Stream: integers.stream()
// 限制
integers.stream().limit(1).forEach(System.out::println);
// 跳过
integers.stream().skip(9).forEach(System.out::println);
// 去重
for (int i = 5; i < 10; i++) {
integers.add(i);
}
integers.stream().distinct().forEach(System.out::println);
// 映射:map(Function f)
// 映射:flatMap(Function f)
// 排序:sorted 需要实现Comparable 或者 传入匿名内部类定制排序
- 终止操作:一旦执行了终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
// 匹配与查找
allMatch(P)===>类似ES的every()
anyMatch(P)===>类似ES的some()
noneMatch(P)
findFirst()
findAny()
count()
max(Comparator c)
min(C)
forEach(C)
// 归约:
reduce()
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer reduce = integers.stream().reduce(0, Integer::sum);
System.out.println(reduce);
// 收集
collect(Collector c)
五、接口的增强
1、静态方法
2、默认方法
六、Optional类
避免出现空指针异常