Java 提供的 Arrays 類里包含了一些 static 修飾的方法 可以直接操作數(shù)組.(static 修飾的方法可以直接通過(guò)類名調(diào)用).Java 8 增強(qiáng)了Arrays類的功能搪柑,增加了一些工具方法,可以充分利用多CPU并行的能力來(lái)提高設(shè)值索烹、排序的性能工碾。
大致分為兩類方法,一類是單線方法(用于單線程處理數(shù)組)百姓,另一類是多線算法(大多以parallel作為前綴渊额,可以充分利用現(xiàn)代CPU多核并行的特點(diǎn)多線程處理數(shù)組,特別是對(duì)于那些規(guī)模非常龐大的數(shù)組)垒拢;
單線程方法:
-
int binarySearch(type[] a,type key)
使用二分法查詢key元素值在a數(shù)組中出現(xiàn)的索引旬迹,如果a數(shù)組中不包含key元素值,則返回負(fù)數(shù)求类, 調(diào)用該方法是要求數(shù)組中元素已經(jīng)按照升序排列奔垦,這樣才能得到正確結(jié)果。 -
int binarySearch(type[] a ,type key,int fromIndex,int toIndex)
重載上一個(gè)方法尸疆,增加了開(kāi)始下標(biāo)和結(jié)束下標(biāo)宴倍,規(guī)定了查找的范圍。調(diào)用該方法是要求數(shù)組中元素已經(jīng)按照升序排列仓技,這樣才能得到正確結(jié)果鸵贬。
private static int binarySearch0(long[] a, int fromIndex, int toIndex,long key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
long midVal = a[mid];
if (midVal < key)
low = mid + 1;
else if (midVal > key)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
獲取任意類型的數(shù)組,一個(gè)對(duì)應(yīng)類型的元素key脖捻,還有int類型的開(kāi)始和結(jié)束下標(biāo)阔逼,為了公用一個(gè)算法方法,我們先給定兩個(gè)局部變量地沮,如果沒(méi)有指定開(kāi)始和結(jié)束下標(biāo)那么指定從0開(kāi)始到數(shù)組a的長(zhǎng)度-1結(jié)束嗜浮。然后循環(huán),循環(huán)判定條件是最小范圍值小于等于最大范圍值摩疑。然后中間值和key的比較危融,確定范圍,最后確定key所在位置的index雷袋,直接返回吉殃。如果沒(méi)有該值,直接返回負(fù)數(shù)。
-
type[] copyOf(type[] original,int length)
復(fù)制original數(shù)組到一個(gè)新數(shù)組蛋勺,length為新數(shù)組的長(zhǎng)度瓦灶,如果length的值大于original的長(zhǎng)度,那么新數(shù)組的其他值補(bǔ)0(數(shù)值類型)抱完,false(布爾類型)贼陶,null(引用類型)等。如果length的值小于original的長(zhǎng)度巧娱,那么新數(shù)組就是origin數(shù)組前l(fā)ength個(gè)元素碉怔。 -
type[] copyOfRange(type[] original,int fromIndex,int toIndex)
該方法是上面方法的重載,規(guī)定了開(kāi)始復(fù)制的下標(biāo)和結(jié)束復(fù)制的下標(biāo)禁添,也就是復(fù)制規(guī)定位置的數(shù)組元素到新數(shù)組中撮胧。
public static byte[] copyOf(byte[] original, int newLength) {
byte[] copy = new byte[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
Java中這個(gè)方法是調(diào)用了System類中的arraycopy方法實(shí)現(xiàn)的,但是arraycopy有一個(gè)修飾符native.方法用native關(guān)鍵字修飾上荡,說(shuō)明該方法有實(shí)現(xiàn)趴樱,但不是使用java代碼實(shí)現(xiàn)的馒闷,它的實(shí)現(xiàn)是在一個(gè)DLL文件中酪捡,可能使用C語(yǔ)言等其他語(yǔ)言實(shí)現(xiàn),方便了java和硬件的交互纳账,缺點(diǎn)是增加開(kāi)銷逛薇。Native方法也被稱為本地方法。
public static byte[] copyOfRange(byte[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0)
throw new IllegalArgumentException(from + " > " + to);
byte[] copy = new byte[newLength];
System.arraycopy(original, from, copy, 0,
Math.min(original.length - from, newLength));
return copy;
}
先計(jì)算出新數(shù)組的長(zhǎng)度疏虫,使用結(jié)束下標(biāo)-開(kāi)始下標(biāo)永罚,如果小于0,說(shuō)明結(jié)束下標(biāo)小于開(kāi)始下標(biāo)卧秘,這樣不成立呢袱,所以手動(dòng)拋出異常。然后調(diào)用System類的arraycopy方法翅敌,執(zhí)行羞福。
-
boolean equals(long[] a1,long[] a2)
判斷兩個(gè)數(shù)組的長(zhǎng)度和內(nèi)容是否相同(數(shù)組元素必須一一對(duì)應(yīng)并相同)。
public static boolean equals(long[] a, long[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++)
if (a[i] != a2[i])
return false;
return true;
}
-
void sort(type[] a)
對(duì)數(shù)組進(jìn)行排序 -
void sort(type[] a,int fromIndex,int toIndex)
該方法是上面方法的重載蚯涮,規(guī)定了開(kāi)始復(fù)制的下標(biāo)和結(jié)束復(fù)制的下標(biāo) String toString(type[] a)
多線方法:都以parallel作為前綴治专,表示并行計(jì)算
- void parallelPrefix(type[] a, int from, int to, typeBinaryOperator op);
i. 表示將數(shù)組a的[from, to)進(jìn)行typeBinaryOperator的二元迭代;
ii. 其中BinaryOperator就是二元操作符的意思遭顶;
iii. 該方法的意思其實(shí)就是以下代碼:
static void parallelPrefix(type[] a, int from, int to, TypeBinaryOperator op) {
for (int i = from; i < to; i++) {
type left = (i == 0)? 1: a[i - 1]; // 對(duì)于第一個(gè)元素left = 1
type right = a[i];
a[i] = left op right;
}
}
即從頭到尾逐個(gè)按照l(shuí)eft op right的方式更新张峰,那更新后的值繼續(xù)迭代下一個(gè)元素。
iv. 其中typeBinaryOperator表示二元運(yùn)算法棒旗,type目前基本支持Java的基礎(chǔ)類型(int喘批、double等),該運(yùn)算法其實(shí)是一個(gè)函數(shù)式接口,里面只有一個(gè)方法:
public interface TypeBinaryOperator {
type applyAsInt(type left, type right);
}
例如上面的如果想使用連乘迭代那就可以直接用Lambda表達(dá)式:Arrays.parallelPrefix(arr, 1, 5, (left, right) -> left * right);就行了谤祖;
- void parallelPrefix(type[] a, typeBinaryOperator op);
默認(rèn)區(qū)間就是全部[0, length] == [0, length + 1)婿滓;
如果是數(shù)組[1, 2, 3, 4, 5]進(jìn)行全區(qū)間的連乘迭代,得到的結(jié)果就是[1, 2, 6, 24, 120]粥喜;
- void parallelSort(type[] a);
對(duì)數(shù)組進(jìn)行排序,與sort相同只是增加了并行能力凸主,可以利用多CPU并行來(lái)提高性能。 - void parallelSort(type[] a, int fromIndex, int toIndex);
該方法是上面方法的重載额湘,規(guī)定了開(kāi)始下標(biāo)和結(jié)束下標(biāo)卿吐。 - void parallelSetAll(type[] a, TypeUnaryOperator op);
該方法就是用填充算法為數(shù)組a的每個(gè)元素賦值; UnaryOperator是一元運(yùn)算符的意思锋华,之所以是一元是因?yàn)樵摲椒J(rèn)用元素的索引來(lái)生成該元素的值嗡官,該接口也是一個(gè)函數(shù)式接口:
public interface TypeUnaryOperator {
type applyAsInt(type operand); // 利用索引生成一個(gè)值,如何生成自己定義
}
該方法的意思就是:
static void parallelSetAll(Type[] a, TypeUnaryOperator op) {
for (int i = 0; i < a.length; i++) {
a[i] = op(i);
}
}
例如:Arrays.parallelSetAll(a, index -> index * 5); // 一個(gè)長(zhǎng)度為5的int數(shù)組其填充結(jié)果就是[0, 5, 10, 15, 20]
-
XxxStream stream(xxx[] array)
將數(shù)組轉(zhuǎn)為流式毯焕,對(duì)array進(jìn)行流式處理衍腥,可用一切流式處理的方法Arrays.stream(arrayTest) .map(a->a*2) .filter(a->a>10) .sorted() .distinct() .limit(6) .forEach(a-> System.out.print(a+" ")); System.out.println();