在日常開發中,「判斷數組是否包含某值」是高頻操作。本文對比 List.contains、Set.contains、for 循環、Arrays.binarySearch、ArrayUtils.contains 五種方案,通過實測數據揭示不同數據量下的性能差異,指導選型。
public static boolean useList(String[] arr, String target) {
return Arrays.asList(arr).contains(target);
}
public static boolean useSet(String[] arr, String target) {
Set set = new HashSet<>(Arrays.asList(arr));
return set.contains(target);
}
public static boolean useLoop(String[] arr, String target) {
for (String s : arr) {
if (s.equals(target)) return true;
}
return false;
}
public static boolean useBinarySearch(String[] arr, String target) {
// 必須確保數組已排序!
int idx = Arrays.binarySearch(arr, target);
return idx >= 0;
}
import org.apache.commons.lang3.ArrayUtils;
public static boolean useArrayUtils(String[] arr, String target) {
return ArrayUtils.contains(arr, target);
}
| 數組長度 | List | Set | Loop | BinarySearch | ArrayUtils |
|---|---|---|---|---|---|
| 5 (小) | 13 | 72 | 5 | 9 | 181 |
| 1,000 (中) | 112 | 2,055 | 99 | 12 | 181 |
| 10,000 (大) | 1,590 | 23,819 | 1,526 | 12 | 3,125 |
Arrays.asList 創建 List 視圖 → 迭代器遍歷 → equals 比較源碼顯示其本質也是 for 循環遍歷,並處理了 null 值、類型檢查等邊界情況:
// ArrayUtils.contains 核心邏輯簡化
for (int i = startIndex; i < array.length; i++) {
if (objectToFind == null) {
if (array[i] == null) return true;
} else if (objectToFind.equals(array[i])) {
return true;
}
}
return false;
性能介於手寫循環與集合之間,優勢在於代碼復用、邊界處理、可讀性。
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 一般業務、數組較小(<1000) | for 循環 或 ArrayUtils.contains | 性能最優、無依賴 / 代碼乾淨、處理邊界 |
| 高頻查詢、大數組、可預排序 | Arrays.binarySearch | O(log n) 查找,一次排序多次受益 |
| 極高性能要求、海量數據 | HashSet/HashMap 預構建 | O(1) 查找,空間換時間 |
| 基本類型數組 | for 循環 | 避免自動裝箱開銷 |
// 簡潔但有 Stream 創建開銷,性能接近 List 方案
boolean exists = Arrays.stream(arr).anyMatch(target::equals);
結論:不要盲目用 List/Set 包裝數組查找。理解底層機制,根據數據量、頻率、有序性選擇最優方案。工具類 ArrayUtils 是工程落地的不二之選,關鍵時刻手寫循環性能最強。