- 浏览: 802647 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (360)
- Java (101)
- JPA/Hibernate (10)
- Spring (14)
- Flex/BlazeDS (37)
- Database (30)
- Lucene/Solr/Nutch (0)
- Maven/Ant (25)
- CXF/WebService (3)
- RPC/RMI/SOAP/WSDL (1)
- REST (6)
- TDD/BDD/JUnit (1)
- Servlet/JSP (2)
- AI/MachineLearning (3)
- Resource (1)
- 字符编码 (2)
- OOA/OOPS/UML (5)
- DesignPattern (8)
- 算法与数据结构 (11)
- Web&App Server (13)
- 并发&异步&无阻塞 (7)
- Entertainment (4)
- JavaScript/ExtJS (45)
- CodeStyle&Quality (1)
- svn/git/perforce (8)
- JSON (2)
- JavaScriptTesting (4)
- Others (6)
- RegularExpression (2)
- Linux/Windows (12)
- Protocal (2)
- Celebrities (1)
- Interview (1)
- 计算机语言 (1)
- English (2)
- Eclipse (5)
- TimeZone/时区 (1)
- Finance (1)
- 信息安全 (1)
- JMS/MQ (2)
- XSD/XML/DTD (3)
- Android (4)
- 投资 (3)
- Distribution (3)
- Excel (1)
最新评论
-
qdujunjie:
如果把m换成具体的数字,比如4或者5,会让读者更明白
m阶B树中“阶”的含义 -
java-admin:
不错,加油,多写点文章
关于Extjs的mixins和plugin -
xiehuaidong880827:
你好,我用sencha cmd打包完本地工程后,把app.js ...
ExtJS使用Sencha Cmd合并javascript文件为一个文件 -
KIWIFLY:
lwpan 写道inverse = "true&qu ...
Hibernate中什么时候使用inverse=true -
luedipiaofeng:
good
消除IE stop running this script弹出框
注意,这里的参考文章基本来自Effective Java和jdk源码
1)ConcurrentModificationException
当你用for each遍历一个list时,如果你在循环主体代码中修改list中的元素,将会得到这个Exception,解决的办法是:
1)用listIterator, 它支持在遍历的过程中修改元素,
2)不用listIterator, new一个新的list,copy old list content to new list, and then modify the new created list, in this way we can avoid such expception.
注意Collection中只有iterator,没有listIterator,List接口中才有listIterator.
请注意,listIterator的remove方法是不需要参数的,因为它是针对最近一次由next或previous获取的对象而言的.
void java.util.ListIterator.remove()
Removes from the list the last element that was returned by next or previous (optional operation). This call can only be made once per call to next or previous. It can be made only if ListIterator.add has not been called after the last call to next or previous.
事实上,不仅只有remove方法这样,ListIterator里面的add,set方法也是基于next和previous返回的结果的。详情可以参考jdk源代码。
扩展知识:
java.util.ConcurrentModificationException
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.
Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
java.util.ListIterator<E>
An iterator for lists that allows the programmer to traverse the list in either direction, modify the list during iteration, and obtain the iterator's current position in the list. A ListIterator has no current element; its cursor position always lies between the element that would be returned by a call to previous() and the element that would be returned by a call to next(). An iterator for a list of length n has n+1 possible cursor positions, as illustrated by the carets (^) below:
Element(0) ^ Element(1) ^ Element(2) ... Element(n-1)^cursor positions: ^
Note that the remove and set(Object) methods are not defined in terms of the cursor position; they are defined to operate on the last element returned by a call to next or previous().
This interface is a member of the Java Collections Framework.
2)关于clone以及Cloneable接口
Cloneable里面没有包含任何方法,它只是决定了Object中受保护的clone方法实现的行为:如果一个类实现了Cloneable, Object的clone方法就返回该对象的逐域拷贝,否则就抛出CloneNotSupportedException。这是接口的一种极端非典型的用法,不值得效仿。通常情况下,实现接口是为了表明类可以为它的客户做些什么。然而对应Cloneable接口,它改变了超类中受保护的方法的行为。
Best Practise:
1)最好不要去实现自己的clone方法,即不要去implement Cloneable接口,要想拷贝,自己可以写一个copy方法,所有的内容完全由自己控制。
2)如果一定要实现Cloneable,那么首先通过super.clone()获取到最初始的拷贝对象,然后去覆盖一些域,因为对list而言,通过super.clone()方法获得的拷贝对象只是在栈中新建了一个list引用变量,但是这个引用变量还是指向原来list中的成员的,即并没有在堆中新建list的成员。
先看一下Jdk1.6 中HashMap的clone方法源码:
java.lang.Cloneable
A class implements the Cloneable interface to indicate to the java.lang.Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class.
Invoking Object's clone method on an instance that does not implement the Cloneable interface results in the exception CloneNotSupportedException being thrown.
By convention, classes that implement this interface should override Object.clone (which is protected) with a public method. See java.lang.Object.clone() for details on overriding this method.
Note that this interface does not contain the clone method. Therefore, it is not possible to clone an object merely by virtue of the fact that it implements this interface. Even if the clone method is invoked reflectively, there is no guarantee that it will succeed.
3)Collections.copy
按如上方式用时,很容易得到"Source does not fit in dest" Exception,原因是copy方法里面会首先比较dest和src的size,而往往你新new的list的size是0,所以会报错。
为什么明明已经设置了长度为src.size,为什么还会出错!
后来打印出dest.size()才知道dest的长度为0,new ArrayList<Object>(src.size())表示的是这个List的容纳能力为src.size,并不是说dest中就有了src.size个元素。查看api才知 道,它的capacity(容纳能力大小)可以指定(最好指定)。而初始化时size的大小永远默认为0,只有在进行add和remove等相关操作 时,size的大小才变化。然而进行copy()时候,首先做的是将desc1的size和src1的size大小进行比较,只有当desc1的 size 大于或者等于src1的size时才进行拷贝,否则抛出IndexOutOfBoundsException异常。
可以通过下面的方法指定目标desc的大小
执行第一句后,desc 的size的大小是为srcList的size,其实它是对一个空数组的浅拷贝,虽然是一个Object类型的空数组,但是list里面只存储引用变量,所以list的size已经变化了,只是每个引用变量还没有指向具体的对象而已。
Collections.copy源码
4)Collections.copy() versus ArrayList(Collection<? extends E> c)
两者都是浅拷贝,只是对源list的元素进行拷贝,拷贝的只是引用。拷贝后两个list的元素(引用)不同,但是引用所指向的对象是一样的。即两个list的每个元素指向的还是同一内存。
you are right, 都是浅拷贝.
1)ConcurrentModificationException
当你用for each遍历一个list时,如果你在循环主体代码中修改list中的元素,将会得到这个Exception,解决的办法是:
1)用listIterator, 它支持在遍历的过程中修改元素,
2)不用listIterator, new一个新的list,copy old list content to new list, and then modify the new created list, in this way we can avoid such expception.
注意Collection中只有iterator,没有listIterator,List接口中才有listIterator.
ListIterator<FilterCriteriaVO> listIterator=filterVOs.listIterator(); int size=filterVOs.size(); for (int i=0; i<size; i++) { FilterCriteriaVO filterExpression=listIterator.next(); listIterator.remove(); listIterator.add(leg1TypeExpression); }
请注意,listIterator的remove方法是不需要参数的,因为它是针对最近一次由next或previous获取的对象而言的.
void java.util.ListIterator.remove()
Removes from the list the last element that was returned by next or previous (optional operation). This call can only be made once per call to next or previous. It can be made only if ListIterator.add has not been called after the last call to next or previous.
事实上,不仅只有remove方法这样,ListIterator里面的add,set方法也是基于next和previous返回的结果的。详情可以参考jdk源代码。
扩展知识:
java.util.ConcurrentModificationException
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.
Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
java.util.ListIterator<E>
An iterator for lists that allows the programmer to traverse the list in either direction, modify the list during iteration, and obtain the iterator's current position in the list. A ListIterator has no current element; its cursor position always lies between the element that would be returned by a call to previous() and the element that would be returned by a call to next(). An iterator for a list of length n has n+1 possible cursor positions, as illustrated by the carets (^) below:
Element(0) ^ Element(1) ^ Element(2) ... Element(n-1)^cursor positions: ^
Note that the remove and set(Object) methods are not defined in terms of the cursor position; they are defined to operate on the last element returned by a call to next or previous().
This interface is a member of the Java Collections Framework.
2)关于clone以及Cloneable接口
Cloneable里面没有包含任何方法,它只是决定了Object中受保护的clone方法实现的行为:如果一个类实现了Cloneable, Object的clone方法就返回该对象的逐域拷贝,否则就抛出CloneNotSupportedException。这是接口的一种极端非典型的用法,不值得效仿。通常情况下,实现接口是为了表明类可以为它的客户做些什么。然而对应Cloneable接口,它改变了超类中受保护的方法的行为。
Best Practise:
1)最好不要去实现自己的clone方法,即不要去implement Cloneable接口,要想拷贝,自己可以写一个copy方法,所有的内容完全由自己控制。
2)如果一定要实现Cloneable,那么首先通过super.clone()获取到最初始的拷贝对象,然后去覆盖一些域,因为对list而言,通过super.clone()方法获得的拷贝对象只是在栈中新建了一个list引用变量,但是这个引用变量还是指向原来list中的成员的,即并没有在堆中新建list的成员。
先看一下Jdk1.6 中HashMap的clone方法源码:
/** * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and * values themselves are not cloned. * * @return a shallow copy of this map */ public Object clone() { HashMap<K,V> result = null; try { result = (HashMap<K,V>)super.clone(); } catch (CloneNotSupportedException e) { // assert false; } result.table = new Entry[table.length]; result.entrySet = null; result.modCount = 0; result.size = 0; result.init(); result.putAllForCreate(this); return result; }
java.lang.Cloneable
A class implements the Cloneable interface to indicate to the java.lang.Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class.
Invoking Object's clone method on an instance that does not implement the Cloneable interface results in the exception CloneNotSupportedException being thrown.
By convention, classes that implement this interface should override Object.clone (which is protected) with a public method. See java.lang.Object.clone() for details on overriding this method.
Note that this interface does not contain the clone method. Therefore, it is not possible to clone an object merely by virtue of the fact that it implements this interface. Even if the clone method is invoked reflectively, there is no guarantee that it will succeed.
3)Collections.copy
List<Object> dest=new ArrayList<Object>(src.size()); //or List<Object> dest=new ArrayList<Object>(); Collections.copy(dest, src());
按如上方式用时,很容易得到"Source does not fit in dest" Exception,原因是copy方法里面会首先比较dest和src的size,而往往你新new的list的size是0,所以会报错。
为什么明明已经设置了长度为src.size,为什么还会出错!
后来打印出dest.size()才知道dest的长度为0,new ArrayList<Object>(src.size())表示的是这个List的容纳能力为src.size,并不是说dest中就有了src.size个元素。查看api才知 道,它的capacity(容纳能力大小)可以指定(最好指定)。而初始化时size的大小永远默认为0,只有在进行add和remove等相关操作 时,size的大小才变化。然而进行copy()时候,首先做的是将desc1的size和src1的size大小进行比较,只有当desc1的 size 大于或者等于src1的size时才进行拷贝,否则抛出IndexOutOfBoundsException异常。
可以通过下面的方法指定目标desc的大小
List<Object> values=new ArrayList<Object>(Arrays.asList(new Object[srcList.size()])); Collections.copy(values, srcList());
执行第一句后,desc 的size的大小是为srcList的size,其实它是对一个空数组的浅拷贝,虽然是一个Object类型的空数组,但是list里面只存储引用变量,所以list的size已经变化了,只是每个引用变量还没有指向具体的对象而已。
Collections.copy源码
/** * Copies all of the elements from one list into another. After the * operation, the index of each copied element in the destination list * will be identical to its index in the source list. The destination * list must be at least as long as the source list. If it is longer, the * remaining elements in the destination list are unaffected. <p> * * This method runs in linear time. * * @param dest The destination list. * @param src The source list. * @throws IndexOutOfBoundsException if the destination list is too small * to contain the entire source List. * @throws UnsupportedOperationException if the destination list's * list-iterator does not support the <tt>set</tt> operation. */ public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++) dest.set(i, src.get(i)); } else { ListIterator<? super T> di=dest.listIterator(); ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) { di.next(); di.set(si.next()); } } }
4)Collections.copy() versus ArrayList(Collection<? extends E> c)
两者都是浅拷贝,只是对源list的元素进行拷贝,拷贝的只是引用。拷贝后两个list的元素(引用)不同,但是引用所指向的对象是一样的。即两个list的每个元素指向的还是同一内存。
评论
2 楼
darrenzhu
2014-05-30
Checkmate 写道
最后一条我倒是看到了不同的解释.
Both methods are shallow copy. So what is the difference between these two methods?
First, Collections.copy() won’t reallocate the capacity of dstList even if dstList does not have enough space to contain all srcList elements. Instead, it will throw an IndexOutOfBoundsException. One may question if there is any benefit of it. One reason is that it guarantees the method runs in linear time. Also it makes suitable when you would like to reuse arrays rather than allocate new memory in the constructor of ArrayList.
Collections.copy() can only accept List as both source and destination, while ArrayList accepts
我也觉得貌似都是浅克隆.
Both methods are shallow copy. So what is the difference between these two methods?
First, Collections.copy() won’t reallocate the capacity of dstList even if dstList does not have enough space to contain all srcList elements. Instead, it will throw an IndexOutOfBoundsException. One may question if there is any benefit of it. One reason is that it guarantees the method runs in linear time. Also it makes suitable when you would like to reuse arrays rather than allocate new memory in the constructor of ArrayList.
Collections.copy() can only accept List as both source and destination, while ArrayList accepts
我也觉得貌似都是浅克隆.
you are right, 都是浅拷贝.
1 楼
Checkmate
2013-09-26
最后一条我倒是看到了不同的解释.
Both methods are shallow copy. So what is the difference between these two methods?
First, Collections.copy() won’t reallocate the capacity of dstList even if dstList does not have enough space to contain all srcList elements. Instead, it will throw an IndexOutOfBoundsException. One may question if there is any benefit of it. One reason is that it guarantees the method runs in linear time. Also it makes suitable when you would like to reuse arrays rather than allocate new memory in the constructor of ArrayList.
Collections.copy() can only accept List as both source and destination, while ArrayList accepts
我也觉得貌似都是浅克隆.
Both methods are shallow copy. So what is the difference between these two methods?
First, Collections.copy() won’t reallocate the capacity of dstList even if dstList does not have enough space to contain all srcList elements. Instead, it will throw an IndexOutOfBoundsException. One may question if there is any benefit of it. One reason is that it guarantees the method runs in linear time. Also it makes suitable when you would like to reuse arrays rather than allocate new memory in the constructor of ArrayList.
Collections.copy() can only accept List as both source and destination, while ArrayList accepts
我也觉得貌似都是浅克隆.
发表评论
-
sapjco3 notes
2019-03-21 14:51 1160sapjco https://support.sap.com/ ... -
使用RestTemplate发送post JSON请求
2019-01-12 17:30 4725private final String BASE_URL = ... -
使用RestTemplate发送post JSON请求
2019-01-12 17:30 3495private final String BASE_URL = ... -
Spring线程池ThreadPoolTaskExecutor
2018-08-06 09:51 1878<!-- spring thread pool ex ... -
Spring注解事物@Transactional不工作
2018-08-02 18:50 2669“In proxy mode (which is the de ... -
创建前缀索引报长度超出错误
2018-07-25 15:44 1723表结构定义如下: CREATE TABLE `sku` ( ` ... -
Mysql Varchar字符长度
2018-07-25 15:23 1349`sku_name` VARCHAR(200) NOT NUL ... -
使用 Spring RestTemplate 发送 post 请求
2018-07-23 18:49 11720注意点: 1)使用MultiValueMap设置入参,不要使 ... -
Java动态代理Dynamic Proxy
2018-07-21 16:33 806JAVA学习篇--静态代理VS动态代理 https://blo ... -
分布式实时日志分析解决方案 ELK 部署架构
2018-07-20 09:52 1186原文链接:http://www.importn ... -
为什么HashMap容量一定要为2的幂呢?
2018-07-19 10:07 1726原文链接:https://blog.csdn.net/wang ... -
为什么计算HashCode时通常选择31这个数?
2018-07-19 10:05 1415摘自http://www.importnew.com/2208 ... -
jackson自定义序列化和反序列化
2018-07-10 18:47 2238原文链接:https://blog.csdn.net/liu ... -
Pay special attention when modifying online running system
2017-06-23 10:25 0Never remove any properties, me ... -
Map中的Null key, Null Value
2017-06-14 10:52 1940ConcurrentHashMap的key和value都不能为 ... -
Java语法糖
2017-06-05 20:03 527Java语法糖之foreach http://www.imp ... -
Java集合相关
2017-05-24 17:55 0Java集合框架:ArrayList http://www. ... -
Java数据类型的转换:隐式(自动)转换与强制转换
2017-05-14 10:46 0http://blog.csdn.net/u011240877 ... -
分布式开放消息系统(RocketMQ)的原理与实践
2017-05-07 19:55 725分布式开放消息系统(RocketMQ)的原理与实践 http ... -
面试知识点复习(Interview knowledge review)
2017-05-07 18:39 0JVM,多线程相关知识 http://darrenzhu.it ...
相关推荐
Java.util.ConcurrentModificationException 异常问题详解 ConcurrentModificationException 异常是 Java 中一个常见的异常,它发生在 Iterator 遍历集合时,集合同时被修改引起的异常。在 Java 中,集合类如 ...
java.util.ConcurrentModificationException 解决方法 在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除。 则使用会报以下异常: Java.util....
Spring数据mongodb测试 在Collections.synchronizedList或Collections.synchronizedSet上测试spring数据mongodb ConcurrentModificationException
在Java编程中,`java.util.ConcurrentModificationException` 是一个常见的运行时异常,通常发生在尝试并发修改集合时。这个异常的产生是由于集合类(如HashMap)的非线程安全特性,当你在一个线程中使用迭代器遍历...
4. 或者,可以使用`Collections.synchronizedMap()`或`CopyOnWriteArrayList/CopyOnWriteArraySet`等同步集合类,它们在多线程环境下提供了一定程度的安全性。 总之,`ConcurrentModificationException`是Java集合...
标题“axis1.4.1.zip”所指的是一份针对Axis1.4版本的修复补丁包,这个补丁主要是为了解决在Java Development Kit (JDK) 1.8环境下,高并发场景下出现的`ConcurrentModificationException`问题。`...
在多线程环境中,只读集合特别有用,因为它们能防止并发修改异常(`ConcurrentModificationException`)。当多个线程试图同时修改集合时,可能会出现这种问题。只读集合确保了即使在并发环境下,数据也能保持一致。 ...
- `CopyOnWriteArrayList`和`CopyOnWriteArraySet`:这些列表和集在线程安全的迭代器上有优势,因为它们在修改时复制底层数组,从而避免了迭代过程中的并发修改异常(`ConcurrentModificationException`)。...
当多个线程同时访问一个集合时,可能会抛出`ConcurrentModificationException`。面试官可能会问如何避免这种异常,一种解决方案是使用`CopyOnWriteArrayList`或`ConcurrentHashMap`等并发安全的集合类。 #### 4. ...
14. **集合的复制**:通过clone()、Arrays.copyOf() 或 Collection.clone() 方法可以实现集合的浅复制。深复制涉及对象的复杂性,需要额外的处理。 15. **集合的排序**:Collections.sort() 方法可以对List进行排序...
迭代器在遍历过程中删除元素时,不会导致ConcurrentModificationException。 2. List接口的使用与排序: - 第二部分实验要求将一系列数字存入List中,并进行升序和降序排序。使用`ArrayList`实现List接口,通过`...
`Iterator`在遍历过程中可以删除元素,但不建议在遍历期间修改集合,因为这可能导致`ConcurrentModificationException`。 5. **增强型for循环(foreach)**:简化了集合的遍历,如`for (Element e : collection) {....
在并发环境下,多个线程同时调用`ArrayList`的`add()`方法会导致`ConcurrentModificationException`,因为这些操作没有内置的同步控制。 2. `LinkedList`: 基于链表结构的列表,它的插入和删除操作通常比`ArrayList...
fail-fast 迭代器在集合修改时,会抛出 ConcurrentModificationException 异常。fail-safe 迭代器在集合修改时,会返回当前集合的快照。 RandomAccess 接口的应用场景 RandomAccess 接口是 Java Collections 框架...
例如,在多个线程同时尝试修改列表时,可能会抛出`ConcurrentModificationException`。 2. `LinkedList`:与`ArrayList`类似,其迭代器也不是线程安全的,因此并发修改会导致异常。 3. `HashMap`:并发写入可能导致...
- 使用`Collections.emptyXX()`或`Collections.emptyList()()`创建不可变的空集合。 - 避免在循环中调用`list.add()`等改变集合大小的方法,可能导致 ConcurrentModificationException。 6. **并发编程**: - ...
如果在迭代过程中集合结构被修改(如添加、删除元素),迭代器会抛出ConcurrentModificationException。 28. **什么是Java的并发容器?** 如ConcurrentHashMap、ConcurrentLinkedQueue等,它们设计用于并发环境,...
- 如果在多线程环境中,需要使用线程安全的数据结构,如`Collections.synchronizedList()`、`CopyOnWriteArrayList`、`ConcurrentHashMap`等,它们支持并发修改。 - 使用`synchronized`关键字或者`java.util....
1. 使用`Collections.synchronizedXXX`方法:如`synchronizedList`, `synchronizedSet`等,它们会返回一个线程安全的集合包装器。不过,虽然外部访问是同步的,但迭代过程中的修改仍然需要额外的同步控制,以避免...