Array轉ArrayList

判斷一個數組是否包含某個值

在迴圈內部刪除List中的一個元素

HashTable與HashMap

使用集合原始型別(raw type)

訪問級別

ArrayList和LinkedList

可變與不可變

父類和子類的構造方法

“”還是構造方法

未來工作

《Java 2019 超神之路》

《Dubbo 實現原理與原始碼解析 —— 精品合集》

《Spring 實現原理與原始碼解析 —— 精品合集》

《MyBatis 實現原理與原始碼解析 —— 精品合集》

《Spring MVC 實現原理與原始碼解析 —— 精品合集》

《Spring Boot 實現原理與原始碼解析 —— 精品合集》

《資料庫實體設計合集》

《Java 面試題 —— 精品合集》

《Java 學習指南 —— 精品合集》

這個列表總結了10個Java開發人員最常犯的錯誤。

Array轉ArrayList

當需要把Array轉成ArrayList的時候,開發人員經常這樣做:

List list = Arrays。asList(arr);

Arrays。asList()會返回一個ArrayList,但是要特別注意,這個ArrayList是Arrays類的靜態內部類,並不是java。util。ArrayList類。java。util。Arrays。ArrayList類實現了set(), get(),contains()方法,但是並沒有實現增加元素的方法(事實上是可以呼叫add方法,但是沒有具體實現,僅僅丟擲UnsupportedOperationException異常),因此它的大小也是固定不變的。為了建立一個真正的java。util。ArrayList,你應該這樣做:

ArrayList arrayList = new ArrayList(Arrays。asList(arr));

ArrayList的構造方法可以接收一個Collection型別,而java。util。Arrays。ArrayList已經實現了該介面。

判斷一個數組是否包含某個值

開發人員經常這樣做:

Set set = new HashSet(Arrays。asList(arr));

return set。contains(targetValue);

以上程式碼可以正常工作,但是沒有必要將其轉換成set集合,將一個List轉成Set需要額外的時間,其實我們可以簡單的使用如下方法即可:

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

或者

for(String s: arr){

if(s。equals(targetValue))

return true;

}

return false;

第一種方法可讀性更強。

在迴圈內部刪除List中的一個元素

考慮如下程式碼,在迭代期間刪除元素:

ArrayList list = new ArrayList(Arrays。asList(“a”, “b”, “c”,“d”));

for (int i = 0; i < list。size(); i++) {

list。remove(i);

}

System。out。println(list);

結果列印:

[b, d]

在上面這個方法中有一系列的問題,當一個元素被刪除的時候,list大小減小,然後原先索引指向了其它元素。所以如果你想在迴圈裡透過索引來刪除多個元素,將不會正確工作。

你也許知道使用迭代器是在迴圈裡刪除元素的正確方式,或許你也知道foreach迴圈跟迭代器很類似,但事實情況卻不是這樣,如下程式碼:

ArrayList list = new ArrayList(Arrays。asList(“a”, “b”, “c”,“d”));

for (String s : list) {

if (s。equals(“a”))

list。remove(s);

}

將丟擲ConcurrentModificationException異常。

然而接下來的程式碼卻是OK的:

ArrayList list = new ArrayList(Arrays。asList(“a”, “b”, “c”,“d”));

Iterator iter = list。iterator();

while (iter。hasNext()) {

String s = iter。next();

if (s。equals(“a”)) {

iter。remove();

}

}

next()方法需要在remove()方法之前被呼叫,在foreach迴圈裡,編譯器會在刪除元素操作化呼叫next方法,這導致了ConcurrentModificationException異常。更多詳細資訊,可以檢視ArrayList。iterator()的原始碼。

HashTable與HashMap

從演算法的角度來講,HashTable是一種資料結構名稱。但是在Java中,這種資料結構叫做HashMap。HashTable與HashMap的一個主要的區別是HashTable是同步的,所以,通常來說,你會使用HashMap,而不是Hashtable。

更多資訊:HashMap vs。 TreeMap vs。 Hashtable vs。 LinkedHashMap Top 10 questions about Map

使用集合原始型別(raw type)

在Java中,原始型別(raw type)和無界萬用字元型別很容易讓人混淆。舉個Set的例子,Set是原始型別,而Set是無界萬用字元型別。

請看如下程式碼,add方法使用了一個原始型別的List作為入參:

public static void add(List list, Object o){

list。add(o);

}

public static void main(String[] args){

List list = new ArrayList();

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 wildcard。

訪問級別

開發人員經常使用public修飾類欄位,雖然這很容易讓別人直接透過引用獲取該欄位的值,但這是一個不好的設計。根據經驗,應該儘可能的降低成員屬性的訪問級別。

相關閱讀:public, default, protected, and private

ArrayList和LinkedList

為什麼開發人員經常使用ArrayList和LinkedList,卻不知道他們之間的區別,因為它們看起來很像。然而它們之間有著巨大的效能差異。簡單的說,如果有大量的增加刪除操作並且沒有很多的隨機訪問元素的操作,應該首選LinkedList。

相關閱讀:ArrayList vs。 LinkedList

可變與不可變

不可變物件有很多優點,如簡單、安全等。但是對於每個不同的值都需要一個單獨的物件,太多的物件會引起大量垃圾回收,因此在選擇可變與不可變的時候,需要有一個平衡。

通常,可變物件用於避免產生大量的中間物件,一個經典的例子是大量字串的拼接。如果你使用一個不可變物件,將會馬上產生大量符合垃圾回收標準的物件,這浪費了CPU大量的時間和精力。使用可變物件是正確的解決方案(StringBuilder);

String result=“”;

for(String s: arr){

result = result + s;

}

另外,在有些其它情況下也是需要使用可變物件。例如往一個方法傳入一個可變物件,然後收集多種結果,而不需要寫太多的語法。另一個例子是排序和過濾:當然,你可以寫一個方法來接收原始的集合,並且返回一個排好序的集合,但是那樣對於大的集合就太浪費了。

更多閱讀:Why String is Immutable??

Why we need mutable classes?

父類和子類的構造方法

Java 程式設計師排行前 10 的錯誤,你有沒有中?

之所以出現這個編譯錯誤,是因為父類的預設構造方法未定義。在Java中,如果一個類沒有定義構造方法,編譯器會預設插入一個無引數的構造方法;但是如果一個構造方法在父類中已定義,在這種情況,編譯器是不會自動插入一個預設的無參構造方法,這正是以上demo的情況;

對於子類來說,不管是無參構造方法還是有參構造方法,都會預設呼叫父類的無參構造方法;當編譯器嘗試在子類中往這兩個構造方法插入super()方法時,因為父類沒有一個預設的無參構造方法,所以編譯器報錯;

要修復這個錯誤,很簡單:

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

更多關於它們記憶體分配的資訊,請參考Create Java String Using ” ” or Constructor??

未來工作

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

譯文連結:

http://www。

programcreek。com/2014/0

5/top-10-mistakes-java-developers-make/

作者:風一樣的碼農

:-D 搜尋微訊號(ID:

芋道原始碼

),可以獲得各種 Java 原始碼解析、原理講解、面試題、學習指南。

:-D 並且,回覆【

書籍

】後,可以領取筆者推薦的各種 Java 從入門到架構的 100 本書籍。

:-D 並且,回覆【

技術群

】後,可以加入專門討論 Java、後端、架構的技術群。

Java 程式設計師排行前 10 的錯誤,你有沒有中?

來吧,騷年~