Lambda表达式
Lambda
需要解决的问题
Lambda表达式其实就是一个匿名函数。
有这样一种场景,需要构造一个TreeSet,而TreeSet的构造方法需要一个Comparator接口的实现,所以需要这样构造:
@Test
public void test1() {
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
};
TreeSet<Integer> set = new TreeSet<>(comparator);
}
以上代码对于Comparator的构造,有用的部分只有o1 - o2,但是由于java语法的约束,需要更多无关的代码。
Lambda表达式则是解决这个问题,通过Lambda表达式,上述代码可以写做:
@Test
public void test2() {
Comparator<Integer> comparator = (o1, o2) -> o1 - o2;
TreeSet<Integer> set = new TreeSet<>(comparator);
}
由此Lambda表达式可以极大精简我们的代码。
案例需求:
需要对两个数进行加减乘除等运算,怎么实现?
传统方式:
public static void main(String[] args) {
add(2,1);
minus(2,1);
multiply(2,1);
divide(2,1);
}
static int add(int left, int right) {
return left + right;
}
static int minus(int left, int right) {
return left - right;
}
static int multiply(int left, int right) {
return left * right;
}
static int divide(int left, int right) {
return left / right;
}
函数式编程:
public static void main(String[] args) {
calc(2, 1, (left, right) -> left + right);
calc(2, 1, (left, right) -> left - right);
calc(2, 1, (left, right) -> left * right);
calc(2, 1, (left, right) -> left / right);
}
static int calc(int left, int right, Calculate calculate) {
return calculate.applyAsInt(left, right);
}
@FunctionalInterface
interface Calculate {
int applyAsInt(int left, int right);
}
使用Lambda表达式的条件
Lambda表达式只能作为函数式接口的表达式
什么是函数式接口
- 像Runnable和Comparator这样只有一个抽象方法的接口,称为函数式接口。 也可以在接口上加上@FunctionalInterface注解,如果编译通过,则该接口就是函数式接口。
- lambda表达式就是对函数式接口中那个唯一的抽象方法的实现
函数式接口大部分定义在 java.util.function包中, 且用@FunctionalInterface注解
四大函数式接口
接口名 | 参数类型 | 返回值类型 | 方法 | 类型 |
---|---|---|---|---|
Predicate | T | boolean | boolean test(T obj) | 断言接口 |
Consumer | T | void | void accept(T obj) | 消费接口 |
Function<T,R> | T | R | R apply(T obj) | 函数接口 |
Supplier | none | T | T get() | 供给接口 |
方法引用
如果Lambda中的内容已经有方法实现了,可以使用“方法引用”。
方法引用是Lambda表达式的另一种表现形式。
采用方法引用时,被引用的方法的入参类型和返回值必须和Lambda表达式一样。
- 对象::实例方法名
PrintStream printStream = System.out;
Consumer consumer1 = i -> System.out.println(i);
Consumer consumer2 = printStream::println;
- 类::静态方法名
Comparator<Integer> comparator1 = (i, j) -> Integer.compare(i, j);
Comparator<Integer> comparator2 = Integer::compare;
- 类::实例方法名
这个方法限制比较多,也比较少用。
- lambda必须两个入参,且调用的方法只能有一个入参
- 第一个参数作为实例方法的调用者,第二个参数作为实例方法的入参
BiFunction<String, String, Boolean> c = (i, j) -> i.equals(j);
BiFunction<String, String, Boolean> c1 = String::equals;
构造方法引用
与函数式接口相结合,自动与函数式接口中方法兼容。
可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一直
Function<Integer,MyClass> fun=(n)->new MyClass(n);
Function<Integer,MyClass> fun=MyClass::new;
数组引用
type[]::new