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

Java 陣列操作進階技巧:排序、搜尋、包裝轉換與 Collection 互操作

     編輯:Java 相關知識

前言

Java 陣列是固定大小、同質型別的資料結構,雖然 Collection 框架更靈活,但陣列在效能敏感、底層互操、原始型別處理上仍不可或缺。java.util.Arrays 提供豐富靜態方法,配合反射 API 可實現陣列與 Collection 的無縫轉換。

一、陣列排序

基本型別陣列排序


import java.util.Arrays;

int[] scores = {85, 92, 78, 96, 88};
Arrays.sort(scores); // 升序,原地排序(Dual-Pivot Quicksort)
// 結果:[78, 85, 88, 92, 96]

// 指定範圍排序
Arrays.sort(scores, 1, 4); // 只排索引 1~3
// 結果:[78, 85, 88, 92, 96] (此例無變化)

物件陣列排序(自然順序 / Comparator)


String[] names = {"Bob", "Alice", "Charlie"};
Arrays.sort(names); // 自然順序 (Comparable)
// 結果:["Alice", "Bob", "Charlie"]

// 自定義比較器:長度降序
Arrays.sort(names, (a, b) -> Integer.compare(b.length(), a.length()));
// 結果:["Charlie", "Alice", "Bob"] (長度 7, 5, 3)

平行排序 (Java 8+)


// 大陣列多核排序,閾值約 8192 元素
Arrays.parallelSort(largeArray); 

二、二分搜尋

前提:陣列必須已排序


int[] sorted = {10, 20, 30, 40, 50};

int idx = Arrays.binarySearch(sorted, 30); // 找到 → 返回索引 2
int idx2 = Arrays.binarySearch(sorted, 35); // 未找到 → 返回 (-(插入點) - 1) = -3

// 插入點計算
int insertPos = -idx2 - 1; // = 2,表示應插在索引 2 (30 和 40 之間)

自定義比較器搜尋


String[] byLength = {"a", "bb", "ccc", "dddd"};
// 必須用相同比較器排序過
Arrays.sort(byLength, Comparator.comparingInt(String::length));
int pos = Arrays.binarySearch(byLength, "xx", Comparator.comparingInt(String::length));
// 找長度 2 的字串位置

三、原始型別陣列 ↔ 包裝型別陣列轉換

手動轉換(效能最佳)


// int[] → Integer[]
int[] primitive = {1, 2, 3};
Integer[] boxed = new Integer[primitive.length];
for (int i = 0; i < primitive.length; i++) {
    boxed[i] = primitive[i]; // 自動裝箱
}

// Integer[] → int[]
Integer[] boxed2 = {4, 5, 6};
int[] primitive2 = new int[boxed2.length];
for (int i = 0; i < boxed2.length; i++) {
    primitive2[i] = boxed2[i]; // 自動拆箱
}

Stream API 一行轉換 (Java 8+)


int[] prim = {1, 2, 3};
Integer[] boxed = Arrays.stream(prim).boxed().toArray(Integer[]::new);

Integer[] boxed2 = {4, 5, 6};
int[] prim2 = Arrays.stream(boxed2).mapToInt(Integer::intValue).toArray();

Apache Commons Lang / Guava 工具類


// Apache Commons Lang
int[] prim = ArrayUtils.toPrimitive(new Integer[]{1,2,3});
Integer[] boxed = ArrayUtils.toObject(new int[]{1,2,3});

// Guava
int[] prim = Ints.toArray(List.of(1,2,3));
List list = Ints.asList(1,2,3);

四、陣列與 Collection 互操作

陣列 → List (固定大小視圖)


String[] arr = {"A", "B", "C"};
List list = Arrays.asList(arr); // 返回固定大小 List 視圖

// 特性:
list.set(1, "Z"); // 允許修改元素 → 原陣列同步變化
// list.add("D"); // 拋出 UnsupportedOperationException
// list.remove(0); // 拋出 UnsupportedOperationException

