【小家java】聊聊Java中的java.util.Arrays类和java.util.Collections工具类(中)

简介: 【小家java】聊聊Java中的java.util.Arrays类和java.util.Collections工具类(中)

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迭代器的时候专题讲解



相关文章
|
2月前
|
Java 编译器 API
Java 密封类:精细化控制继承关系
Java 密封类:精细化控制继承关系
267 83
|
3月前
|
IDE Java 数据挖掘
Java 基础类从入门到精通实操指南
这份指南专注于**Java 17+**的新特性和基础类库的现代化用法,涵盖开发环境配置、数据类型增强(如文本块)、字符串与集合处理进阶、异常改进(如密封类)、IO操作及实战案例。通过具体代码示例,如CSV数据分析工具,帮助开发者掌握高效编程技巧。同时提供性能优化建议和常用第三方库推荐,适合从入门到精通的Java学习者。资源链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
177 35
|
4月前
|
存储 安全 Java
【高薪程序员必看】万字长文拆解Java并发编程!(7):不可变类设计指南
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中Java不可变类设计指南,废话不多说让我们直接开始。
73 0
|
25天前
|
安全 IDE Java
Java记录类型(Record):简化数据载体类
Java记录类型(Record):简化数据载体类
129 0
|
2月前
|
Java API
Java API中Math类功能全景扫描
在实际使用时,这些方法的精确度和性能得到了良好的优化。当处理复杂数学运算或高精度计算时,`Math`类通常是足够的。然而,对于非常精细或特殊的数学运算,可能需要考虑使用 `java.math`包中的 `BigDecimal`类或其他专业的数学库。
86 11
|
2月前
|
Java API
深入解析Java API中Object类的功能
了解和合理运用 Object类的这些方法,对于编写可靠和高效的Java应用程序至关重要。它们构成了Java对象行为的基础,影响着对象的创建、识别、表达和并发控制。
60 0
|
2月前
|
安全 Java
JAVA:Collections类的shuffle()方法
`Collections.shuffle()` 是 Java 中用于随机打乱列表顺序的工具方法,适用于洗牌、抽奖等场景。该方法直接修改原列表,支持自定义随机数生成器以实现可重现的打乱顺序。使用时需注意其原地修改特性及非线程安全性。
95 0
|
2月前
|
存储 Java 编译器
深入理解Java虚拟机--类文件结构
本内容介绍了Java虚拟机与Class文件的关系及其内部结构。Class文件是一种与语言无关的二进制格式,包含JVM指令集、符号表等信息。无论使用何种语言,只要能生成符合规范的Class文件,即可在JVM上运行。文章详细解析了Class文件的组成,包括魔数、版本号、常量池、访问标志、类索引、字段表、方法表和属性表等,并说明其在Java编译与运行过程中的作用。
|
2月前
|
SQL Java 数据库连接
Java 期末考试救急必备涵盖绝大多数核心考点及五大类经典代码助你过关
本文为Java期末考试复习指南,涵盖基础语法、面向对象编程、异常处理、文件操作、数据库连接五大核心考点,提供详细解析与实用代码示例,助力快速掌握重点,高效备考,轻松应对考试。
70 0