首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 高質量代碼指南:數組與集合的 9 大核心最佳實踐

     編輯:Java 相關知識

前言

在 Java 開發中,數組與集合是最基礎也最常用的數據結構。雖然集合框架功能豐富,但數組在性能敏感場景下仍有不可替代的優勢。本文總結 9 大核心最佳實踐,助你寫出高效、健壯的代碼。

1. 性能優先:選擇數組

核心觀點:數組存儲基本類型,避免裝箱/拆箱開銷;集合底層也是數組實現,但存儲包裝類型。

性能對比

// 基本類型數組:連續內存,無對象頭開銷
int[] intArray = new int[1000000];

// 集合:每個元素都是 Integer 對象,佔用更多內存,訪問需拆箱
List<Integer> intList = new ArrayList<>(1000000);

適用場景

  • 大數據量、高頻數值計算
  • 內存敏感環境
  • 與本地代碼(JNI)交互

2. 需要動態擴容:封裝變長數組

ArrayList 擴容本質是 Arrays.copyOf() 創建新數組並複製。可自行封裝變長數組:

public class DynamicArray<T> {
    private T[] data;
    private int size = 0;
    private static final int DEFAULT_CAPACITY = 10;
    
    @SuppressWarnings("unchecked")
    public DynamicArray() {
        data = (T[]) new Object[DEFAULT_CAPACITY];
    }
    
    public void add(T element) {
        ensureCapacity(size + 1);
        data[size++] = element;
    }
    
    private void ensureCapacity(int minCapacity) {
        if (minCapacity > data.length) {
            int newCapacity = data.length * 3 / 2; // 1.5 倍擴容
            data = Arrays.copyOf(data, newCapacity);
        }
    }
}

3. 警惕淺拷貝陷阱

Arrays.copyOf()、clone()、System.arraycopy() 均為淺拷貝。

// 陷阱示例
int[][] matrix = {{1,2}, {3,4}};
int[][] copy = Arrays.copyOf(matrix, matrix.length);
copy[0][0] = 99;
// 原數組也被修改!matrix[0][0] == 99

深拷貝方案:手動遞歸拷貝、序列化反序列化、JSON 轉換、Stream API。

4. 明確場景:為集合指定初始容量

ArrayList 默認初始容量 10,擴容觸發 copyOf 開銷大。

// 差:多次擴容
List<User> users = new ArrayList<>();
for (int i = 0; i < 10000; i++) users.add(getUser());

// 優:一次分配
List<User> users = new ArrayList<>(10000);

同理適用於 HashMap:new HashMap<>(expectedSize),避免重複 rehash。

5. 選擇合適的最值算法

// 方案一:單次遍歷 O(n) - 推薦
public static int getMaxLinear(int[] data) {
    int max = data[0];
    for (int i = 1; i < data.length; i++) {
        if (data[i] > max) max = data[i];
    }
    return max;
}

// 方案二:排序後取值 O(n log n) - 不推薦用於單純求最值
public static int getMaxBySort(int[] data) {
    Arrays.sort(data);
    return data[data.length - 1];
}

除非需要有序數組,否則單次遍歷最優。

6. 基本類型數組轉 List 的陷阱

int[] nums = {1, 2, 3};
List<int[]> list = Arrays.asList(nums); // 錯誤!List<int[]> size=1
// 正確做法:
List<Integer> list = Arrays.stream(nums).boxed().collect(Collectors.toList());
// 或使用 Guava: Ints.asList(nums)

原因:基本類型數組無法泛型化,被視為單個對象。

7. asList 返回的 List 不可變


List list = Arrays.asList("a", "b", "c");
list.add("d"); // 拋出 UnsupportedOperationException
list.set(0, "x"); // 允許:修改現有元素

原因:返回的是 Arrays.ArrayList(內部類),未實現 add/remove。需轉換:new ArrayList<>(Arrays.asList(...))。

8. 不同結構用不同遍歷方式

集合類型推薦遍歷原因
ArrayListfor 循環下標訪問實現 RandomAccess,隨機訪問 O(1)
LinkedListforeach / 迭代器雙向鏈表,下標訪問 O(n),順序訪問 O(1)

// ArrayList:下標遍歷最快
for (int i = 0, size = list.size(); i < size; i++) {
    process(list.get(i));
}

// LinkedList:迭代器遍歷
for (String s : linkedList) {
    process(s);
}

9. 適時選擇 ArrayList 或 LinkedList

操作ArrayListLinkedList
隨機訪問O(1) ✓O(n)
頭/尾插入刪除O(n)O(1) ✓
中間插入刪除O(n)O(n) 但無需移動數組
內存佔用較小較大(節點對象開銷)

經驗法則:默認用 ArrayList;作為隊列/棧、頻繁頭尾操作用 LinkedList 或 ArrayDeque。

10. 列表比較只關心元素

集合 equals() 已重寫:只比較元素內容與順序,不比較具體實現類。


List<Integer> arrayList = new ArrayList<>(Arrays.asList(1, 2));
List<Integer> linkedList = new LinkedList<>(Arrays.asList(1, 2));
arrayList.equals(linkedList); // true

這讓面向接口編程更安心。

總結速查表

| 场景 | 推薦選擇 | |------|----------| | 高性能數值計算 | 基本類型數組 | | 動態集合、隨機訪問 | ArrayList(初始容量) | | 隊列、棧、頻繁頭尾操作 | ArrayDeque / LinkedList | | 需要不可變列表 | List.of() / Collections.unmodifiableList() | | 基本類型轉 List | Stream.boxed() / Guava | | 多線程環境 | CopyOnWriteArrayList / ConcurrentHashMap |
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved