随着java8的普及,lambda表达式的书写日益增多。咱们看下面一个例子: 编程有一条原则如下:
避免创建不必要的对象:最好能重用对象,而不要在每次需要的时候就创建一个相同功能的新对象。
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
// 1、匿名内部类
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
//2、lambda表达式
Collections.sort(names, (a, b) -> b.compareTo(a));
如果比较器,如果我们需要使用多次,其实可以在外面定义一个比较器对象,然后直接使用就成,不用每次都new一个内部类吧?
那么问题来了:是不是每次排序都创建了一个新的Comparator对象,导致性能降低?那么还主张使用Lambda表达式吗?
根本原因: Lamdba表示根本就不是匿名内部类的语法糖,也就是说Lambda表达式底层实现不是匿名内部类的实现方式,他们其实两个东西。 证明如下: 匿名内部类其实在编译的时候会生成一个类文件,命名以ClassName$数字的方式,所以要是Lamdba表达式底层也是由匿名内部类的方式实现的话,那肯定也会生成一个同样类似的内文件 所以我们简单把你的例子分别写在不同包下面的类,再在来检查编译后的效果 匿名内部类实现 InnerTest
这时候我们编译后,可以看到两个class文件
我们再看看lambda表达式的例子lambda表达式 LambdaTest
然而class文件只有一个:LambdaTest.class 所以,真像永远只有一个:很显然lambda和匿名内部类不是同一个东西
具体的,以后有时间会专门写博文分享,但是lambda的大致思路如下:
invokedynamic
指令(java7 JVM中增加了一个新的指令)调用,同时呢也生成了一个对应的BootstrapMethod
invokedynamic
指令,该指令引导调用LambdaMetafactory.metafactory
方法,该方法返回一个CallSite
实例MethodHandle
实例,而这个MethodHandle
实例会调用到1中生成的静态方法,在上面的例子就是lambda$main$0
这个方法,完成整个lamdba表达式的使用其实可以看到lamdba表达式在某种意义上的确比匿名内部类好很多,可读性还是大优势~哈哈,我要说大势,是因为lamdba表达式后续可以优化的空间更广,反正我是在java中用惯了,相当喜欢
有许许多多关于 Java 8 中流效率的讨论,其中最著名要属这篇译文了:Java8 Lambda表达式和流操作如何让你的代码变慢5倍 看标题是不是感觉有点不敢用lambda了呢?我觉得还是不能人云亦云,还是自己测试一把吧~~~~
下面Demo用稍微真是一点的场景测试,而不是单纯的数字计算,这样应该更具有说服力些~
public class Person {
public String name;
public Integer age;
// 省略get set方法
}
// Main方法测试
public static void main(String[] args) {
int count = 10000;
List<Person> personList = new ArrayList<>();
for (int i = 0; i < count; i++) {
personList.add(new Person("fsx", 18 + i));
}
Instant start = Instant.now();
//getAgesWithLambda(personList);
getAges(personList);
System.out.println("耗时:" + Duration.between(start, Instant.now()).toMillis() + "ms");
}
// 使用lambda表达式方式~
private static List<Integer> getAgesWithLambda(List<Person> personList) {
return personList.stream().map(Person::getAge).collect(Collectors.toList());
}
// 使用普通方式~
private static List<Integer> getAges(List<Person> personList) {
List<Integer> ages = new ArrayList<>();
for (Person person : personList) {
ages.add(person.getAge());
}
return ages;
}
当count=1000时:getAges(1ms) getAgesWithLambda(70ms) 当count=10000时:getAges(2ms) getAgesWithLambda(71ms) 当count=100000时:getAges(10ms) getAgesWithLambda(76ms) 当count=1000000时:getAges(21ms) getAgesWithLambda(101ms) 当count=10000000时:getAges(619ms) getAgesWithLambda(738ms)
从上面测试,我得出如下两个结论,不知道小伙伴同意不?
所以我坚持:lambda表达式,非常推荐使用。毕竟我认为代码永远是人看得懂看得舒服才是第一位,其次才是机器~ (虽然量不大的时候lambda比普通方式差,但是既然量都不大怎么可能会有性能问题呢?完全可以忽略嘛~)
说明:测试机器为I5普通pc笔记本,各位不同机器上测试效果(耗时)上可能会有出入~