Lambda表达式
一、函数式接口
函数式接口(functional interface 也叫功能性接口,其实是同一个东西)。简单来说,函数式接口是只包含一个方法的接口。比如Java标准库中的java.lang.Runnable和 java.util.Comparator都是典型的函数式接口。
java 8提供 @FunctionalInterface作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个方法的接口),虚拟机会自动判断, 但 最好在接口上使用注解@FunctionalInterface进行声明,以免团队的其他人员错误地往接口中添加新的方法。
Java中的lambda无法单独出现,它需要一个函数式接口来盛放,lambda表达式方法体其实就是函数接口的实现.
下面的接口就是一个函数式接口
package com.yztcedu.lambdademo_01;
@FunctionalInterface //添加此注解后,接口中只能有一个抽象方法。
public interface A {
void call();
}
二、lambda语法
包含三部分:
1、一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数
2、一个箭头符号:->
3、方法体,可以是表达式和代码块。
(parameters) -> expression 或者 (parameters) -> { statements; }
通过下面的代码可以看到lambda表达式设计的代码更简洁,而且可读性更好。
package com.yztcedu.lambdademo_01;
public class Demo1 {
public static void main(String[] args) {
runThreadByLambda();
runThreadByInnerClass();
}
public static void runThreadByLambda() {
/*
Runnable就是一个函数式接口:他只有一个方法run()方法。
1、因为run()方法没有参数,所以 ->前面的()中不需要声明形参
2、run返回的是void,所以不需要return。
3、->后面写的代码其实就是定义在run方法内的代码。因为此处代码只有一行,所以{}也可以省略。如果此处多与一行,则无法省略。
*/
Runnable runnable = () -> System.out.println("这个是用拉姆达实现的线程");
new Thread(runnable).start();
}
public static void runThreadByInnerClass() {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("这个是用内部类实现的线程");
}
};
new Thread(runnable).start();
}
}
三、方法引用
其实是lambda表达式的一种简化写法。所引用的方法其实是lambda表达式的方法体实现,语法也很简单,左边是容器(可以是类名,实例名),中间是"::",右边是相应的方法名。如下所示:
ObjectReference::methodName
一般方法的引用格式:
- 如果是静态方法,则是ClassName::methodName。如 Object ::equals
- 如果是实例方法,则是Instance::methodName。如Object obj=new Object();obj::equals;
- 构造函数.则是ClassName::new
package com.yztcedu.lambdademo_01;
public class Demo2 {
public static void main(String[] args) {
/*
* 方法引用
*/
Runnable runnable = Demo2::run;//此处本应该是函数式接口的匿名内部类的,表达式Demo2::run,把下面run方法的实现,放到了函数式接口的匿名内部类的run方法中
new Thread(runnable).start();
}
public static void run(){
System.out.println("方法引用的代码...");
}
}
可以看出,run方法就是lambda表达式的实现,这样的好处就是,如果你觉得lambda的方法体会很长,影响代码可读性,方法引用就是个解决办法
四、默认方法和static方法---接口改进
简单说,就是接口可以有实现方法,而且不需要实现类去实现其方法。只需在方法名前面加个default关键字即可。
package com.yztcedu.lambdademo_01;
@FunctionalInterface
public interface A {
void call();
default void fun() {
System.out.println("我是接口的默认方法1中的代码");
}
default void fun2() {
System.out.println("我是接口的默认方法2中的代码");
}
}
为什么要有这个特性?首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8之前的集合框架没有foreach方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口 添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了使接口没有引入与现有的实现不兼容扩展。
Java8中接口引入了defualt,static两种方法提供默认实现,彻底打破了接口不能有默认实现的规定:
static
让接口类似于工具类,提供一些静态方法
static方法不会被子类继承
defualt
给接口加入了默认方法实现
defualt方法会被子类继承,defualt方法的重要运用场景,接口需要新加一个方法,可以帮助我们向后兼容的同时,不断演进,同时我们应该发现这样一来Java也相当于有了部分多重继承的能力。
浙公网安备 33010602011771号