如何安全操作ArrayList?
2017-09-22 00:00
197 查看
摘要: 又是被面试官问到的问题。
<老马说编程>中讲过ArrayList,先去看一下
动态删除ArrayList中的元素
ArrayList删除元素后长度变小了,元素的索引也会跟着改变,但是迭代的下标没有跟着相应的改变。import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Created with IDEA by penelopeWu * Date:2017/9/22 9:18 */ public class SafeOptrationOfArrayList { public static void main(String[] args) { List<String> list = new ArrayList(); /* list.add("c"); list.add("a"); list.add("c"); list.add("b"); list.add("c"); list.add("d"); list.add("c"); */ list.add("a"); list.add("c"); list.add("c"); list.add("b"); list.add("c"); list.add("c"); list.add("d"); list.add("c"); } /** * 删除Arraylist中值为"c"的元素 * 不安全 * @param list */ public static void removeListElement1(List<String> list) { for (int i = 0; i < list.size(); i++) { if ("c".equals(list.get(i))) { list.remove(i); } } } /** * 删除Arraylist中值为"c"的元素 * 安全 * @param list */ public static void removeListElement2(List<String> list) { for (int i = 0; i < list.size(); i++) { if ("c".equals(list.get(i))) { list.remove(i); --i;//删除元素的同时,要让迭代下标也跟着改变 } } } /** * 删除Arraylist中值为"c"的元素 * 安全 * @param list */ public static void removeListElement3(List<String> list) { Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ String str = iterator.next(); if ("c".equals(str)){ iterator.remove(); //为什么iterator的remove方法是可靠的? } } } }
ArrayList.remove(int index)源码
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; //需要移动的元素个数 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //数组复制,被删除元素之后的元素各前移一位 elementData[--size] = null; // clear to let GC do its work // 空出的位置 设置为null。 return oldValue; //返回被删除的元素 }
System.arraycopy(...)
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
迭代器操作ArrayList为什么是可靠的?
先看下ArrayList的内部类Itr的源码/** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; //敲黑板!!,将ArrayList的modCount赋值给Itr的expectedModCount,expectedModCount接下来有大用处 public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); //首先检查ArrayList是否被结构性修改 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification();//首先检查ArrayList是否被结构性修改 try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } final void checkForComodification() { //敲黑板!!如果ArrayList被结构性修改,这时modCount和expectedModCount就不再一致了,直接抛异常 if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
相关文章推荐
- 如何避免企业内部的恶意操作或操作疏忽带来的安全威胁
- ArrayListTest编译问题:使用了未经检查或不安全的操作;请使用 -Xlint:unchecked 重新编译
- 如何设置Win8操作中心功能及时安全提醒
- 证明ArrayList线程不安全以及如何安全
- Tomcat会话超时时如何记录操作日志,满足安全审计要求
- Hashtable与ArrayListTest编译问题:使用了未经检查或不安全的操作;请使用 -Xlint:unchecked 重新编译
- UNIX 如果查询一个共享内存已经被IPCRM,程序中如何操作保证安全
- 11.38 CastleActiveRecord中如何保证多线程并发操作的安全与成功?
- 如何在子线程中通过安全调用方法操作窗体控件
- 如何避免企业内部的恶意操作或操作疏忽带来的安全威胁
- 如何操作LS中的安全实体(用户、角色、权限)! Accessing security entities in a Lightswitch application (转)
- Mac OS X:单用户模式(Single User Mode)的操作和安全漏洞
- 如何在 Git 里撤销(几乎)任何操作
- 如何分辨拷贝构造函数和赋值操作符两种操作
- surface pro如何进入安全模式?
- C#中如何把XML转化成强类型操作
- 挑战与机遇 我国信息安全产业如何把持
- Settings如何去掉 设置-安全里面的部分菜单
- 如何在 Linux 上录制你的终端操作
- ABAP--如何通过Oracle游标直接操作Oracle的系统表