Java開發者易犯錯誤Top10

摘要:在Java中,有些事物若是不瞭解的話,很容易就會用錯,如數組轉換爲數組列表、元素刪除、Hashtable和HashMap、ArrayList和LinkedList、Super和Sub構造函數等,若是這些對你來講是陌生的,你能夠在本文中瞭解它們。java

本文總結了Java開發者常常會犯的前十種錯誤列表。算法

 

Top1. 數組轉換爲數組列表

將數組轉換爲數組列表,開發者常常會這樣作:數組

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

Arrays.asList()將返回一個數組內部是私有靜態類的ArrayList,這不是java.util.ArrayList類,java.util.Arrays.ArrayList類有set()、 get()、 contains()方法,可是沒有任何加元素的方法,所以它的大小是固定的。你應該這麼作來建立一個真正的數組:安全

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

ArrayList的構造函數可以接受一個集合類型,這也是java.util.Arrays.ArrayList的超級類型。數據結構

 

Top2. 檢查一個數組包含一個值

開發者常常這麼作:函數

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

代碼能夠工做,可是沒有必要首先轉換列表到Set,轉換一個列表到一個Set須要額外的時間。所以你能夠把它簡化爲:性能

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

ui

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

第一個比第二個更具可讀性spa

 

Top3. 在一個循環中從一個列表裏刪除一個元素

考慮下面刪除元素的代碼在迭代中的結果:設計

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]

該方法有一個嚴重的問題,當一個元素被刪除時,列表收縮的大小以及指針改變了。因此想要在循環內利用指針刪除多個元素是沒法正常進行的。

這種狀況下使用迭代器纔是正確的方法,foreach循環在Java中的工做像是一個迭代器,但實際上並非,考慮下面的代碼:

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()以前被調用。在foreach循環中,編譯器將在刪除元素操做以後調用.next(),這也是致使ConcurrentModificationException異常的緣由,你能夠查看ArrayList.iterator()的源代碼

 

Top4. Hashtable vs HashMap

根據算法的常規,Hashtable是對數據結構的稱呼。可是在Java中,數據結構的名稱是HashMap。Hashtable和HashMap關鍵不一樣之一是Hashtable是同步的。

關於這一點可查看如下兩個連接:

HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap

Map問題Top10

 

Top5. 使用集合的原始類型

在Java中,原始類型和無限制的通配符類型很容易被混淆。以Set爲例,Set是原始類型,而Set(?)則是無限制的通配符類型。

考慮下面的代碼,以一個原始類型List做爲參數: 

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 ...

使用原始類型集合是危險的,由於原始類型集合跳過了泛型類型檢查,也不安全。Set、Set<?>和Set之間有很大的不一樣。詳細可查看

Raw type vs. Unbounded wildcardType Erasure

 

Top6. 訪問級別

開發者常常對類域使用public,這很容易經過直接引用得到域值,但這是一個很是糟糕的設計。根據經驗來講是給予成員的訪問級別越低越好。

詳細狀況可點擊查看Java中成員訪問級別:public、protected、private

 

Top7.ArrayList VS LinkedList

若是你不知道ArrayList和LinkedList之間的區別時,你可能會常常的選用ArrayList,由於它看起來看熟悉。然而它們之間有巨大的性能不一樣。簡單的來講,若是有大量的添加/刪除操做,而且沒有不少的隨機存取操做時,LinkedList應該是你的首選。若是您對此不是很瞭解的話,點此此處查看更多關於它們性能的信息。

 

Top8. Mutable VS Immutable

Immutable對象有不少優點,好比簡單、安全等等。但它要求每個不一樣的值都須要有一個不一樣的對象,而太多的對象可能會致使垃圾收集的高成本。因此對Mutable和Immutable的選擇應該有一個平衡點。

通常來講,Mutable對象用於避免產生過多的中間對象,經典的例子是鏈接大量的字符串數。若是你使用Immutable字符串,那麼會產生不少符合垃圾收集條件的對象。這對CPU是浪費時間和精力的,當其可使用Mutable對象做爲正確的解決方案。(如StringBuilder)

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

這裏還有一些其餘Mutable對象可取的狀況。例如mutable對象傳遞到方法中容許你在不跳過太多語法的狀況下收集多個結果。另外一個例子是排序和過濾,你能夠構建一個帶有原有集合的方法,並返回一個已排序的,不過這對大的集合來講會形成更大的浪費。

推薦閱讀:爲何字符串是Immutable?

Top9. Super和Sub構造函數

編譯報錯

編譯報錯

這個編譯錯誤是由於默認的Super構造函數是未定義的。在Java中,若是一個類沒有定義一個構造函數,編譯器會默認的爲類插入一個無參數構造函數。若是一個構造函數是在Super類中定義的,這種狀況下Super(String s),編譯器不會插入默認的無參數構造函數。

另外一方面,Sub類的構造函數,不管帶不帶有參數,都會調用無參數的Super構造函數。

編譯器在Sub類中試圖將Super()插入到兩個構造函數中,可是Super默認的構造函數是沒有定義的,編譯器纔會報錯。如何解決這一問題?你只需在Super類中添加一個Super()構造函數,以下所示:

public Super(){  
    System.out.println("Super");  
}

或移除自定義的Super構造函數,又或者在Sub函數中添加super(value)。

這方面想了解更多的能夠點擊此處查看。

 

Top10. 「」或構造函數?

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

//1. use double quotes  
String x = "abc";  
//2. use constructor  
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

關於它們如何在內存中分佈的更多細節能夠查看《使用」」或構造函數建立Java字符串》

 

推薦閱讀:

Constructors of Sub and Super Classes in Java?
How Developers Sort in Java?
How to Convert Array to ArrayList in Java?
Java Type Erasure Mechanism

相關文章
相關標籤/搜索