概述
现在,很多同学已经接受并熟悉了 Java 的 Lamda 写法,但可能有些同学还是一头雾水。
这里,我抛砖引玉,来对 Java Lamda 写法做一个简单的介绍:
-
首先 Lamda 写法的固定格式为:参数 -> 语句块
-
另外 Lamda 语法是出现在Java8及其以后的,Java8以前是不涉及的,所以JDK1.7及其以前版本这种写法编译是会被报错的。
优势
那么Lamda 写法有哪些优势呢?
-
首先,他简化了代码,将以前很多行的代码简化为几行或者一行,使得代码看上去更加的简介;
-
另外,Lamda 算法对并行运算非常具有优势,某些实现用 Lamda 方式会更加高效。
示例
如果一个接口只有一个实现方法,我们称这种接口叫做函数式接口。
那么我们通常会以匿名内部类的方式去实现。
比如:我们常用的多线程去异步实现某个功能的时候,常常会使用如下方式:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("异步功能实现");
}
}).start();
这里的 Runable 接口就一个run() 实现方法,源码如下图:
那么这种条件下,就可以简化为 Lamda 写法,具体效果如下:
new Thread(() -> System.out.println("异步实现功能")).start();
我们可以看见:Lamda 写法的代码量已经浓缩为了一行,确实简洁了不少。
释义
那么如何理解上面这句 Lamda 写法呢?
(1)我们可以看到,变化的只是参数接口匿名实现类的写法,外面外并未有任何变化;
(2)由于 Thread 类里面就一个以接口为参数的方法,所以省去了接口名 Runable;
(3)由于 Ruanble 接口里面就一个 run() 方法定义,故而省去了方法名;
(4)由于 run() 方法定义里未有任何参数,故而 Lamda 写法就只有以一个 () 开头了;
(5) 中间的箭头 -> 是 Lamda 标识符,读作 “goes to”;
(6)箭头后面就是实现方式了,这个同以前代码实现。
拓展示例
示例1
那么,当一个接口的唯一方法涉及多个参数,此时 Lamda 写法又该怎么样呢?
我们不妨创建一个 MyService,里面包含一个带有参数的方法定义:
public interface MyService {
public void say(String name);
}
然后我们创建一个 Test 类,并在类里面添加一个该接口为参数的 test() 方法,以及主方法进行测试:
Java 8 以前的写法:
public class Test {
public static void main(String[] args){
test(new MyService() {
@Override
public void say(String name) {
System.out.println("hello : " + name);
}
});
}
public static void test(MyService service) {
service.say("jack");
}
}
程序运行结果为如下所示:
Java 8 Lamda 写法:
public class Test {
public static void main(String[] args){
test((name) -> System.out.println("hello : " + name));
}
public static void test(MyService service) {
service.say("jack");
}
}
运行结果,同样为:
经过上面两个例子,我们已经证实了,两种写法的运行效果完全是可以等价的,Lamda 写法看起来也更简洁。
另外,当参数只有一个的时候,参数的括号也可以省去不写,例如,上面的 Lamda 写法还可以进一步简写:
test(name -> System.out.println("hello : " + name));
同理,如果接口的方法有多个参数的时候,Lamda 参数括号里也需要传递多个参数。
示例2
我们将接口里面的 say(String name) 方法,增加一个参数 age,改为如下:
public interface MyService {
public void say(String name, int age);
}
那么对应的方法调用就成为了如下:
Java 8 前写法:
public class Test {
public static void main(String[] args){
test(new MyService() {
@Override
public void say(String name, int age) {
System.out.println("hello : " + name + ", I am " + age);
}
});
}
public static void test(MyService service) {
service.say("jack", 28);
}
}
Java 8 Lamda 写法:
public class Test {
public static void main(String[] args){
test((name, age) -> System.out.println("hello : " + name + ", I am " + age));
}
public static void test(MyService service) {
service.say("jack", 28);
}
}
两种写法的输出结果都是:
可以看到,随着接口方法 say() 里的参数增加,Lamda 参数括号里面的参数也相应增加。
同理,当 Lamda 语句块里面只有一条语句的时候,我们可以通常省略语句块符号{},如上面的 Lamda语句:
test((name, age) -> System.out.println("hello : " + name + ", I am " + age));
但如果涉及多条语句的时候,就需要增加语句块 {}了,比如我们将 name 和 age 分别打印的话,则对应的 Lamda 写法为:
test((name, age) -> {
System.out.println("My name is"+ name);
System.out.println("I am "+ age);
});
变量作用域
方法变量
首先,Lamda 语句中引用外层方法中的变量的时候,是不允许修改其变量值的,具体什么意思呢?我们不妨接着往下看。
我们在上一步中的方法增加一个变量;
然后我们在 Lamda 语句块中将其值修改下:
可以看到:编译器这时候报了错,说明其值是不允许被修改的:
这就说明: Lamda 不允许修改所在外层方法里的变量;
类变量
然后,我们将变量的位置挪动下,将方法变量移动到为类的变量(这里由于方法是 static 的,所以我们为了能直接访问到变量,也加上 static 修饰)。
可以看到,这时编译器并未进行报错,说明 Lamda 语句块中是可以修改其类成员变量(final 修饰除外)。
我们运行程序:
可以看到,确实是我们修改后的值。
结尾语
上面所讲的主要是 Lamda 写法之匿名内部类,这是一个较为容易理解 Lamda 写法的入门,谢谢大家!