Arrays工具類的使用(十七)

勿以惡小而爲之,勿以善小而不爲--------------------------劉備
勸諸君,多行善事積福報,莫作惡

上一章簡單介紹了 JavaSE實現任務調度的三種方式(十六),如果沒有看過,請觀看上一章

一. Arrays 工具類

一.一 爲什麼出現 Arrays 工具類

在開發當中,雖然經常使用的是集合維護數據,但是數組的使用頻率也是很高的,尤其是在 Java SE 階段。

數組,常見的有 添加數據,刪除數據,更新數據,搜索數據,排序, 獲取長度,數組最大/小值 等很多內容。

在 JDK 1.2 版本時, 爲了方便維護數組, 增加了一個 Arrays 的工具類。

Arrays 類 位於 java.utils 包下。

一.二 Arrays 工具類的常見方法

數組,有多種類型的數組, int,float,char,boolean 等, 所以Arrays 工具類中裏面有很多的重載方法。 這裏只以最常用的 int 類型進行舉例。

方法簽名 方法作用
轉換成集合:
public static <T> List<T> asList(T… a) 將可變參數數組轉換成集合
打印輸出:
public static String toString(int[] a) 輸出數組中的內容
查詢搜索的:
public static int binarySearch(int[] a, int key) 從數組a 裏面查詢key ,返回索引位置。
public static int binarySearch(int[] a,

int fromIndex, int toIndex,int key)
從數組a 的fromIndex 到 toIndex 索引位置 查詢 key,限定了查詢的範圍
複製數組的:
public static int[] copyOf(int[] original, int newLength) 複製數組original, 從0索引開始,長度爲newLength,返回 一個新數組
public static int[] copyOfRange(int[] original, int from, int to) 複製數組 original, 從from 開始,到to 結束, 不包括to, 返回一個新的數組。 是範圍性複製
比較數組是否相同的:
public static boolean equals(int[] a, int[] a2) 比較兩個數組的內容是否一樣,如果一樣,返回true,不一樣,返回false
填充數組的:
public static void fill(int[] a, int val) 將 val 的值填充到數組裏面,全部替換
public static void fill(int[] a, int fromIndex, int toIndex, int val) 只替換 fromIndex 到toIndex 的內容,不包括toIndex 處的元素
二元操作的:
public static void parallelPrefix(int[] array, IntBinaryOperator op) 對數組 array 進行二元操作,具體看例子
public static void parallelSetAll(int[] array, IntUnaryOperator generator) 對數組中每一個元素進行操作, 具體看例子
public static void setAll(int[] array, IntUnaryOperator generator) 全部做表達式操作,具體看例子
排序的:
public static void parallelSort(int[] a) 併發排序, 是升序
public static void parallelSort(int[] a, int fromIndex, int toIndex) 對 fromIndex 到 toIndex 範圍內的數字進行併發排序
public static void sort(int[] a) 普通排序, 是升序
public static void sort(int[] a, int fromIndex, int toIndex) 對fromIndex 到toIndex 範圍內的數字進行排序
轉換成流:
public static IntStream stream(int[] array) 將數組轉換成流
public static IntStream stream(int[] array, int startInclusive, int endExclusive) 將 startInclusive 到 endExclusive 的部分轉換成流

二. Arrays 工具類的具體使用

二.一 轉換成集合 asList(T … a)

二.一.一 例子

 @Test
    public void asListTest(){
        //轉換成集合
        List<Integer> arrList=Arrays.asList(1,2,3,4,5,6,7,8,9);

        System.out.println("轉換成後長度:"+arrList.size()+",內容是:"+arrList.toString());
    }

控制檯打印輸出:

有圖片

二.一.二 簡單內部實現

有圖片

注意,內部構造的 ArrayList 並不是 java.util.ArrayList, 而是 Arrays 內部類 ArrayList.

二.二 打印內容 toString(int[] a)

二.二.一 例子

 @Test
public void toStringTest(){
    //數組
    int[] arr={1,2,3,4,5,6,7,8,9};
    //打印內容
    String str=Arrays.toString(arr);

    System.out.println("打印內容:"+str);
}

控制檯打印輸出:

有圖片

二.二.二 簡單內容實現

