刚开始接触java时很长一段时间, 总觉得java链表的删除操作自己写的有bug。
第一个bug版本:
仅接removeByForlist.remove(j)之后应该显示调用i--
public static void testRemoveByFor() {
List<Integer> removeByForlist = Lists.newArrayList(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
System.out.println(ToStringBuilder.reflectionToString(Joiner.on("").join(removeByForlist)));
for (Integer i = 0; i < removeByForlist.size(); i++) {
Integer j = removeByForlist.get(i);
if (j.equals(1)) {
removeByForlist.remove(j);
}
}
System.out.println(ToStringBuilder.reflectionToString(Joiner.on("").join(removeByForlist)));
}
public static void main(String[] args) {
testRemoveByFor();
}
输出结果:
java.lang.String@35718057[value={1,1,1,1,1,1,1,1,1,1},hash=2075774624]
java.lang.String@3f4de7ea[value={1,1,1,1,1},hash=46760945]
第二个bug版本:
首先介绍一下fail-fast: fail-fast 机制是java集合(Collection)中的一种错误机制。 当多个线程对同一个集合的内容进行操作时,就可能会产生 fail-fast 事件。 例如:当某一个线程A通过 iterator 去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException 异常,产生 fail-fast 事件。这种设计模式原则是与其留下隐患,不如最初就直接拒绝。这就好比有时我们做人一样,有时需要干脆的拒绝他人。
<p><strong> <span> <strong style="line-height: 1.5;"> <span style="line-height: 1.5; background-color: #ff0000;"></span> </strong> </span> </strong></p><span style="color:#ff9900;"><strong> </strong></span>public static void testRemoveByForeach() {
List<Integer> removeByForeach = Lists.newArrayList(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
System.out.println(ToStringBuilder.reflectionToString(Joiner.on("").join(removeByForeach)));
for(Integer i : removeByForeach){
removeByForeach.remove(i);
}
System.out.println(ToStringBuilder.reflectionToString(Joiner.on("").join(removeByForeach)));
}
public static void main(String[] args)
testRemoveByIterator();
}
输出结果:
java.lang.String@35718057[value={1,1,1,1,1,1,1,1,1,1},hash=2075774624]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at listTest.Main.testRemoveByForeach(Main.java:55)
at listTest.Main.main(Main.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
<strong>对第二个bug版本官方文档解释如下:</strong>
* <p><a name="fail-fast"/>
* The iterators returned by this class's {@link #iterator() iterator} and
* {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:
* <strong><span style="color:#FF6666;">if the list is structurally modified at any time after the iterator is
* created, in any way except through the iterator's own
* {@link ListIterator#remove() remove} or
* {@link ListIterator#add(Object) add} methods, the iterator will throw a
* {@link ConcurrentModificationException}. </span></strong> Thus, in the face of
* concurrent modification, the iterator fails quickly and cleanly, rather
* than risking arbitrary, non-deterministic behavior at an undetermined
* time in the future.
第三个正确版本:
public static void testRemoveByIterator() {
List<Integer> removeByIterator = Lists.newArrayList(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
System.out.println(ToStringBuilder.reflectionToString(Joiner.on("").join(removeByIterator)));
Iterator<Integer> iterator = removeByIterator.iterator();
int i = 0;
while (iterator.hasNext()) {
Integer next = iterator.next();
if (next.equals(1)) {
iterator.remove();
}
}
System.out.println(ToStringBuilder.reflectionToString(Joiner.on("").join(removeByIterator)));
}
public static void main(String[] args) {
testRemoveByIterator();
}
输出结果:
java.lang.String@2ea0eb2a[value={1,1,1,1,1,1,1,1,1,1},hash=2075774624]
java.lang.String@13b4d41e[value={},hash=0]