Java小细节

Java小细节,把遇到的小问题汇集到这里,不定期持续更新~~

 

①下面的程序打印结果是什么?

public class TestMain1 {
    public static void main(String[] args) {
        Integer i1 = 127;
        Integer i2 = 127;
        System.out.println(i1==i2);
        
        Integer i3 = 128;
        Integer i4 = 128;
        System.out.println(i3==i4);
        
        Integer i5 = 127;
        Integer i6 = new Integer(127);
        System.out.println(i5==i6);
        
        Integer i7 = 128;
        Integer i8 = new Integer(128);
        System.out.println(i7==i8);
    }
}

运行一下,得到的结果是:true  false  false   false

第3、4打印出false比较好理解,因为是new的不同对象。但是第1、2打印的结果为什么不一样呢?

这是因为:Integer的缓存做了处理。看看Integer的valueOf方法就明白了:

public static Integer valueOf(int i) {
    final int offset = 128;
    if (i >= -128 && i <= 127) { // must cache
        return IntegerCache.cache[i + offset];
    }
    return new Integer(i);
}

就是说-128~127之间的数据,返回的是同一个对象。所以i1==i2 i3!=i4

Java的解释是:....this method is likely to yield significantly better space and time performance by caching frequently requested values...

 

②下面这段程序能正常运行吗?

import java.util.Arrays;
import java.util.List;


public class TestMain2 {
    public static void main(String[] args) {
        String[] array= new String[5];
        for (int i = 0; i < array.length; i++) {
            array[i] = String.valueOf(i);
        }
        
        List<String> list = Arrays.asList(array); 
        
        list.add("test");
    }

}

答案是不能,会抛出java.lang.UnsupportedOperationException异常

解析:Arrays.asList方法得到的list是一个静态的内部类

 

private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable

 

而这个ArrayList并没有覆写父类的add方法,所以上面的代码会调用AbstractList中的add方法。

而AbstractList中的add方法是这个样子的:

public boolean add(E o) {
    add(size(), o);
    return true;
}

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

所以,执行到list.add("test");就会抛出异常。

 

③遍历集合的同时删除元素

 昨天看同事写的代码中出现的代码,是在是匪夷所思,一个多年Java经验的人写出来的啊~~

 除开具体的业务逻辑,大概是下面这个样子

    
    public static void main(String[] args) {
        List<String> testList = new ArrayList<String>();
        testList.add("one");
        testList.add("two");
        testList.add("three");
for (String string : testList) { System.out.println(string); if (string.equals("one")) { testList.remove(string); } } }

先说明一下,for-each循环会被编译器转换成Iterator来进行。上面的代码会出现什么问题呢?抛出java.util.ConcurrentModificationException,

看看源码即知:

    public E next() {
            checkForComodification();
        try {
        E next = get(cursor);
        lastRet = cursor++;
        return next;
        } catch(IndexOutOfBoundsException e) {
        checkForComodification();
        throw new NoSuchElementException();
        }
    }

在AbstractList中实现了next方法,在取得下一个之前进行检查,checkForComodification源码如下:

final void checkForComodification() {
        if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}
modCount:表示该集合对象结构被修改的次数,add或者remove,都会让modCount++
expectedModCount:表示期待的modCount值,用来判断在遍历过程中集合是否被修改过。

回到正题,上面的代码执行remove之后,modCount==4,而expectedModCount==3

在取得下一个next的时候,会抛出异常。(是的,你没看错,是remove之后,并不是remove的同时抛出的异常)

不过,这样的代码,并不总是抛出ConcurrentModificationException,看看下面的代码:

    
    public static void main(String[] args) {
        List<String> testList = new ArrayList<String>();
        testList.add("one");
        testList.add("two");
        //testList.add("three");

        for (String string : testList) {
            System.out.println(string);
            if (string.equals("one")) {
                testList.remove(string);
            }
        }
    }
    

这个代码和上面的只有一行只差,他不会抛出ConcurrentModificationException异常,但是不会打印出two,你知道为什么吗?

答案其实在上面也提到了,在取得下一个next的时候,会抛出异常。(是的,你没看错,是remove之后,并不是remove的同时抛出的异常)

删除“one”之后,size变成1,就不会有下一次遍历,即使modCount==3,而expectedModCount==2,异常也不会触发。

不管怎么说,上面的删除方式是错误的,那么正确的该怎么写呢?用Iterator的remove方法

    
    public static void main(String[] args) {
        List<String> testList = new ArrayList<String>();
        testList.add("one");
        testList.add("two");
        testList.add("three");

        Iterator<String> it = testList.iterator();
        while (it.hasNext()) {
            String temp = it.next();
            System.out.println(temp);
            if (temp.equals("one")) {
                it.remove();
            }
        }
    }
    

 

 

 

 

 

 

 

 

 

posted @ 2013-05-07 15:53  yejg1212  阅读(312)  评论(0编辑  收藏  举报