本文已参与「新人创作礼」活动,一起开启掘金创作之路。
什么是增强for?
首先需要说明一点,增强for指的就是for-each或者称之为for...in。所谓的增强不是真的就是最好的。就比如说,老婆饼中都带有老婆两个字,那么买老婆饼送老婆吗?再比如有个顾客点了一份鱼香肉丝,什么鱼香肉丝里面没有鱼?然后顾客不给钱,你懂我意思吧。写到这又想起来一个段子:服务员问:先生,您需要特殊服务吗?顾客(想了想,来一个呗):给我整一个呗。接着来了一个男服务员:先生,我的服务就是特殊服务。顾客:* ***你个 。
这里的‘ 老婆**’,‘** 鱼**’,‘** 特殊**’不都是表象吗?个人认为所谓的增强其实指的是可以让程序员写代码时更简单,写更少的代码,完成同样的功能。一般称之为语法糖。所以并不是所有场景下都是增强for最牛批!**
增强for循环(for-each/for...in):可以迭代数组和集合,取出其中的元素。
语法:
for(元素类型 变量 : 数组/Iterable对象){
//TODO
}
复制代码
在大部分初学者的脑子里的增强for就是用来遍历数组跟集合的。这是没有错的,但是不够准确。在我看来,集合只是实现了Iterable接口。
- 因为List和Set是Collection接口的子接口,而Collection接口继承了Iterable接口,所以针对于List和Set可以使用for-each,而Map不行。从下图不难看出他们的关系
- 在底层对于数组来说:底层依然使用普通for循环迭代数组,使用数组的索引来获取每一个元素。对于Iterable对象来说,底层依然使用迭代器(Iterator)
for-each是怎么工作的呀
先看代码然后来一个总结。
public class ForEachTest {
public static void main(String[] args) {
doArray();
doIterable();
}
// 使用foreach遍历数组
public static void doArray() {
String[] arr = new String[] {"A","B","C","D"};
for (String str : arr) {
System.out.println(str);
}
}
// 使用foreach遍历集合(Iterable对象)
public static void doIterable() {
Set set = new HashSet();
set.add("A");
set.add("B");
set.add("C");
set.add("D");
for (Object obj : set) {
System.out.println(obj);
}
}
}
复制代码
好像看着没啥问题,接下来我们来看看庐山真面目。
学习一定要对比着学习,这个地方我觉得整容公司跟减肥公司做的最好,减肥前什么样,减肥后什么样。你懂我意思吧,手动狗头!
从上图我们可以知道,增强for操作数组,底层实现是普通for循环,通过下标取值。增强for操作Iterable对象时,底层是使用了迭代器,而不涉及下标。
并发修改异常分析
首先先上源代码,我一贯使用代码块包裹代码,目的是如果阅读者有需要就不需要对着图片打。但是不太美观,多多见谅。
public class ForeachIteratorTest {
public static void main(String[] args) {
CartItem item1 = new CartItem("苹果8",1111,10);
CartItem item2 = new CartItem("苹果8P",2222,15);
CartItem item3 = new CartItem("苹果11",3333,20);
// 统计价格
// Double ret = getTotalPrice(item1,item2,item3);
// System.out.println(ret);
// 筛选价格
List list = new ArrayList();
list.add(item1);
list.add(item2);
list.add(item3);
// List items = filter1(list);
List items = filter2(list);
System.out.println(items);
}
// 筛选售价在2000以上的手机方法1
public static List filter1(List items) {
for (Object obj : items) {
CartItem item = (CartItem)obj;
if(item.getPrice()<2000) {
items.remove(item);
}
}
return items;
}
// 筛选售价在2000以上的手机方法2
public static List filter2(List items) {
for(Iterator it=items.iterator();it.hasNext();) {
CartItem item = (CartItem) it.next();
if(item.getPrice()<2000) {
it.remove();
}
}
return items;
}
// 求出购买所有商品所需的总价格
private static Double getTotalPrice(CartItem...items) {
Double ret = 0.0;
for(int i = 0; i<items.length;i++) {
CartItem item = items[i];
ret += item.getPrice() * item.getNum();
}
// for(CartItem item:items) {
// ret += item.getPrice() * item.getNum();
// }
return ret;
}
}
复制代码
假设我这边有一个需求,计算出所有手机的总价,那么我们有几种方式呢? 来看看吧
这两种方式都能够输出正确答案,虽然实现方式不同,但是他们在操作数据时,只是遍历数据,并没有删除数据之类的操作。上面这句话现在可能看不懂,正常滴,这是为了更好的理解下面的并发修改异常
假设我现在又有一个需求:筛选出价格大于2000的手机。
- 那么这边给出两种方式,且看方式一,这里发现运行后出现了一个异常,这个异常就是重点了,它叫并发修改异常。
- 方式二是可以正常输出结果的,这里为了简洁就不放图了
接下来看个图详细了解一下产生原因与解决办法。
写该文的目的有两个,其一是为了复习,其二是增强for在实际开发中也是经常使用的,而它存在的并发修改异常经常被人忽视。