java 8中的lambda表达式(补充知识)

JAVA ginotang 733℃ 0评论

什么时候可以使用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方法:

由于默认方法必须提供方法实现,因此,如果我们有自己实现了Iterable接口的类,这些类就不需要实现forEach方法。

由于jdk8中的接口允许实现方法,而多个接口又可以同时被一个类实现,这就会造成新的问题:如果一个接口中定义了一个默认方法,而该接口的一个父类或者其他接口中又定义了一个同名的方法(类似c++中的多重继承),那么,会如何选择?下面是jdk的解决规则:

  • 优先选择父类的方法。如果一个父类提供了具体的实现方法,那么接口中具有相同名称和参数的默认方法会被忽略。
  • 接口冲突。如果一个父接口提供了一个默认方法,而另一个接口也提供了一个具有相同名称和参数类型的方法(不管该方法是否默认方法),那么需要我们通过覆盖该方法来解决冲突(需要我们自己手动选择)

使用lambda表达式创建线程

在没有lambda表达式之前,我们是这样创建线程的:

jdk8之后,使用lambda,可以简化创建线程的代码:

相比之下,lambda表达式的效率要高不小。

使用lambda表达式替换比较器

基本上,一个接口里面如果只定义了一个方法,那么以这个接口类型为参数的地方基本上可以使用lambda表达式代替。其中最常见的场景就是排序。以前,我们可能是这样排序的

如果要逆序排序,只要把o1-o2变成o2-o1即可。

使用lambda表达式简化代码:

 

 

转载请注明:Pure nonsense » java 8中的lambda表达式(补充知识)

喜欢 (0)
0 0 投票数
文章评分
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x
()
x