public static String toString(int[] a) {
		//爲空時, 返回 null 
        if (a == null)
            return "null";
		//長度爲0 時, 返回 [] 
        int iMax = a.length - 1;
        if (iMax == -1)
            return "[]";

        StringBuilder b = new StringBuilder();
        b.append('[');
        for (int i = 0; ; i++) {
            b.append(a[i]);
            if (i == iMax)
               {
					 return b.append(']').toString();
				}
            b.append(", ");
        }
    }
}

二.三 查詢搜索 binarySearch(int[] a, int key)

二.三.一 無範圍的例子

  @Test
    public void binarySearchTest1(){
        //數組
        int[] arr={1,2,3,4,5,6,7,8,9};
        int index=Arrays.binarySearch(arr,5);
        System.out.println("查詢5的索引:"+index);
        index=Arrays.binarySearch(arr,10);
        System.out.println("查詢10的索引:"+index);
    }

控制檯打印輸出:

有圖片

內部實現,調用的是 有範圍的查詢, 查詢的是 從0 到 arr.length 範圍的

二.三.二 有範圍的例子

    @Test
    public void binarySearchTest2(){
        //數組
        int[] arr={1,2,3,4,5,6,7,8,9};
        int index=Arrays.binarySearch(arr,4,8,5);
        System.out.println("查詢5的索引:"+index);
        index=Arrays.binarySearch(arr,4,8,9);
        System.out.println("查詢不在範圍內的9的索引:"+index);
    }

控制檯打印輸出:

有圖片

二.三.三 簡單內部實現

 private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
		//不包括 toIndex 索引處的位置
        int high = toIndex - 1;

        while (low <= high) {
			//獲取中間位置, 二分查找
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
		// 如果沒有查找到, 返回的是 - (low+1), 並不一定是-1
        return -(low + 1);  // key not found.
    }

以 無範圍的 10 例子進行舉例, 傳入過來的參數依次是: 1~9的數組,0,9,10.

那麼 low=0, hight=8;

第一次循環: 0<=8, 成立。 mid=(0+8)/2=4, midVal=5, 5<10, 此時 low=4+1=5;

第二次循環: 5<=8, 成立, mid=(5+8)/2=6, midVal=7, 7<10, 此時 low=6+1=7;

第三次循環: 7<=8, 成立, mid=(7+8)/2=7, midVal=8, 8<10, 此時 low=7+1=8;

第四次循環: 8<=8, 成立, mid=(8+8)/2=8, midVal=9,9<10,此時 low=8+1=9;

9<=8, 不成立, 退出循環。 此時, low=9

返回 -(9+1)= -10, 最後結果返回 -10.

二.四 複製數組 copyOf 和範圍複製數組 copyOfRange

二.四.一 copyOf 小例子

@Test
    public void copyOfTest(){
        //數組
        int[] arr={1,2,3,4,5,6,7,8,9};
        //只複製前5個
        int[] newArr=Arrays.copyOf(arr,5);

        System.out.println("newArr新數組長度:"+newArr.length+",內容:"+Arrays.toString(newArr));
    }

控制檯打印輸出:

有圖片

內部調用的是 System 類的 arraycopy() 方法。

有圖片

二.四.二 copyOfRange 小例子

 @Test
    public void copyOfRnageTest(){
        //數組
        int[] arr={1,2,3,4,5,6,7,8,9};
        //只複製 3~7 索引的位置。 不包括7 索引處的元素
        int[] newArr=Arrays.copyOfRange(arr,3,7);

        System.out.println("newArr新數組長度:"+newArr.length+",內容:"+Arrays.toString(newArr));
    }

控制檯打印輸出:

有圖片

我們發現,內部調用的依然是 System 類的 arraycopy() 方法。

有圖片

那麼,接下來,我們就分析一下, System 類的 arraycopy() 方法 是如何實現數組複製的。

二.四.三 System 類的 arraycopy()

System 類位於 java.lang 包下, System 類用 final 進行修飾

  public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

該方法 arraycopy 用 native 進行修飾,是用其他底層語言寫的,可以快速進行數組複製。

這兒看不到具體的實現, 我們就仔細分析一下,各個參數吧。

src, 源數組。 即複製源是誰

srcPos, 從源數組的哪兒開始複製, 即複製的開始索引

dest ,目的數組, 即複製目的地是誰

