Lambda 表达式
创建线程对比
一般写法:
public class LambdaTest implements Runnable {
public static void main(String[] args) {
new Thread(new LambdaTest()).start();
}
@Override
public void run() {
System.out.print("start");
}
}
lambda表达式写法
public class LambdaTest {
public static void main(String[] args) {
new Thread(()->{
System.out.print("start");
}).start();
}
}
说明:
lambda中
- ()里没有内容,可以看作形参,如果有参数,可以用逗号隔开。
- -> 指要做的事情
- {} 指代码块,可以理解为我们要做的内容。
Lambda表达式练习
使用前提:
- 有一个接口
- 接口只有一个抽象方法
无参写法
同理,我们可以高仿线程的创建进行练习;
首先创建一个接口
public interface ILambdaTest {
void start();
}
我们想要通过这个接口做一些事情的话,一般的写法如下:
创建一个实现类
public class ILambdaImpl implements ILambdaTest {
@Override
public void start() {
System.out.print("start");
}
}
main 进行调用
public class LambdaTest {
public static void main(String[] args) {
ILambdaTest test = new ILambdaImpl();
test.start();
}
}
如此写法相对复杂
Lambda写法对比
public class LambdaTest {
public static void main(String[] args) {
new LambdaTest().start(()->{
System.out.print("start");
});
}
private void start(ILambdaTest test){
test.start();
}
}
有参写法
如果接口有参数的话,在() 中用逗号隔开就好,另外传入的参数类型是可以省略的。
public interface ILambdaTest {
String start(String s,String y);
}
例如:
// 写法1
public class LambdaTest {
public static void main(String[] args) {
LambdaTest t = new LambdaTest();
String s= t.start((String x,String y)->{
System.out.println(x+y);
return "lambda start";
});
System.out.println(s);
}
private String start(ILambdaTest test){
return test.start("sss","yyyy");
}
}
// 写法2 省略类型
public class LambdaTest {
public static void main(String[] args) {
LambdaTest t = new LambdaTest();
String s= t.start(( x, y)->{
System.out.println(x+y);
return "lambda start";
});
System.out.println(s);
}
private String start(ILambdaTest test){
return test.start("sss","yyyy");
}
}
有参省略写法
这是在两个参数的时候,如果只有一个参数的时候,括号都可以省略
例如:
public interface ILambdaTest {
String start(String s);
}
省略写法
public class LambdaTest {
public static void main(String[] args) {
LambdaTest t = new LambdaTest();
String s= t.start(x->{
System.out.println(x);
return "lambda start";
});
System.out.println(s);
}
private String start(ILambdaTest test){
return test.start("sss");
}
}
如果代码块也只有一条的情况下,大括号,分号也可以省略
例如:
public interface ILambdaTest {
void start(String s);
}
public class LambdaTest {
public static void main(String[] args) {
LambdaTest t = new LambdaTest();
t.start(x->System.out.print("yyy"));
}
private void start(ILambdaTest test){
test.start("sss");
}
}
如果有值需要return时需要注意
如果有return 时 并且只有一行代码块去掉分号、大括号的同时 ,return也要去掉
例如:
public interface ILambdaTest {
String start(String s);
}
如下写法;
public class LambdaTest {
public static void main(String[] args) {
LambdaTest t = new LambdaTest();
t.start(x->x);
}
private void start(ILambdaTest test){
test.start("sss");
}
}
lambda表达式和匿名内部类的区别
使用限制不同
- 匿名内部类可以是接口,可以是抽象类,也可以是具体类
- Lambda表达式只能是接口,而且接口只能有一个方法
- 如果在接口中有多个方法的话,只能使用匿名内部类的方式
例如:有抽象类,接口,和普通类
public abstract class AbstractLambdaTest {
abstract String start(String str);
}
public interface ILambdaTest {
String start(String s);
}
public class ILambdaImpl implements ILambdaTest {
@Override
public String start(String s) {
System.out.print(s);
return "";
}
}
有如上内容,我们同时用匿名内部类的方式调用
public class LambdaTest {
public static void main(String[] args) {
interfaceTest(new ILambdaTest() {
@Override
public String start(String s) {
return "start";
}
});
CLassTest(new ILambdaImpl(){
@Override
public String start(String s) {
return "start";
}
});
AbstractLambdaTest(new AbstractLambdaTest() {
@Override
String start(String str) {
return "str";
}
});
}
private static void interfaceTest(ILambdaTest test){
test.start("sss");
}
private static void CLassTest(ILambdaImpl test){
test.start("sss");
}
private static void AbstractLambdaTest(AbstractLambdaTest test){
test.start("sss");
}
}
如上,用匿名内部类的方式是可以通过编译的;
但是用Lambda表达式的方式无法通过编译
public class LambdaTest {
public static void main(String[] args) {
// 这个可以通过编译,因为这是个接口
interfaceTest((s)->{
return "";
});
//无法通过编译
CLassTest((s)->{
return "";
});
//无法通过编译
AbstractLambdaTest((s)->{
return "";
});
}
private static void interfaceTest(ILambdaTest test){
test.start("sss");
}
private static void CLassTest(ILambdaImpl test){
test.start("sss");
}
private static void AbstractLambdaTest(AbstractLambdaTest test){
test.start("sss");
}
}
此次实验再次说明在使用Lambda表达式的前提是,在接口中, 有且只有一个方法的时候。
字节码文件不同
在使用匿名内部类的时候,会单独的生成一个.class字节码文件,Lambda表达式在运行的时候,会在运行的时候动态生成。
总结
有参总结:
- 参数类型可以省略不写,但是多个参数时,要么不省略,要么同时省略;
- 如果参数只有一个,小括号可以省略
- 如果代码块只有一条,大括号和分号可以省略,如果有return 也要省略。
再次强调:
- 使用Lambda 必须要有接口,接口中只能有一个抽象方法
- Lambda 使用时必须要有上下文环境,才能到处Lambda对应的接口; #1
1.上面第二句话可能不好理解。在此解释
例如:
public class LambdaTest {
public static void main(String[] args) {
new Thread(()->{
System.out.print("start");
}).start();
}
//如上写法 中的 ()->{Sysout.out.print("start")}
//其实是代替了new Runable(){public void run(){}}
// 如果没有在new Thread()中,那这个语句就什么都不是。就无法推导 出是什么
public static void main(String[] args) {
()->{System.out.print("start");}
}
// 正确的写法如下
public static void main(String[] args) {
Runnable runnable = ()->System.out.print("start");
new Thread(runnable).start();
}
}