原文出自:http://www.programcreek.com/2014/05/top-10-mistakes-java-developers-make/java
本文總結了Java程序員常犯的10個錯誤。程序員
把Array轉化成ArrayList,程序員常常用如下方法:算法
List
Arrays.asList() 實際上返回一個ArrayList,可是這個ArrayList是Arrays的一個內部私有類,而不是java.util.ArrayList類。這個私有類java.util.Arrays.ArrayList有set(), get(), contains()方法,可是不可以添加新的元素。它的大小是固定的。若是你想要一個java.util.ArrayList,正確的方法是:
ArrayList
java.util.ArrayList的構造函數能夠接受一個集合類型。java.util.Arrays.ArrayList也繼承了集合類型,因此能夠做用參數使用。
開發人員常常作的是:數據結構
Set
return set.contains(targetValue);
這個代碼是工做的,但沒有沒有效率。把列表轉換成set沒有必要,須要額外的時間。正確的方法是:
Arrays.asList(arr).contains(targetValue);
或者,一個簡單的loop:oop
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
第一種比第二種更具備可讀性。性能
考慮下面的代碼,迭代過程當中刪除元素:ui
ArrayList
for (int i = 0; i < list.size(); i++) {
list.remove(i);
}
System.out.println(list);
這段代碼的輸出是:
[b, d]
這個方法有一個嚴重的問題。當元素被移除,該列表的大小縮減,元素索引也隨之發生了變化。因此,若是你想經過使用索引來刪除一個循環內的多個元素,就會致使錯誤的結果。
你可能猜到可使用iterator來刪除循環中的元素。在Java中的foreach循環的工做原理就像一個iterator。 可是在這裏也會發生錯誤。請看下面的代碼:
ArrayList
for (String s : list) {
if (s.equals("a"))
list.remove(s);
}
上面的foreach loop代碼會拋出一個異常ConcurrentModificationException. 可是下面這段代碼不會。
ArrayList
Iterator
while (iter.hasNext()) {
String s = iter.next();
if (s.equals("a")) { iter.remove(); }
}
經過分析ArrayList.iterator()的原代碼,咱們能夠發現next()方法必需要在remove()方法前被調用。在foreach loop中,編譯器產生的代碼會先調用next()方法,從而產生異常ConcurrentModificationException。請查看ArrayList.iterator()的原代碼。
按照算法慣例,Hashtable是數據結構的名稱。但在Java中,數據結構的名稱是HashMap。Hashtable是同步的版本。因此不少時候你並不須要Hashtable,而是HashMap。 這兩篇文章詳細介紹了各類Map的區別和常見的問題: HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap, Map常見10大問題,
在Java中,原始類型和無界通配符類型很容易混在一塊兒。以Set爲例,Set是原始類型,而Set>是無界通配符類型。 考慮下面的代碼,它使用原始類型的List做爲參數: public static void add(List list, Object o){ list.add(o); } public static void main(String[] args){ List
不少時候,開發者使用public修飾字段。這樣作的好處是很容易經過直接引用來獲取字段的值,可是這是一個很是糟糕的設計。經驗法則是「給成員的訪問級別儘量低」。能夠查看Java4種不一樣的訪問級別public, default, protected, and private。
當開發人員不知道ArrayList和LinkedList的區別的時候,他們常用的是ArrayList,可能由於它看起來面熟。可是ArrayList和LinkedList之間有巨大的性能差別。 簡單來講若是有大量的添加/刪除操做,而沒有不少隨機存取操做,LinkedList的應該是首選。能夠查看ArrayList與LinkedList瞭解它們之間更多的區別。
不可變對象有不少優勢,如簡單性,安全性等。可是它須要爲每一個不一樣的值創造一個單獨的對象,對象太多可能會致使垃圾回收的成本高。因此可變和不可變之間進行選擇時應該有一個平衡。
通常狀況下,使用可變對象,以免產生過多的中間對象。一個經典的例子是串聯了大量的字符串。若是使用的是不可變的字符串String,會產生不少能夠垃圾回收的對象。這樣既浪費時間也浪費CPU的運算能力,使用可變對象是正確的解決方案(如StringBuilder)。
String result="";
for(String s: arr){
result = result + s;
}
另一些狀況,可變對象剛更加合適可取。例如排序(Collections.sort())。若是Collection是不可變的,排序方法每次將會返回一個新的Collection,這樣會極其浪費資源。 能夠看看爲何在Java中String被設計成不可變?
以上這段代碼出現編譯錯誤,由於默認的父類構造函數未定義。在Java中,若是一個類沒有定義構造函數,編譯器會默認插入一個默認的無參數構造函數。若是程序員定義構造函數,編譯器將不插入默認的無參數構造函數。上面的代碼因爲自定義了有參數的構造函數,編譯器再也不插入無參數的構造函數。子類的構造函數,不管是有參數或無參數,都將調用父類無參構造函數。當子類須要父類的無參數構造函數的時候,就發生了錯誤。
解決這個問題,能夠1)增長一個父類構造函數
public Super(){
System.out.println("Super");
}
,或2)刪除自定義的父類構造函數,或3)添加super(value)到子類構造函數。更多請查看父類和子類的構造函數。
字符串能夠經過兩種方式建立:
//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字符串使用「」或構造函數?
小結
以上是我根據GitHub上的開源項目,Stack Overflow上的問題,和谷歌熱門搜索詞所作的總結。雖然它們不是準確的top 10,但很常見的。若是你有不一樣的觀點或者指出更常見的錯誤,請留言。我也會更新這個列表。很是感謝。