Lambda表达式
体验Lambda表达式
public class LambdaDemo {
public static void main(String[] args) {
//方式一:新建类实现Runnable接口
Runnable runnable = new RunnableImpl();
Thread thread = new Thread(runnable);
thread.start();
//方式二:匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多线程启动");
}
}).start();
//方式三:Lambda表达式
new Thread(() -> {
System.out.println("多线程启动");
}).start();
}
}
Lambda表达式的标准格式
()
:形式参数,如果有多个参数,使用英文逗号隔开,如果没有参数,留空即可。->
:固定写法,代表指向动作{}
:代码块,具体要做的事,方法体内容
Lambda表达式的使用前提
- 有一个接口
- 接口中有且只有一个抽象方法
- 必须要有上下文环境,才能推导出对应的接口
- 可以根据局部变量的数值推导出Lambda对应的接口:
Runnable r = () -> System.out.println("Lambda表达式");new Thread(r);
- 可以根据调用方法的参数推导出Lambda对应的接口:
new Thread(() -> System.out.println("Lambda表达式")).start();
带参数,带返回值的Lambda表达式
public class AddableDemo {
public static void main(String[] args) {
//lambda表达式
useAddable((x,y) -> x + y);
}
private static void useAddable(Addable addable) {
System.out.println(addable.add(6,5));
}
/*public interface Addable {
int add(int x ,int y);
}*/
}
Lambda表达式的省略模式
- 参数的数据类型可以省略,但是有多个参数时,不能只省略一个参数的数据类型
- 如果参数有且仅有一个,那么小括号可以省略
- 如果代码块只有一条语句,那么可以省略大括号和分号,甚至是return
//lambda表达式
useAddable((int x,int y) -> {
return x + y;
});
//lambda表达式的省略模式
useAddable((x,y) -> x + y);
}
Lambda表达式和匿名内部类的区别
所需类型不同:
- 匿名内部类:可以是接口,可以是抽象类,可以是具体类
- Lambda表达式:只能是接口
使用限制不同: - 如果接口中有且只有一个抽象方法,那么既可以使用匿名内部类也可以使用Lambda表达式
- 如果接口中不只一个抽象方法,那么只能使用匿名内部类不能Lambda表达式
实现原理不同: - 匿名内部类:编译之后产生一个单独的.class字节码文件。
- Lambda表达式:编译之后没有一个单独的.class字节码文件。对应的字节码会在运行时动态生成。
接口组成更新描述
接口的组成
- 常量,
public static final 数据类型 变量名;
- 抽象方法,
public abstract 返回值类型 方法名 ();
- 默认方法(Java8)
- 静态方法(Java8)
- 私有方法(Java9)
接口中的默认方法
格式:public default 返回值类型 方法名(参数列表){方法体}
注意事项:
- 常用于接口升级,需要新增方法时。以及函数拼接。
- 定义默认方法时,可以省略掉
public
修饰符,不能省略掉default
修饰符。 - 默认方法不是抽象方法,所以不强制被重写。可以可以被重写,重写时要去掉default关键字
接口中的静态方法
格式:public static 返回值类型 方法名(参数列表){方法体}
注意事项:
- 不需要实例化,直接使用,节省空间
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
- public可以省略,static不能省略
接口中的私有方法
格式:
-
格式1:
private 返回值类型 方法名(参数列表){方法体}
-
格式2:
private static 返回值类型 方法名(参数列表){方法体}
注意事项: -
默认方法可以调用私有的静态方法和非静态方法
-
静态方法只能调用私有的静态方法
方法引用符
::
该符号为引用运算符,而它所在的表达式被称为方法引用
- Lambda表达式:
usePrintable(s -> System.out.println(s));
,分析:拿到参数s之后通过Lambda表达式,传递给System.out.println方法处理 - 方法引用:
usePrintable(System.out::println);
,分析:直接使用System.out中的println方法来取代Lambda表达式,代码更简洁 获取对象::调用方法;
推导与省略
- 如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,他们都将被自动推导
- 如果使用方法引用,也是同样可以根据上下文进行推导
- 方法引用是Lambda的孪生兄弟
public class PrintableDemo {
public static void main(String[] args) {
//Lambda表达式
usePrintable(i -> System.out.println(i));//999
//方法引用
usePrintable(System.out::println);//999
}
private static void usePrintable(Printable printable) {
printable.print(999);
}
}
Lambda表达式支持的方法引用
引用类方法
- 格式:
类名::静态方法
- 范例:
Inteager::parseInt
public class ConvertableDemo {
public static void main(String[] args) {
//Lambda表达式
useConvertable((String s ) -> Integer.parseInt(s));//666
//方法引用
useConvertable(Integer :: parseInt);//666
//Lambda表达式被应用类方法代替时,它的形式参数全部传递给静态方法作为参数
}
private static void useConvertable(Convertable convertable) {
System.out.println(convertable.convert("666"));
}
}
引用对象的实例方法
格式范例:
- 创建对象:
PrintUpper printUpper1 = new PrintUpper();
- 引用对象的实例(成员)方法:
userUpperable(printUpper1 :: printStringUpper);
public class UpperableDemo {
public static void main(String[] args) {
PrintUpper printUpper = new PrintUpper();
//Lambda表达式
userUpperable((String string) -> printUpper.printStringUpper(string));
PrintUpper printUpper1 = new PrintUpper();
//引用对象的实例(成员)方法
userUpperable(printUpper1 :: printStringUpper);
//Lambda表达式被对象的实例方法代替时,它的形式参数全部传递给该方法作为参数
}
private static void userUpperable(Upperable upperable) {
upperable.toUpper("hello word");
}
}
引用类的实例方法
- 格式:
类名::类的实例/成员方法);
- 范例:
String::substring
public static void main(String[] args) {
//public String substring(int beginIndex, int endIndex),返回beginIndex和endIndex之间的字串
//Lambda表达式
useMyStringable((String s, int x,int y) -> s.substring(x,y));
//引用类的实例方法
useMyStringable(String::substring);
//Lambda表达式被类的实例方法代替时,第一个形式参数作为调用者,其余的形式参数全部传递给该方法作为参数
}
private static void useMyStringable(MyString myString) {
String result = myString.mySubString("hello", 1, 3);
System.out.println(result);
}
}
引用构造器(引用构造方法)
- 格式:类名::new
- 范例:Student::new
public class StudentBuildeDemo {
public static void main(String[] args) {
//Lambda表达式
useStudentBuilderable((String name,int age) -> {return new Student(name,age);});
//引用构造器
useStudentBuilderable(Student::new);
//Lambda表达式被构造器代替时,它的形式参数全部传递给构造器/构造方法作为参数
}
private static void useStudentBuilderable(StudentBuilder studentBuilder) {
Student student = studentBuilder.buildStudent("张三", 18);
System.out.println(student.getName()+","+student.getAge());
}
}