destPos, 目的數組的源頭在哪,即複製目的地的開始索引。 不一定是從0開始複製,支持中間索引位置處複製

length, 複製的長度。

這五個參數的順序不能搞錯。

copyOf() 方法時,傳入過來的是 srcPos=0, destPos=0, length= Math.min(arr.length,newLength), 最小的那個長度。

表示從頭開始複製。 如果newLength> arr.length 的話, 那麼從 arr.length~newLength 處的值爲默認值。

copyOfRange() 方法時,傳入過來的是 srcPos=from, destPos=0,length=Math.min(arr.length-from, to-from)

二.四.四 System 類的 arraycopy() 方法舉例

   @Test
    public void arraycopyTest(){
        //源數組
        int[] arr={1,2,3,4,5,6,7,8,9};
        //目標
        int [] dest={100,101,102,103,104,105,106,107,108,109,110};

        // 從103處開始複製, 拿過來的是 開始位置是5, 拿5個。
        System.arraycopy(arr,4,dest,3,5);

        // System.arraycopy(arr,4,dest,3,5);: 新複製的長度:11,內容:[100, 101, 102, 5, 6, 7, 8, 9, 108, 109, 110]

        //System.arraycopy(arr,4,dest,3,6); java.lang.ArrayIndexOutOfBoundsException
        System.out.println("新複製的長度:"+dest.length+",內容:"+Arrays.toString(dest));
    }

控制檯打印輸出:

有圖片

需要注意,兩個數組, 源數組 src, 目標數組 dest 的原始長度可能不一致, 複製的開始位置也可能不一致,而複製的長度是一致的, 而數組 dest的長度是無法改變的, 所以很有可能造成 ArrayIndexOutOfBoundsException 異常。

要保證: srcPos+length<= src.length; destPos+length<=dest.length;

二.五 比較數組是否相同 equals()

二.五.一 例子

 @Test
    public void equalsTest(){
        //源數組
        int[] arr1={1,2,3,4,5,6,7,8,9};
        int[] arr2={1,2,3,4,5};
        int[] arr3={1,2,3,4,5,6,7,8,9};

        System.out.println("arr1與 arr2是否相同:"+Arrays.equals(arr1,arr2));
        System.out.println("arr1與 arr3是否相同:"+Arrays.equals(arr1,arr3));
    }

控制檯打印輸出:

有圖片

也可以比較 對象數組, 需要重寫對象的 equals () 方法。

二.五.二 簡單內部實現

有圖片

二.六 填充數組 fill

二.六.一 無範圍填充

 @Test
    public void fillTest1(){
        //源數組有內容填充:
        int[] arr1={1,2,3,4,5,6,7,8,9};
       //填充100
        Arrays.fill(arr1,100);
        System.out.println("有內容數組填充:"+Arrays.toString(arr1));

        int[] arr2=new int[9];
        Arrays.fill(arr2,100);
        System.out.println("無內容數組填充:"+Arrays.toString(arr2));
    }

控制檯打印輸出:

有圖片

實際上,就是替換。

內部實現:

 public static void fill(int[] a, int val) {
        for (int i = 0, len = a.length; i < len; i++)
            a[i] = val;
  }

二.六.二 有範圍填充

 @Test
    public void fillTest2(){
        //源數組有內容填充:
        int[] arr1={1,2,3,4,5,6,7,8,9};
        //填充100,只填充2~5 索引處的內容
        Arrays.fill(arr1,2,5,100);
        System.out.println("有內容數組2~5填充:"+Arrays.toString(arr1));

        int[] arr2=new int[9];
        Arrays.fill(arr2,2,5,100);
        System.out.println("無內容數組2~5填充:"+Arrays.toString(arr2));
    }

控制檯打印輸出:

有圖片

內部實現, 範圍性替換

 public static void fill(int[] a, int fromIndex, int toIndex, int val) {
       // rangeCheck(a.length, fromIndex, toIndex); //檢查範圍是否合理
        for (int i = fromIndex; i < toIndex; i++)
            a[i] = val;
    }

二.七 二元操作

類似於 遍歷數組中的每一個元素,執行相同的維護操作。

二.七.一 parallelPrefix() 小例子