陣列 → 可修改 List


// Java 9+
List modifiable = new ArrayList<>(List.of(arr));

// Java 8
List modifiable = new ArrayList<>(Arrays.asList(arr));

// Guava
List modifiable = Lists.newArrayList(arr);

Collection → 陣列


List list = List.of("X", "Y", "Z");

// 正確方式:傳入型別陣列
String[] arr1 = list.toArray(new String[0]); // JVM 優化:新建精確大小陣列
String[] arr2 = list.toArray(String[]::new); // Java 11+ 方法引用寫法

// 錯誤方式:toArray() 返回 Object[],無法轉型為 String[]
// String[] bad = (String[]) list.toArray(); // ClassCastException

五、反射操作陣列

適用於運行期型別未知的通用工具開發


import java.lang.reflect.Array;

public class ArrayUtils {
    /** 通用陣列複製並轉型 */
    @SuppressWarnings("unchecked")
    public static  T[] copyAndCast(Object srcArray, Class componentType) {
        if (srcArray == null || !srcArray.getClass().isArray()) return null;
        int len = Array.getLength(srcArray);
        T[] dest = (T[]) Array.newInstance(componentType, len);
        for (int i = 0; i < len; i++) {
            dest[i] = componentType.cast(Array.get(srcArray, i));
        }
        return dest;
    }
    
    /** 建立指定型別、長度的陣列 */
    public static Object newArray(Class componentType, int length) {
        return Array.newInstance(componentType, length);
    }
}

六、多維陣列操作

建立與初始化


// 規則二維陣列
int[][] matrix = new int[3][4]; // 3 行 4 列

// 不規則陣列
int[][] jagged = {
    {1, 2},
    {3, 4, 5, 6},
    {7}
};

深度複製


int[][] original = {{1,2}, {3,4}};
// 錯誤:淺複製
int[][] shallow = original.clone(); // 內層陣列共用引用

// 正確:深度複製
int[][] deep = new int[original.length][];
for (int i = 0; i < original.length; i++) {
    deep[i] = original[i].clone(); // 或 Arrays.copyOf(original[i], original[i].length)
}

平行流處理 (Java 8+)


int[][] data = largeMatrix;
// 計算每行總和
int[] rowSums = Arrays.stream(data)
    .parallel()
    .mapToInt(row -> Arrays.stream(row).sum())
    .toArray();

七、效能與記憶體考量

操作時間複雜度空間複雜度備註
Arrays.sort (基本型別)O(n log n)O(1)Dual-Pivot Quicksort,原地
Arrays.sort (物件)O(n log n)O(n)TimSort,穩定,需輔助陣列
Arrays.binarySearchO(log n)O(1)前提:已排序
Arrays.asListO(1)O(1)視圖,無複製
List.toArrayO(n)O(n)新建陣列複製
Stream 轉換O(n)O(n)中間物件開銷較大

八、常見陷阱避坑指南

  1. Arrays.asList 陷阱:基本型別陣列會被當作單一元素
    List list = Arrays.asList(new int[]{1,2}); // size() == 1
  2. 陣列 covariance 風險:Object[] objArr = new String[10]; objArr[0] = new Integer(1); // 運行期 ArrayStoreException
  3. toArray() 型別擦除:必須傳入型別陣列或方法引用
  4. 並行排序門檻:小陣列用 parallelSort 反而較慢
  5. 基本型別無法泛型:List 不合法,必須用 List 或第三方庫

總結

掌握 Arrays 工具類、Stream API、反射陣列操作與 Collection 互轉技巧,能讓你在處理大量資料、高效能計算、底層庫開發時遊刃有餘。原則:能用基本型別陣列就不用包裝型別,能用 Arrays 靜態方法就不用手寫迴圈,能用 Stream 表達意圖就不用命令式迴圈。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved