Lambda表达式
Lambda表达式可以理解为简洁地表示可传递的匿名函数的一种方式: 它没有名称,但它
有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。
举个例子:
// Java8以前
Comparator<Apple> byWeight = new Comparator<Apple>() {
public int compare(Apple a1, Apple a2) {
return a1.getWeight().compareTo(a2.getWeight());
}
}
// Java8,使用了Lambda表达式
Comparator<Apple> byWeight = (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
如何使用Lambda表达式?
- 参数列表:这里采用了Comparator中compare方法的参数,两个 Apple 。
- 箭头:箭头 -> 把参数列表与Lambda主体分隔开。
- Lambda主体:比较两个 Apple 的重量。表达式就是Lambda的返回值了。
注意: 可以不需要写参数类型,单条语句不需要写return,多条语句需要使用{ }括号括起来。
在哪里使用Lambda表达式?
在函数式接口上使用Lambda表达式。
函数式接口
函数式接口就是只定义一个抽象方法的接口。
// 下面哪些是函数式接口?
public interface Adder {
int add(int a, int b);
}
public interface SmartAdder extends Adder{
int add(double a, double b);
}
public interface Nothing{
}
答案: 只有Adder是函数式接口。SmartAdder不是函数式接口,因为它继承了一个Adder又自己定义了一个。Nothing则没有声明抽象方法。
函数式接口能干什么?
Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例。 具体来说就是函数式接口一个具体实现的实例。
其实,使用匿名内部类也可以完成同样的事情,只不过比较笨拙:需要提供一个实现,然后直接内联将它实例化。比如下面的Runnable的run方法。
// 使用匿名内部类的方式
Runnable r = new Runnabler(){
@Override
public void run(){
System.out.println("Hello World!");
}
}
// 使用Lambda
Runnable r = () -> System.out.println("Hello World!");
使用函数式接口
-
Predicate
java.util.function.Predicate接口定义了一个名叫test的抽象方法,他接受泛型T对象,并返回一个boolean。在你需要表示一个涉及类型T的布尔表达式时,就可以使用这个接口。从下面Predicate的源码中也可以看到其他的默认实现方法,这些将会在后面进行解答。// 底层源码 @FunctionalInterface public interface Predicate<T>{ boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> negate() { return (t) -> !test(t); } default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); } }
先看一个栗子:
public static <T> List<T> filter(List<T> list, Predicate<T> p) { List