Java核心问题集锦_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Java核心问题集锦

Java核心问题集锦

 2012/8/21 11:13:38  darrenzhu  程序员俱乐部  我要评论(0)
  • 摘要:注意,这里的参考文章基本来自EffectiveJava和jdk源码1)ConcurrentModificationException当你用foreach遍历一个list时,如果你在循环主体代码中修改list中的元素,将会得到这个Exception,解决的办法是:1)用listIterator,它支持在遍历的过程中修改元素,2)不用listIterator,new一个新的list,copyoldlistcontenttonewlist,andthenmodifythenewcreatedlist
  • 标签:Java 问题
注意,这里的参考文章基本来自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<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方法,即不要去实现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> values=new ArrayList<Object>(srcList.size());
//or List<Object> values=new ArrayList<Object>();
Collections.copy(values, srcList());


按如上方式用时,很容易得到"Source does not fit in dest" Exception,原因是copy方法里面会首先比较dest和src的size,而往往你新new的list的size是0,所以会报错,可以用如下方式:
List<Object> values=new ArrayList<Object>(Arrays.asList(new Object[srcList.size()]));
Collections.copy(values, srcList());


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());
            }
        }
    }
发表评论
用户名: 匿名