增强for循环:增强到底增强到哪里了?

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

什么是增强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在实际开发中也是经常使用的,而它存在的并发修改异常经常被人忽视。

猜你喜欢

转载自juejin.im/post/7102770111936741413