一.示例代码
package lambda.examples._02;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class App {
List<Apple> getAppleList() {
List<Apple> list = new ArrayList<Apple>();
list.add(new Apple("green", 100));
list.add(new Apple("red", 150));
list.add(new Apple("green", 50));
return list;
}
public void test() {
List<Apple> list = getAppleList();
list.sort(Comparator.comparing(Apple::getWeight));
list.forEach(System.out::println);
}
public static void main(String[] args) {
new App().test();
}
}
class Apple {
private String color;
private int weight;
public Apple(String color, int weight) {
super();
this.color = color;
this.weight = weight;
}
@Override
public String toString() {
return "Apple [color=" + color + ", weight=" + weight + "]";
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
二.代码分析
输出如下:
Apple [color=green, weight=50]
Apple [color=green, weight=100]
Apple [color=red, weight=150]
在test方法中我们使用了java8中的新特性lambda表达式,
list.sort()需要传入一个Comparator接口的实现类,在java8之前我们通常使用匿名内部类实现,类似这样
list.sort(new Comparator<Apple>() {
@Override
public int compare(Apple a, Apple b) {
return a.getWeight() > b.getWeight() ? 1 : (a.getWeight() < b.getWeight() ? -1 : 0);
}
});
可以看出来其实有用的就一行代码,还要写那么多,所以对于这种只有一个抽象方法的接口我们称之为函数式接口,我们直接用lambda表达式实现,代码如下:
list.sort((a, b) -> a.getWeight() > b.getWeight() ? 1 : (a.getWeight() < b.getWeight() ? -1 : 0));
分析下什么意思,sort可以接受Comparator类型的接口实现类,Comparator是一个函数式接口,他的抽象方法是
@Override
public int compare(Apple a, Apple b) {
return a.getWeight() > b.getWeight() ? 1 : (a.getWeight() < b.getWeight() ? -1 : 0);
}
我们简写为
(a, b) -> a.getWeight() > b.getWeight() ? 1 : (a.getWeight() < b.getWeight() ? -1 : 0)
即可
->意为goto,前面的是方法的参数,后面是结果,如果只有一行就不写return,否则需要用{}括起来,并且return返回值,例如:
list.sort((a, b) -> {
if (a.getWeight() > b.getWeight())
return 1;
if (a.getWeight() < b.getWeight())
return -1;
return 0;
});
这里ab我们并不需要写类型,编译器会根据list的类型做推断
三.lambda如何实现
代码如下:
package lambda.examples._02;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class App {
List<Apple> getAppleList() {
List<Apple> list = new ArrayList<Apple>();
list.add(new Apple("green", 100));
list.add(new Apple("red", 150));
list.add(new Apple("green", 50));
return list;
}
public void test() {
List<Apple> list = getAppleList();
list.sort(new Comparator<Apple>() {
@Override
public int compare(Apple a, Apple b) {
return a.getWeight() > b.getWeight() ? 1 : (a.getWeight() < b.getWeight() ? -1 : 0);
}
});
list.sort((a, b) -> a.getWeight() > b.getWeight() ? 1 : (a.getWeight() < b.getWeight() ? -1 : 0));
list.forEach(System.out::println);
}
}
class Apple {
private String color;
private int weight;
public Apple(String color, int weight) {
super();
this.color = color;
this.weight = weight;
}
@Override
public String toString() {
return "Apple [color=" + color + ", weight=" + weight + "]";
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
package lambda.examples._02;
import java.io.IOException;
public class OtherApp {
public static void main(String[] args) throws IOException {
new App();
System.in.read();
}
}
现在用OtherApp的main方法初始化一个App类型的对象(这是为了加载App类),然后阻塞住查看字节码
java -classpath "%JAVA_HOME%/lib/sa-jdi.jar" sun.jvm.hotspot.HSDB
jps查看pid
使用hsdb attch 4744
打开Tools -> Class Brower
搜索App
查看class,发现其中有一个方法叫
private static [synthetic] int lambda$0(lambda.examples._02.Apple, lambda.examples._02.Apple)@0x000000001da80b80;
synthetic表示这是编译器生成的方法
所以说lambda语句会在所在的类被加载时,被jvm解析为该类中的一个private static 方法,接收lambda语句中的参数并且返回 lambda语句 -> 后面的结果(如果有返回值)
Create .class File
执行
javap -c -p App.class
结果如下:
Compiled from "App.java"
public class lambda.examples._02.App {
public lambda.examples._02.App();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
.
.
.
略
.
.
.
private static int lambda$0(lambda.examples._02.Apple, lambda.examples._02.Apple);
Code:
0: aload_0
1: invokevirtual #72 // Method lambda/examples/_02/Apple.getWeight:()I
4: aload_1
5: invokevirtual #72 // Method lambda/examples/_02/Apple.getWeight:()I
8: if_icmple 15
11: iconst_1
12: goto 31
15: aload_0
16: invokevirtual #72 // Method lambda/examples/_02/Apple.getWeight:()I
19: aload_1
20: invokevirtual #72 // Method lambda/examples/_02/Apple.getWeight:()I
23: if_icmpge 30
26: iconst_m1
27: goto 31
30: iconst_0
31: ireturn
}
可以清晰的看到我们在lambda语句里定义的逻辑
所以
lambda语句会在类被jvm加载时解析为该类的private static 方法随之初始化