Java程序員們最常犯的10個錯誤

1.將數組轉化爲列表  

將數組轉化爲一個列表時,程序員們常常這樣作: 

Java代碼 
  1. List<String> list = Arrays.asList(arr);  

Arrays.asList()會返回一個ArrayList對象,ArrayList類是Arrays的一個私有靜態類,而不是java.util.ArrayList類,java.util.Arrays.ArrayList類有set()、get()、contains()方法,可是沒有增長元素的方法,因此它的大小是固定的,想要建立一個真正的ArrayList類,你應該這樣作: 

Java代碼 
  1. ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));  

ArrayList的構造方法能夠接受一個集合類型,恰好它也是java.util.Arrays.ArrayList的超類。 

2.判斷一個數組是否包含一個值  

程序員們常常這樣作: 

Java代碼 
  1. Set<String> set = new HashSet<String>(Arrays.asList(arr));   
  2. return set.contains(targetValue);  

這段代碼起做用,可是沒有必要把一個數組轉化成列表,轉化爲列表須要額外的時間。它能夠像下面那樣簡單:

Java代碼 
  1. Arrays.asList(arr).contains(targetValue);  

或者是: 

Java代碼 
  1. for(String s:arr){  
  2.     if(s.equals(targetValue)){  
  3.         return true;  
  4.     }  
  5. }  
  6. return false;  

第一種方法比第二種更容易讀 

3.在一個循環中刪除一個列表中的元素  

思考下面這一段在循環中刪除多個元素的的代碼 

Java代碼 
  1. ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));  
  2. for(int i=0;i<list.size();i++){  
  3.     list.remove(i);  
  4. }  
  5. System.out.println(list);  

輸出結果是: 

Java代碼 
  1. [b,d]  

在這個方法中有一個嚴重的錯誤。當一個元素被刪除時,列表的大小縮小而且下標變化,因此當你想要在一個循環中用下標刪除多個元素的時候,它並不會正常的生效。 

你也許知道在循環中正確的刪除多個元素的方法是使用迭代,而且你知道java中的foreach循環看起來像一個迭代器,但實際上並非。考慮一下下面的代碼: 

Java代碼 
  1. ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));  
  2. for(String s:list){  
  3.     if(s.equals("a")){  
  4.         list.remove(s);  
  5.     }  
  6. }  

它會拋出一個ConcurrentModificationException異常。 

相反下面的顯示正常: 

Java代碼 
  1. ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));  
  2. Iterator<String> iter = list.iterator();  
  3. while(iter.hasNext()){  
  4.         String s = iter.next();  
  5.         if(s.equals("a")){  
  6.             iter.remove();  
  7.     }  
  8. }  

.next()必須在.remove()以前調用。在一個foreach循環中,編譯器會使.next()在刪除元素以後被調用,所以就會拋出ConcurrentModificationException異常,你也許但願看一下ArrayList.iterator()的源代碼。 

4.Hashtable與HashMap的對比  

就算法而言,哈希表是數據結構的一個名字。可是在java中,這個數據結構的名字是HashMap。Hashtable與HashMap的一個重要不一樣點是Hashtable是同步的。因此你常常不須要Hashtable,相反HashMap常常會用到。 

具體請看: 

5.在集合中使用原始類型  

在Java中原始類型與無界通配符類型很容易混合在一塊兒,拿Set來講,Set是一個原始類型,而Set<?>是無界的通配符類型。 
考慮下面使用原始類型List做爲參數的代碼: 

