java常見十大誤區

一、轉化數組爲ArrayList

一般開發者轉化數組爲ArrayList的方式爲java

List<String> list = Arrays.asList(arr);

Arrays.asList()會返回一個ArrayList,而這個ArrayList是Arrays類的靜態內部類,不是java.util.ArrayList。數組

這個類有get()、set()和contains()方法,但卻沒有任何能夠添加元素的方法。正確的作法能夠這樣作安全

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

二、檢查數組裏面是否包含某個元素

部分開發者會這樣實現數據結構

return new HashSet<String>(Arrays.asList(arr)).contains(targetValue);

結果是對的,可是沒有必要轉化爲Set,這反而會花費更多時間,能夠簡單這樣實現函數

return Arrays.asList(arr).contains(targetValue);

或者性能

for(String s: arr){
    if(s.equals(targetValue))
        return true;
}
return false;

補充:第一種相比第二種可讀性會高一些。ui

三、數組中循環刪除元素

分析一下下列代碼:this

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
for (int i = 0; i < list.size(); i++) {
    list.remove(i);
}
System.out.println(list);

輸出結果爲:線程

[b, d]設計

由於當數組刪除一個元素後,它的長會縮小,index至關於向後移動一位,這是個嚴重的問題。當你想經過index來刪除多個元素時候,這種方法是不可取的。

你也許知道用迭代器來刪除是沒問題的,而且java中有一類for語句原理就是使用迭代器。但實際你想用這類for語句來代替迭代器進行刪除也是不行的,以下代碼

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
 
for (String s : list) {
    if (s.equals("a"))
        list.remove(s);
}

將會拋出ConcurrentModificationException異常。

以下代碼纔是正確的

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String s = iter.next();
 
    if (s.equals("a")) {
        iter.remove();
    }
}

next()必須在remove()以前被調用。而在for循環中,編譯器會在元素被remove以後調用next(),所以就會拋出ConcurrentModificationException異常。

四、hashtable和hashmap

java中有兩類,HashTable和HashMap,二者的數據結構是一致的(哈希表),而後二者的區別是:HashTable是同步的。

因此HashTable是線程安全的,HashMap不是線程安全的。

提示:也可使用ConcurrentHashMap來保證線程安全,ConcurrentHashMap使用分段鎖(segment)的原理,效率上會高一些。

五、集合中原生態類型(raw type)的使用

在java中,開發者一般把原生態類型(raw type)一般和無界通配符類型(unbounded wildcard type)弄混。拿Set來舉例子,Set是原生態類型,而Set<?>是無界通配符類型。

以下代碼使用了原生態類型

public static void add(List list, Object o){
    list.add(o);
}
public static void main(String[] args){
    List<String> list = new ArrayList<String>();
    add(list, 10);
    String s = list.get(0);
}

代碼將會拋出異常

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at ...

原生態類型會越過泛型的校驗,是不安全的。

六、訪問級別

有的開發者將類某些屬性直接定義爲public,這很容易經過外部訪問,但絕對是不好的設計。根據拇指規則,最佳作法應該是儘可能減小屬性的訪問級別。

七、LinkList vs ArrayList

不少開發者都習慣使用ArrayList,可能ArrayList相對來講比較熟悉的緣故,其實ArrayList和LinkList仍是存在很大的區別。簡而言之,LinkList應該在有大量增刪操做且無隨機訪問操做時候使用。

八、可變(mutable) vs 不可變(immutable)

不可變對象有不少優勢,好比簡單、安全等。但對於多個值則須要多個不一樣的對象來表示,對象過多時,會消耗不少的GC資源。

一般的,可變對象可用來避免產生過多的對象。以下代碼中使用了不可變對象,那麼執行過程當中將會產生不少的String,消耗不少時間和cpu性能。若是換成可變對象(StringBuilder等),將會好不少。

String result="";
for(String s: arr){
    result = result + s;
}

九、父子類的構造函數

class Super {
        String s;

        public Super(String s) {
            super();
            this.s = s;
        }

    }

    class Sub extends Super {

        public Sub(String s) {
        }

        public Sub() {

        }
    }

上述代碼會出錯,是由於父類默認構造函數沒有定義。在java中,若是一個類沒有定義構造函數,則編譯器會給它構造默認的無參構造函數。若是類中定義了構造函數,那麼編譯器將不會給它插入默認構造函數。這個正是上述父類的遇到的狀況。

在子類中的兩個構造函數中,編譯器試圖插入父類的默認構造函數super(); ,然而並未找到,所以編譯出錯。

十、"" or Constructor

字符串能夠經過兩種方式創建

//1. 直接引用
String x = "abc";
//2. 使用構造函數
String y = new String("abc");

二者卻別可經過以下代碼闡明

String a = "abcd";
String b = "abcd";
System.out.println(a == b);  // True
System.out.println(a.equals(b)); // True
 
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d);  // False
System.out.println(c.equals(d)); // True
相關文章
相關標籤/搜索