Java中List<E>对象赋值操作问题

业务需求是:取2个集合中的交集对象并返回。如下代码,busMap中key值和stocks中Map中的key值相等的对象则返回继续操作,也就是说剔除stocks中的不存在于busMap中的对象,就是一个过滤操作。

实现代码 ① bug版 报错: java.util.ConcurrentModificationException ; at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) ; at java.util.ArrayList$Itr.next(ArrayList.java:831) ; 原因: forEach实现是采用Iterator实现的,而remove操作不能在Iterator下操作,所以报错,具体原因是Iterator遍历开始前,会对该对象生成一个改变前的标记值,在进行map.remove操作的时候,改变了这个值,导致循环结束后,程序检查初始标记和结束标记不一致,就报错了。而使用Iterator.remove操作时,它同时会修改这个初始标记值,一直让这个初始标记值等于当前标记值,程序结束后判断两者相等,就不会有异常!

private static void  appendStock(Map<String,Object> busMap, List<Map<String, Object>> stocks , String key){
	if (stocks != null)
		for (Map<String,Object> s : stocks ) {
			boolean b = false;
			for (Map.Entry<String, Object> e : busMap.entrySet()) {
				if (s.get("stock_code") != null)
					if (s.get("stock_code").toString().equals(e.getKey())) {
						b = true;
						break;
					}
			}
			if ( !b ){
				stocks.remove(s);
			}
		}
}

代码② 修正foreach中remove异常,bug版 bug: 执行该方法后,stocks并没有改变!! 原因: 对象引用传递导致。这个stocks是形参,他会复制外界的引用,也就是说这个stocks和外界的stocks不是同一个引用,但是指向同一个内存地址。所以只要stocks指向的对象修改了,外界对象(同一个对象)也随着修改。但是这个stocks是形参,是一个新的变量,生命周期只存在于该方法体内,所以代码最后stocks = newStocks没有任何意义,因为调用方法结束,newStocks和stocks都会被GC干掉,外界对象引用地址是没有发生一点变化的。唯独变化的就是外界对象的另一个引用(就是方法中的stocks)在方法中对其的修改!这就告诉我们一个道理:在设计方法是void还是return的时候,要看看外界引用是否需要被重新赋值。如果需要,则return,否则void。也就是void方法只是对外界对象的堆内存操作。return对象多了可以对外界对象引用的修改优势,但是这要加大开销!

private static void  appendStock(Map<String,Object> busMap, List<Map<String, Object>> stocks , String key){
	if (stocks != null)
		List<Map<String,Object>> newStocks =  Lists.newArrayList();  // 构建新对象保存交集数据
		for (Map<String,Object> s : stocks ) {
			for (Map.Entry<String, Object> e : busMap.entrySet()) {
				if (s.get("stock_code") != null)
					if (s.get("stock_code").toString().equals(e.getKey())) {
						newstocks.add(s);
						break;
					}
			}
		}
		stocks = newStocks;
}

代码③ 绕开改变外界引用,稳定版 采用Iterator来删除元素,摒弃拷贝,从而不入浅拷贝的坑

private static void  appendStock(Map<String,Object> busMap, List<Map<String, Object>> stocks , String key){
	if (stocks != null && stocks.size() > 0) {
		Iterator<Map<String, Object>> iterator = stocks.iterator();
		while (iterator.hasNext()) {
			Map<String, Object> s = iterator.next();
			if (s.get("stock_code") != null) {
				String stockCode = String.valueOf(s.get("stock_code"));
				if ( !busMap.containsKey(stockCode)) {
					iterator.remove();
				}
			}
		}
	}
}

代码④返回引用赋值给外界引用,稳定版

	private static List<Map<String, Object>>  appendStock(Map<String,Object> busMap, List<Map<String, Object>> stocks , String key){
	if (stocks != null)
		List<Map<String,Object>> newStocks =  Lists.newArrayList();  // 构建新对象保存交集数据
		for (Map<String,Object> s : stocks ) {
			for (Map.Entry<String, Object> e : busMap.entrySet()) {
				if (s.get("stock_code") != null)
					if (s.get("stock_code").toString().equals(e.getKey())) {
						newstocks.add(s);
						break;
					}
			}
		}
		return newStocks;
}