Java代碼 
  1. public static void add(List list,Object o){  
  2.     list.add(o);  
  3. }  
  4. pulbic static void main(String[] args){  
  5.     List<String> list = new ArrayList<String>();  
  6.     add(list,10);  
  7.     String s = list.get(0);  

這段代碼會拋出一個異常: 

Java代碼 
  1. Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String  
  2.   
  3.     at ...  

使用原生類型集合是危險的,這是由於原生類型集合跳過了泛型類型檢查,而且不是安全的,在Set、Set<?>和Set<Object>中有很大的不一樣,具體請看 Raw type vs. Unbounded wildcard Type Erasure 。 

6.訪問級別  

程序員們常用public做爲類字段的修飾符,能夠很簡單的經過引用獲得值,但這是一個壞的設計,按照經驗,分配給成員變量的訪問級別應該儘量的低。 

具體請看: public, default, protected, and private  

7.ArrayList與LinkedList的對比  

當程序員們不知道ArrayList與LinkedList的區別時,他們常用ArrayList,由於它看起來比較熟悉。然而,它們以前有巨大的性能差異。簡而言之,若是有大量的增長刪除操做而且沒有不少的隨機訪問元素的操做,應該首先LinkedList。若是你剛接觸它們,請查看 ArrayList vs. LinkedList 來得到更多關於它們性能的信息。 

8.可變與不可變  

不可變對象有許多的優勢,好比簡單,安全等等。可是對於每個不一樣的值都須要一個獨立的對象,太多的對象可能會形成大量的垃圾回收。當選擇可變與不可變時應該有一個平衡。 
通常的,可變對象用來避免產生大量的中間對象。一個典型的例子是鏈接大量的字符串。若是你用一個不可變的字符串,你會產生不少須要進行垃圾回收的對象。這很浪費CPU的時間,使用可變對象是正確的解決方案(好比StringBuilder)。 

Java代碼 
  1. String result="";  
  2. for(String s: arr){  
  3.     result = result + s;  
  4. }  

有時在某些狀況下也是須要可變對象的,好比將可變對象做爲參數傳入方法,你不用使用不少語句即可以獲得多個結果。另一個例子是排序和過濾:固然,你能夠寫一個方法來接收原始的集合,而且返回一個排好序的集合,可是那樣對於大的集合就太浪費了。(來自StackOverFlow的 dasblinkenlight’s的答案

具體請看: Why String is Immutable?  

9.父類與子類的構造函數  



這個編譯期錯誤的出現是父類默認的構造方法未定義,在java中,若是一個類沒有定義構造方法,編譯器會默認的爲這個類添加一個無參的構造方法。若是在父類中定義了構造方法,在這個例子中是Super(String s),編譯器就不會添加默認的無參構造方法,這就是上面這個父類的情形。 

子類的構造器,不論是無參還有有參,都會調用父類的無參構造器。由於編譯器試圖在子類的兩個構造方法中添加super()方法。可是父類默認的構造方法未定義,編譯器就會報出這個錯誤信息。 

想要修復這個問題,能夠簡單的經過1)在父類中添加一個Super()構造方法,像下面這樣: 

Java代碼 
  1. public Super(){  
  2.     System.out.println("Super");  
  3. }  

或者2)移除父類自定義的構造方法,或者3)在子類的構造方法中調用父類的super(value)方法。 

具體請看: Constructor of Super and Stub  

10.使用"   "仍是構造器  

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

Java代碼 
  1. //1.使用字符串  
  2. String x = "abc";  
  3. //2.使用構造器  
  4. String y = new String("abc");  

有什麼區別? 

下面的例子會給出一個快速的答案: 

Java代碼 
  1. String a = "abc";  
  2. String b = "abc";  
  3. System.out.println(a==b);//true  
  4. System.out.println(a.equals(b));//true  
  5.    
  6. String c = new String("abc");  
  7. String d = new String("abc");  
  8. System.out.println(a==b);//false  
  9. System.out.println(a.equals(b));//true  

關於它們內存分配的更多信息,請參考 Create Java String Using 」 」 or Constructor?.  

未來的工做  

這個列表是我基於大量的github上的開源項目,Stack overflow上的問題,還有一些流行的google搜索的分析。沒有明顯示的評估證實它們是前10,但它們絕對是很常見的。若是您不一樣意任一部分,請留下您的評論。若是您能提出其它一些常見的錯誤,我將會很是感激。 

原文連接:  programcreek  翻譯:  ImportNew.com  林林  
譯文連接:  http://www.importnew.com/12074.html
相關文章
相關標籤/搜索