JavaRush /Java Blog /Random-TW /Java 開發人員常犯的 10 個錯誤
theGrass
等級 24
Саратов

Java 開發人員常犯的 10 個錯誤

在 Random-TW 群組發布
Java 開發人員常犯的 10 個錯誤 - 1
此清單包括Java開發人員經常犯的 10 個錯誤。
  1. 將數組轉換為ArrayList

    要將陣列轉換為ArrayList,開發人員經常使用以下方法:

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

    Arrays.asList()會傳回一個類對象,它是該類的ArrayList內部私有靜態類,並且這不是一個類,該類包含方法,,,但不包含任何添加元素的方法,其大小是固定的。要創建一個真正的,請執行以下操作:(private static class)Arraysjava.util.ArrayList.java.util.Arrays.ArrayListset()get()contains()java.util.ArrayList

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

    類別建構子java.util.ArrayList可以將所有實作介面的物件作為參數Collection,該介面的實作由類別繼承。java.util.Arrays.ArrayList

    (私有靜態類別 ArrayList<E> 擴充 AbstractList<E> 實作 RandomAccess、java.io.Serializable)。

  2. 檢查數組中的特定值。

    開發人員經常這樣做:

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

    該代碼可以工作,但無需將其轉換ListSet. 轉換為Set將需要額外的時間。其實一切都很簡單:

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

    或者

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

    第一種方法要短得多。

  3. 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會減少並且元素索引會發生變化。

    因此,如果您想使用索引刪除循環中的多個元素,請避免使用此方法。

    您可能知道使用迭代器是刪除循環中元素的正確解決方案,並且您知道樣式循環的for-each工作方式類似於迭代器,但事實並非如此。

    考慮以下程式碼:

    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()

    在循環風格中for-each,編譯器將呼叫該方法remove(),只有在那時next(),才會引發錯誤ConcurrentModificationException。你可以看一下程式碼ArrayList.iterator()

  4. Hashtable反對HashMap

    由於對應的實現,Hashtable是資料結構的名稱。

    但在Java中,資料結構的名稱是HashMapHashtable和之間的主要區別之一HashMap是它是Hashtable同步的,因此不應該Hashtable在 where 中使用HashMap

    HashMap 對比 樹狀圖對比 哈希表對比 LinkedHashMap

    關於地圖介面的 10 個基本問題

  5. 使用沒有內容限制的集合

    В Java часто путают коллекции без ограничений по содержимому, и коллекции с маской по типу содержимого. К примеру, для множеств - Set это коллекция без ограничений по содержимому, а Set<?> — коллекция у которой все-таки есть ограничения, но эти ограничения ничего на самом деле не ограничивают. Рассмотрим следующий code, где 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);
    }

    Данный code выбросит исключение:

    Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    	at …

    Использование коллекций без ограничений по содержимому очень опасно, потому что вы не можете быть уверенными в том что там лежит внутри. А для того чтобы понять всю глубину разницы между Set, Set<?> и Set<Object> — почитайте вот эту и эту ссылки.

  6. Уровень доступа

    Очень часто для полей класса разработчики используют модификатор доступа public. Так проще получить meaning поля напрямую. Правильнее использовать How можно более ограниченный доступ к членам класса.

    public, default, protected, and private.

  7. ArrayList против LinkedList

    Когда разработчики не знают чем отличается ArrayList от LinkedList, они используют первый в силу его большей известности. Однако, есть огромная разница в производительности между ними. На самом деле, выбор между ними должен быть продиктован их внутренними особенностями — ArrayList позволяет быстро производить доступ к произвольному элементу массива, а LinkedList — быстро добавлять/удалять элементы в массиве. Почитайте статью по ссылке ArrayList vs. LinkedList чтобы понять причины их разной производительности.

  8. Mutable (Изменяемый) против Immutable (Неизменяемый)

    Неизменяемый an object имеет много преимуществ: простота, безопасность и т.д. Но он требует отдельного an object для каждого нового значения, и за слишком большое количество an objectов придется заплатить понижением производительности. Должен быть баланс при выборе между изменяемым и неизменяемым обьектом.

    В основном чтобы избежать подготовки промежуточных an objectов используется изменяемый an object. Один из классических примеров это конкатенация большого количества строк. Если вы используете неизменяемый an object типа String, то вы создаете много an objectов, которые сразу попадут в сборщик мусора. Это тратит время и энергию процессора, поэтому правильное решение это использование изменяемых обьектов (например StringBuilder).

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

    Еще один пример использования изменяемых an objectов — передача такого an object в метод. Это позволит вернуть результат в нем же, без создания лишних an objectов. При работе с an objectми большого размера, к примеру коллекциями, передача коллекции в метод для сортировки и возвращение результата в другой коллекции приводит к совершенно излишнему расходу ресурсов. (Ответ пользователя dasblinkenlight на Stack Overflow).

    Почему an object класса String неизменяем?

  9. Конструкторы классов Super и Sub

    Java 開發人員常犯的 10 個錯誤 - 2

    這個編譯錯誤是由於祖先類別沒有定義預設的構造函數所導致。在Java中,除非您自己指定類別建構函數,否則編譯器將建立一個不需要參數的預設建構函數。如果建構函式在類別中描述SuperSuper(String s){},則編譯器本身不會添加任何內容。這就是我們在範例中看到的。

    類別的建構函數Sub,無論是哪一個,都會呼叫該類別的預設建構函數Super,因為沒有指定其他內容。由於類別中沒有預設建構函數Super,這將導致編譯錯誤。

    解決這個問題的第一個方法是給類別添加一個預設建構函數Super

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

    第二個選項是從類別中刪除我們描述的建構函數Super,以便編譯器建立預設建構函數。

    最後一個選項是添加super(value)對類別建構函數的調用Sub,以便調用現有的類別建構函數而不是預設建構函數Super

    Super 和 Sub 的建構子

  10. 「」還是構造函數?

    建立字串有兩種方法:

    //1. использовать двойные кавычки
    String x = "abc";

    //2. использовать конструктор
    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 上的問題以及 Google 上的熱門查詢的分析。我不想證明它們真的是十大最嚴重的錯誤之一,但它們實際上很常見。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION