说来挺惭愧的,JDK8已经出来这么多年,在实际项目中却很少真正使用Lambda表达式。其实工作中的项目很早就从开发、测试、生产,全面使用JDK8+Tomcat8了。
所以看来是时候要重新认识下这个奇怪的东西。
没错,当第一次看到Lambda表达式时,我就认为这是个奇怪的东西,->
写法让我感觉这是在写其它语言,说好的一切皆对象呢?
表达式语法
这是Lambda表达式的基本语法:
(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
statment1;
statment2;
//......
return statmentM;
}
参数列表是一个逗号分隔的形式参数列表,这些参数与功能接口中单一方法的形式参数相对应。指定参数类型是可选项;如果未指定参数类型,将从上下文推断。参数列表必须用括号括起来,但当指定的单一参数不带参数类型时除外;指定单一形式参数时可以不带括号。如果功能接口方法不指定任何形式参数,则必须指定空括号。
语句块必须包含在大括号内,除非语句块是一个方法调用语句。
举个简单例子
对于无参无返回值,可以有如下写法:
public interface TestIntf {
public void sayHello();
}
// -> 前的一对小括号和后面的一对大括号都不能去掉。
TestIntf intf = () -> {System.out.println("HelloWorld!!!");};
intf.sayHello();
对于有参有返回值,可以有如下写法:
public interface TestIntf {
public String sayHello(String word);
}
// 完整写法
TestIntf intf = (String word) -> {return "Hello " + word;};
// 参数word的类型可以推断时,可以去掉类型定义:
TestIntf intf = (word) -> {return "Hello " + word;};
// 甚至当参数只有一个时,可以去掉左边的小括号:
TestIntf intf = word -> {return "Hello " + word;};
// 右侧的方法体只有一个表达式时,可以去掉大括号,甚至连return都可以不要:
TestIntf intf = word -> "Hello " + word;
变量作用域
Lambda表达式内部可以访问外部的变量,但需要注意:
局部变量无论是在Lambda表达式主体中声明,还是在封闭作用域中声明,使用之前都必须先初始化。如:
interface TestIntf {
public String sayHello(String word);
}
public class App {
public static void main(String[] args) {
String str;
TestIntf intf = (String word) -> {
System.out.println(str); // 编译失败,提示str变量未被初始化。
return "Hello " + word;
};
}
}
Lambda表达式不会定义新的作用域;Lambda表达式的作用域与封闭作用域相同。如:
interface TestIntf {
public String sayHello(String word);
}
public class App {
public static void main(String[] args) {
String str = "word";
TestIntf intf = (String word) -> {
String str = ""; // 编译失败,提示str变量重复定义了。
return "Hello " + word;
};
}
}
而且也不能修改外部变量:
interface TestIntf {
public String sayHello(String word);
}
public class App {
public static void main(String[] args) {
String str = "word";
TestIntf intf = (String word) -> {
str = "word!!!"; // 编译报错:Local variable str defined in an enclosing scope must be final or effectively final
return "Hello " + word;
};
}
}
当然,引用变量是可以通过内部方法达到数据修改的。
interface TestIntf {
public String sayHello(StringBuilder word);
}
public class App {
public static void main(String[] args) {
StringBuilder str = new StringBuilder("word");
TestIntf intf = (StringBuilder word) -> {
word.append("!!!");
return "Hello " + word;
};
System.out.println(intf.sayHello(str)); // Hello word!!!
System.out.println(str); // word!!!
}
}
Lambda表达式中的this
在Lambda表达式中this引用的不是Lambda表达式对象,而是声明它的外部对象:
interface TestIntf {
public String sayHello();
}
public class App {
public void test() {
TestIntf intf = () -> "Hello " + this.getClass().getSimpleName();
System.out.println(intf.sayHello());
}
public static void main(String[] args) {
App app = new App();
app.test(); // Hello App
}
}
参考文章
https://www.oracle.com/techne...