最近在使用java8提供的Lambda新特性,期间也踩了不少坑,这里记录一下
Lambda新特性–ForEach
java8以前,我们通常用对集合的循环都是一下几种(例子:累加)
public void test1() {
List<Integer> list = new ArrayList<>();
int sum = 0;
for (int i = 0;i <= list.size();i++){
sum += list.get(i);
}
}
//增强for循环
public void test2() {
List<Integer> list = new ArrayList<>();
int sum = 0;
for (Integer a : list){
sum += a;
}
}
//迭代器循环
public void test3() {
List<Integer> list = new ArrayList<>();
Iterator<Integer> it = list.iterator();
int sum = 0;
while (it.hasNext()){
sum += it.next();
}
}
日常开发中最常用的就是增强for循环了。而到了java8的Lambda表达式中,我自然而然的根据他的格式进行修改:
public void test() {
List<Integer> list = new ArrayList<>();
int sum = 0;
list.forEach(a -> {
sum += a;
});
}
发现他报错:Variable used in lambda expression should be final or effectively final,意思是不允许在Lambda表达式中修改使用的(外部)变量。
后来发现了有规避的方法但不推荐使用,即写一个方法,在循环中调用该方法。推荐使用 Lambda提供的Steam流的规约操作,java.util.stream包提供了各种通用的和专用的规约操作(例如sum、min和max)
public void test3() {
List<Integer> list = new ArrayList<>();
int sum = list.stream()
.mapToInt(e -> e)
.sum();
System.out.println(sum);
}
分析
使用lamdba表达式的时候,不能觉得只是for的变种语法而已…然后写代码依然按照for怎么循环怎么处理,这样是不对的,毕竟语法的书写方式总是跟它的设计方式是吻合的。
为什么要禁止修改外部变量?
由于这样的写法在多线程的情况下容易产生race condition竞态条件,导致结果不正确,除非我们能强制保证线程安全,这样引发的问题可能更多。
从设计者角度分析,java8提倡大家使用steam流,让大家习惯使用规约操作
总结
java8 Lambda 新特性在一定程度上提高的代码的稳定性和安全性,而与以往的版本相比,优化的部分并不是简单的套用,需要我一个“坑”一个“坑”的去踩。当然,大家在在日常开发中,可以根据实际情况进行选择。比如Lambda 的ForEach虽然稳定,但是在性能上比增强for循环稍微有所不足。
谢谢!!大家一起学习,有错之处,请指正!