Lambda表达式与函数式接口
1 Lambda表达式
Java8 新特性
1.1 从匿名内部类到Lambda
匿名内部类的作用:当一个内部类只需为其创建一次对象,且以后也不会再被用到,就可以使用匿名内部类简化代码编写。
例子:创建线程。
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("CLASS");
}
}).start();
Lambda表达式:大部分场景下可以取代匿名内部类的新特性。
创建线程的代码可以简化为
new Thread(() -> {
System.out.println("LAMBDA");
}).start();
此外,Lambda表达式还可以结合forEach用于容器的遍历。只需一行即可完成遍历。
list.forEach(x -> System.out.println(x));
1.2 Lambda语法
完整的格式
(TYPE parameter, TYPE parameter) -> { code }
做减法,可以分情况省略部分。
"()" 当parameter只有一个时,可以省略,例如list.forEach(x -> System.out.println(x));
"{}" 当code只有一行时,可以省略,例子同上。
"TYPE" 参数类型总是可以省略,编译器会自动识别。
1.3 使用Lambda表达式的限制
Lambda表达式只能实现函数式接口。
2 函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
2.1 @FunctionalInterface
一个让编译器强制检查接口是否为函数式的注解。
2.2 函数式接口的类型
Java在1.8之前就有一些函数式接口:Runnable,Callable,Comparator,FileFilter等等。
Java1.8又新增了一批函数式接口,放在java.util.function
包下(图未截完整)
2.3 从函数式接口到Lambda
2.3.1 Consumer
Consumer:位于java.util.function
包下,接收一个泛型的参数T,然后调用accept,对这个参数进行操作(accept为抽象方法,具体做什么操作由实现决定),没有返回值。
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
//非抽象方法略
}
上面提到的forEach就接收了一个Consumer泛型接口
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
回到forEach配合Lambda进行遍历
list.forEach(x -> System.out.println(x));
Lambda表达式实现了Consumer接口,accept方法被重写为打印接收的参数x,在forEach方法内部通过for循环完成遍历。
2.3.2 Predicate
Predicate:位于java.util.function
包下,接收一个泛型参数T,测试其是否符合test方法中的规则(test方法为抽象方法,具体规则由实现决定),返回一个boolean值。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
//非抽象方法略
}
removeIf:Collection中方法,用于条件删除容器中的元素,接收一个Predicate泛型接口。
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
删除list中小于3的元素
list.removeIf(x -> x < 3);