程序員常犯的幾個錯誤

1. 數組轉ArrayListjava

爲了實現把一個數組轉換成一個ArrayList,不少Java程序員會使用以下的代碼:程序員

List<String> list = Arrays.asList(arr);
Arrays.asList確實會返回一個 ArrayList對象,可是該類是 Arrays類 中一個私有靜態內部類,而不是常見的 java.util.ArrayList類。這個 java.util.Arrays.ArrayList 類具備 set(),get(),contains()等方法,可是不具備任何添加或移除元素的任何方法。由於該類的大小(size)是固定的。爲了建立出一個真正的 java.util.ArrayList,代碼應該以下所示:編程

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
咱們知道,ArrayList的構造方法能夠接受一個 Collection 類型的對象,而咱們的 java.util.Arrays.ArrayList 正好也是它的一個子類。實際上,更加高效的代碼示例是:數組

ArrayList<String> arrayList = new ArrayList<String>(arr.length);安全

Collections.addAll(arrayList, arr);
2. 數組是否包含特定值數據結構

爲了檢查數組中是否包含某個特定值,不少Java程序員會使用以下的代碼:函數

Set<String> set = new HashSet<String>(Arrays.asList(arr));性能

return set.contains(targetValue);
就功能而言,該代碼是正確無誤的,但在數組轉List,List再轉Set的過程當中消耗了大量的性能。咱們能夠優化成以下形式:學習

Arrays.asList(arr).contains(targetValue);
或者,進一步優化成以下所示最高效的代碼:優化

for(String s: arr){

if(s.equals(targetValue))

return true;

}

return false;
3. 在迭代時移除List中的元素

首先,看一下在迭代過程當中移除List中元素的代碼:

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]
這個示例代碼中存在一個很是嚴重的錯誤。當一個元素被移除時,該List的大小(size)就會縮減,同時也改變了索引的指向。因此,在迭代的過程當中使用索引,將沒法從List中正確地刪除多個指定的元素。

你可能知道解決這個錯誤的方式之一是使用迭代器(iterator)。並且,你可能認爲Java中的 foreach 語句與迭代器(iterator)是很是類似的,但實際狀況並非這樣。咱們考慮一下以下的示例代碼:

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 循環中,編譯器使得 remove()方法先於next()方法被調用,這就致使了 ConcurrentModificationException 異常。具體細節能夠查看 ArrayList.iterator()的源碼。

4. Hashtable vs HashMap

學習過數據結構的讀者都知道一種很是重要的數據結構叫作 哈希表。在Java中,對應哈希表的的類是 HashMap 而不是 Hashtable。HashMap與Hashtable之間的最核心區別就是:HashMap是非同步的,Hashtable是同步的。

5. 在Collection中使用原始類型

在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 ...
在Collection使用原始類型是具備不少的類型錯誤風險的,由於原始類型沒有靜態類型檢查。實際上,Set、Set<?>和Set之間具備很是大的差別。

6. 訪問權限

不少的Java初學者喜歡使用 public 來修飾類的成員。這樣能夠很方便地直接訪問和存取該成員。可是,這是一種很是糟糕的編程風格,正確的設計風格應該是儘量下降類成員的訪問權限。

7. ArrayList vs LinkedList

不少的Java初學者不明白ArrayList與LinkedList之間的區別,因此,他們徹底只用相對簡單的ArrayList,甚至不知道JDK中還存在LinkedList。可是,在某些具體場景下,這兩種List的選擇會致使程序性能的巨大差別。簡單而言:當應用場景中有不少的 add/remove 操做,只有少許的隨機訪問操做時,應該選擇LinkedList;在其餘的場景下,考慮使用ArrayList。

8. 可變 vs 不可變

不可變的對象具備很是多的優點,好比簡單,安全等。可是,對於每個不一樣的值,都須要該類的一個對象。並且,生成不少對象帶來的問題就是可能致使頻繁的垃圾回收。因此,在選擇可變類仍是不可變類時,應該綜合考慮後再作抉擇。

一般而言,可變對象能夠避免建立大量的中間對象。一個很是經典的例子就是連接大量的短String對象爲一個長的String對象。若是使用不可變String類,連接的過程將產生大量的,適合當即被垃圾回收的中間String對象,這將消耗大量的CPU性能和內存空間。此時,使用一個可變的StringBuilder或StringBuffer纔是正確的。

String result="";

for(String s: arr){

result = result + s;

}
除了上述狀況,可變對象在其餘場景下可能因爲不可變對象。好比,傳遞一個可變的對象到方法內部,利用該對象能夠收集多個結果,而不用在多個循環層次中跳進跳出。

9. 繼承中的構造函數

上圖中出現的兩個編譯時錯誤是由於:父類中沒有定義默認構造函數,而子類中又調用了父類的默認構造函數。在Java中,若是一個類不定義任何構造函數,編譯期將自動插入一個默認構造函數到給類中。一旦一個類定義了任何一個構造函數,編譯期就不會插入任何構造函數到類中。在上面的示例中,Super類定義了一個參數類型爲String的構造函數,因此該類中只有一個構造函數,不會有默認構造函數了。

&emps;在咱們的子類 Sub 中,咱們定義了兩個構造函數:一個參數類型爲String的構造函數,另外一個爲午飯的默認函數。因爲它們都沒有在函數體的第一行指定調用父類的哪個構造函數,因此它們都須要調用父類 Super 的默認構造函數。可是,父類 Super 的默認構造函數是不存在的,因此編譯器報告了這兩個錯誤信息。

10. 字符串對象的兩個構建方式

Java中的字符串對象具備兩個常見的建立方式:

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

相關文章
相關標籤/搜索