compare和compareUnsigned
备注:此两个方法是JDK9提供的方法。JDK里没有哦,所以本文不介绍此方法
copyOf和copyOfRange 复制、截取数组
这个在复制数组和截取数组的时候非常有用,推荐使用:
public static void main(String[] args) { Integer[] arrayTest = {6, 1, 9, 2, 5, 7, 6, 10, 6, 12}; //复制出新的数组,复制长度由 newLength 决定,长度可大于被复制数组的长度 也可以小于 Integer[] copyArray1 = Arrays.copyOf(arrayTest, 2); //长度小于 Integer[] copyArray11 = Arrays.copyOf(arrayTest, 15); //长度大于 System.out.println(Arrays.toString(copyArray1)); //[6, 1] System.out.println(Arrays.toString(copyArray11)); //[6, 1, 9, 2, 5, 7, 6, 10, 6, 12, null, null, null, null, null] //复制指定下标范围内的值,含头不含尾(这是通用规则) Integer[] copyArray2 = Arrays.copyOfRange(arrayTest, 2, 7); //截取部分 System.out.println(Arrays.toString(copyArray2)); }
equals和deepEquals:比较数组内容是否相等
equals:比较一位数组内容
deepEquals:比较二维数组内容
public static void main(String[] args) { Integer[] arrayTest = {6, 1, 9, 2, 5, 7, 6, 10, 6, 12}; //定义一个二维数组 学生成绩 Integer[][] stuGrades = {{1, 3, 5, 7, 9}, {2, 4, 6, 8}, {1, 5, 10}}; Integer[] equals1 = Arrays.copyOf(arrayTest, arrayTest.length); //完整拷贝 //比较一维数组内容是否相等 System.out.println(Arrays.equals(equals1, arrayTest)); //true Integer[][] equals2 = Arrays.copyOf(stuGrades, stuGrades.length); //比较二维数组内容是否相等 System.out.println(Arrays.deepEquals(stuGrades, equals2)); //true }
toString和deepToString
public static void main(String[] args) { Integer[] arrayTest = {6, 1, 9, 2, 5, 7, 6, 10, 6, 12}; //一维数组toString System.out.println(Arrays.toString(arrayTest)); Integer[][] stuGrades={{1,3,5,7,9},{2,4,6,8},{1,5,10}}; //二维数组toString System.out.println(Arrays.deepToString(stuGrades)); }
hashCode和deepHashCode
基本同上,例子略
fill:将一个数组全部置为 val ,或在下标范围内将数组置为 val
public static void main(String[] args) { Integer[] arrayTest = {6, 1, 9, 2, 5, 7, 6, 10, 6, 12}; //Integer[] arrayTest = new Integer[5]; //将一个数组置为 val(5) Arrays.fill(arrayTest,5); System.out.println(Arrays.toString(arrayTest)); //[5, 5, 5, 5, 5, 5, 5, 5, 5, 5] //将一个数组指定范围内置为 val(10) 含头不含尾 Arrays.fill(arrayTest,2,3,10); //通过角标 可以控制可以批量换值 System.out.println(Arrays.toString(arrayTest)); //[5, 5, 10, 5, 5, 5, 5, 5, 5, 5] }
setAll和parallelSetAll:JDK有歧义的实现方式
这个有点类似于Stream里的Map,但是JDK的实现有bug。
setAll的语义,作者的元思想肯定是希望处理each element,但是我们看看源码:
public static <T> void setAll(T[] array, IntFunction<? extends T> generator) { Objects.requireNonNull(generator); for (int i = 0; i < array.length; i++) array[i] = generator.apply(i); }
generator.apply(i);它竟然用的是i,而不是array[i],所以此处我们使用的时候一定要万分注意,回调给我们的是角标,而不是值,而不是值
public static void main(String[] args) { Integer[] arrayTest = {6, 1, 9, 2, 5, 7, 6, 10, 6, 12}; Integer[] setAllArr = Arrays.copyOf(arrayTest, arrayTest.length); //一个数组全部做表达式操作 System.out.println(Arrays.toString(setAllArr)); //[6, 1, 9, 2, 5, 7, 6, 10, 6, 12] //一定要注意 此处我们需要用setAllArr[i]才是我们想要的结果 Arrays.setAll(setAllArr, i -> setAllArr[i] * 3); //Arrays.setAll(setAllArr, i -> i * 3); System.out.println(Arrays.toString(setAllArr)); //[18, 3, 27, 6, 15, 21, 18, 30, 18, 36] }
看到这种使用方式,很逆天有没有。真不知道是JDK的设计者脑子进水了,还是进水了,因为处理角标没任何意义,至少我是不太同意这种设计的。
一次同样的parallelSetAll也是采用的角标,他们的区别只是一个串行,一个并行。
stream 这个就不解释了
parallelPrefix:二元迭代,对原数组内容进行二元操作
这个解释起来比较麻烦,直接先看一个例子吧
public static void main(String[] args) { Integer[] arrayTest = {6, 1, 9, 2, 5, 7, 6, 10, 6, 12}; Integer[] arrayPP1 = Arrays.copyOf(arrayTest, arrayTest.length); System.out.println(Arrays.toString(arrayPP1)); //[6, 1, 9, 2, 5, 7, 6, 10, 6, 12] //二元迭代,对原数组内容进行二元操作 Arrays.parallelPrefix(arrayPP1, (x, y) -> x * y); System.out.println(Arrays.toString(arrayPP1)); //[6, 6, 54, 108, 540, 3780, 22680, 226800, 1360800, 16329600] //在指定下标范围内,对原数组内容进行二元操作,下标含头不含尾 Integer[] arrayPP2 = Arrays.copyOf(arrayTest, arrayTest.length); Arrays.parallelPrefix(arrayPP2, 0, 5, (x, y) -> x * y); System.out.println(Arrays.toString(arrayPP2)); //[6, 6, 54, 108, 540, 7, 6, 10, 6, 12] }
从效果中我们可以看出来,这个就是拿前面的结果,和当前元素做运算。这个运算规则,由我们自己来定义。
使用场景:这个在一些数学运算中,会比较好用
sort和parallelSort:算法精华
排序一直以来效率是很依赖于算法的,所以我们抽查一个源码看看它的精妙之处:
static void sort(byte[] a, int left, int right) { // Use counting sort on large arrays if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) { int[] count = new int[NUM_BYTE_VALUES]; for (int i = left - 1; ++i <= right; count[a[i] - Byte.MIN_VALUE]++ ); for (int i = NUM_BYTE_VALUES, k = right + 1; k > left; ) { while (count[--i] == 0); byte value = (byte) (i + Byte.MIN_VALUE); int s = count[i]; do { a[--k] = value; } while (--s > 0); } } else { // Use insertion sort on small arrays for (int i = left, j = i; i < right; j = ++i) { byte ai = a[i + 1]; while (ai < a[j]) { a[j + 1] = a[j]; if (j-- == left) { break; } } a[j + 1] = ai; } } }
如果大于域值那么就使用计数排序法,否则就使用插入排序。
parallelSort是java8中新出的一种排序API,这是一种并行排序,Arrays.parallelSort使用了Java7的Fork/Join框架使排序任务可以在线程池中的多个线程中进行,Fork/Join实现了一种任务窃取算法,一个闲置的线程可以窃取其他线程的闲置任务进行处理。
性能对比结论:数组数据量越大,parallelSort的优势就越明显。
jdk源码中写的排序算法都很精简,值得学习
spliterator:最优的遍历
这是JDK为了高级遍历数组而提供的一个方法。具体使用方式,会在后续讲解spliterator迭代器的时候专题讲解