什么时候可以使用lambda表达式
lambda表达式只有在上下文中类型有定义的时候才可以使用。也就是说,上下文中定义了该lambda的函数式接口,且目标函数参数为该类型的时候才可以使用。
有些时候,使用系统API的时候我们可以直接使用lambda作为参数传递,原因在于,系统已经定义了一系列的内置函数式接口。
系统预定义的函数式接口
Runnable: 该接口定义了没有参数和返回值的run方法,用于执行一个没有参数和返回值的操作。
Supplier<T>: 定义了返回类型为T的get方法。 用于获取一个T类型的值
Consumer<T>: 定义了一个参数为T的accept方法。用于处理一个T类型的值。
BiConsumer<T,U>: 定义了接收两个参数的accept。用于处理T和U类型的值。
Function<T, R>: 定义了参数为T返回值为R的apply方法。
BiFunction<T,U,R>: 定义了接收参数T,U,返回值为R的accept方法。
Predicate<T>: 定义了一个接收T参数,返回值为boolean的test方法。
BiPredicate<T,U>: 定义了一个接收参数T和U,返回值为boolean的test方法。
接口中的默认方法和静态方法
前面的文章曾经说过,函数式接口里面只能有一个方法,这种说法不太准确。准确的说法应该是:接口中除了必须有且只有一个没有方法体的方法之外,还可以有多个默认方法和静态方法,且这些方法必须有方法体。
默认方法必须使用关键字default
修饰。
jdk8的这些改进的原因在于:lambda表达式的出现导致某些系统接口(interface)需要被修改,为了确保继承/实现了这些接口的类可以保持不变,接口中添加的内容必须由接口自己实现。
比如:Iteratable接口新增的forEach方法:
1 2 3 4 5 6 |
default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } |
由于默认方法必须提供方法实现,因此,如果我们有自己实现了Iterable接口的类,这些类就不需要实现forEach方法。
由于jdk8中的接口允许实现方法,而多个接口又可以同时被一个类实现,这就会造成新的问题:如果一个接口中定义了一个默认方法,而该接口的一个父类或者其他接口中又定义了一个同名的方法(类似c++中的多重继承),那么,会如何选择?下面是jdk的解决规则:
- 优先选择父类的方法。如果一个父类提供了具体的实现方法,那么接口中具有相同名称和参数的默认方法会被忽略。
- 接口冲突。如果一个父接口提供了一个默认方法,而另一个接口也提供了一个具有相同名称和参数类型的方法(不管该方法是否默认方法),那么需要我们通过覆盖该方法来解决冲突(需要我们自己手动选择)
使用lambda表达式创建线程
在没有lambda表达式之前,我们是这样创建线程的:
1 2 3 4 5 6 7 8 9 10 11 |
public class ThreadDemo { public static void main(String[] args){ new Thread(new Runnable() { @Override public void run() { System.out.printf(Thread.currentThread().getName()+ " created.."); } }).start(); } } |
jdk8之后,使用lambda,可以简化创建线程的代码:
1 |
new Thread(() -> System.out.printf(Thread.currentThread().getName()+ " created..")).start(); |
相比之下,lambda表达式的效率要高不小。
使用lambda表达式替换比较器
基本上,一个接口里面如果只定义了一个方法,那么以这个接口类型为参数的地方基本上可以使用lambda表达式代替。其中最常见的场景就是排序。以前,我们可能是这样排序的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public static void main(String[] args){ List<Integer> myList = new ArrayList<>(); myList.add(10); myList.add(20); myList.add(2); myList.add(5); myList.add(13); myList.sort(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1-o2; } }); myList.forEach(System.out::println); } |
如果要逆序排序,只要把o1-o2
变成o2-o1
即可。
使用lambda表达式简化代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static void main(String[] args){ List<Integer> myList = new ArrayList<>(); myList.add(10); myList.add(20); myList.add(2); myList.add(5); myList.add(13); myList.sort((o1, o2) -> o2-o1); myList.forEach(System.out::println); } |
转载请注明:Pure nonsense » java 8中的lambda表达式(补充知识)