如,使數組中的每一個元素,都變成 當前元素* 上一個索引處的元素, 即改變每一個元素的值。

 @Test
    public void parallelPrefixTest(){

        int[] arr={1,2,3,4,5,6,7,8,9};

        Arrays.parallelPrefix(arr, new IntBinaryOperator() {
            //left代表數組中前一個索引處的元素值,第一個元素,不進入該方法計算
            //right代表數組中當前索引處的元素值
            @Override
            public int applyAsInt(int left, int right) {
                return left*right;
            }
        });
        System.out.println("新內容爲:"+Arrays.toString(arr));
    }

控制檯打印輸出:

有圖片

二.七.二 parallelSetAll() 小例子

用於重新設置數組中的元素值

 @Test
    public void parallelSetAllTest(){
        int[] arr={1,2,3,4,5,6,7,8,9};
        Arrays.parallelSetAll(arr, new IntUnaryOperator() {
            @Override
            public int applyAsInt(int operand) {
                return operand*2;
            }
        });
        System.out.println("有內容的新內容爲:"+Arrays.toString(arr));

         arr=new int[9];
        Arrays.parallelSetAll(arr, new IntUnaryOperator() {
            @Override
            public int applyAsInt(int operand) {
                return operand*2;
            }
        });
        System.out.println("無內容的新內容爲:"+Arrays.toString(arr));
    }

控制檯打印輸出:

有圖片

二.七.三 setAll() 小例子

 @Test
    public void setAllTest(){
        int[] arr={1,2,3,4,5,6,7,8,9};
        Arrays.setAll(arr, new IntUnaryOperator() {
            @Override
            public int applyAsInt(int operand) {
                return operand*3;
            }
        });
        System.out.println("有內容的新內容爲:"+Arrays.toString(arr));

        arr=new int[9];
        Arrays.setAll(arr, new IntUnaryOperator() {
            @Override
            public int applyAsInt(int operand) {
                return operand*3;
            }
        });
        System.out.println("無內容的新內容爲:"+Arrays.toString(arr));
    }

控制檯打印輸出:

有圖片

二.八 排序 sort()

二.八.一 parallelSort() 併發無範圍排序 小例子

 @Test
    public void parallelSortTest1(){
        int[] arr={1,3,5,7,9,2,4,6,8};
        Arrays.parallelSort(arr);
        System.out.println("排序後的數組爲:"+Arrays.toString(arr));
    }

控制檯打印輸出:

有圖片

二.八.二 parallelSort() 併發有範圍排序 小例子

@Test
    public void parallelSortTest2(){
        int[] arr={1,3,5,7,9,2,4,6,8};
        //只排序 3~7, 即 7,9,2,4 四個元素。 排序完爲 2,4,7,9
        Arrays.parallelSort(arr,3,7);
        System.out.println("排序後的數組爲:"+Arrays.toString(arr));
    }

控制檯打印輸出:

有圖片

二.八.三 sort() 無範圍排序 小例子

@Test
    public void sortTest1(){
        int[] arr={1,3,5,7,9,2,4,6,8};
        Arrays.sort(arr);
        System.out.println("排序後的數組爲:"+Arrays.toString(arr));
    }

控制檯打印輸出:

有圖片

二.八.四 sort() 有範圍排序小例子

@Test
    public void sortTest2(){
        int[] arr={1,3,5,7,9,2,4,6,8};
        //只排序 3~7, 即 7,9,2,4 四個元素。 排序完爲 2,4,7,9
        Arrays.sort(arr,3,7);
        System.out.println("排序後的數組爲:"+Arrays.toString(arr));
    }

控制檯打印輸出:

有圖片

二.九 轉換成流 Stream()

二.九.一 無範圍轉換小例子

@Test
    public void streamTest1(){
        int[] arr={1,2,3,4,5,6,7,8,9};
        //轉換成流
        Arrays.stream(arr).forEach(n -> System.out.print(n));
    }

控制檯打印輸出:

有圖片

二.九.二 有範圍轉換小例子

@Test
    public void streamTest2(){
        int[] arr={1,2,3,4,5,6,7,8,9};
        //將索引位置爲 3~8的轉換成流,不包括8索引處的元素
        Arrays.stream(arr,3,8).forEach(n -> System.out.print(n));
    }

控制檯打印輸出:

有圖片

謝謝您的觀看,如果喜歡,請關注我,再次感謝 !!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章