Arrays是一个数组类,类里面有很多操作数组的方法,包括排序和查找。同时类里面有一个静态工厂,它允许你将数组当成列表来使用。
sort方法支持int[] short[] long[] char[] byte[] float[] double[]等基本类型的升序排序,内部实现用的是改进过后的快速排序,叫DualPivotQuicksort
常见的几种使用方式如下
int[] a = new int[]{10000,565,234,654,8}; Arrays.sort(a); log.info(Arrays.toString(a)); int[] b = new int[]{10000,565,234,654,8}; Arrays.sort(b,1,5); log.info(Arrays.toString(b)); initStudents(students); Arrays.sort(students);//Student类实现了Comparable接口 initTeachers(teachers); Arrays.sort(teachers,Comparator.comparingInt(Teacher::getNo));//Teacher类没有实现Comparable接口,所以需要传入一个比较器,这里用了java8的特性 //对象的排序同样支持部分排序 复制代码
数组长度超过8192时推荐使用该方法进行排序,它会将数组分割成小数组进行排序,再将结果合并起来
使用该方法时,注意内部有一个判断 if (n <= MIN_ARRAY_SORT_GRAN ||(p = ForkJoinPool.getCommonPoolParallelism()) == 1)
,该判断为true时调用sort方法,否则,才进入并行排序算法
方法使用情况同sort(),用例如下
Random random = new Random(System.currentTimeMillis()); Student[] students = new Student[9000]; Teacher[] teachers = new Teacher[9000]; for (int i = 0; i < 9000; i++) { students[i] = new Student(); students[i].setNo(random.nextInt()%90000); teachers[i] = new Teacher(); teachers[i].setNo(random.nextInt()%90000); } Arrays.parallelSort(students);//超过8192后有时候行,有时候不行?如果加上%90000,就没问题,但%2100000000也会有问题 Arrays.parallelSort(teachers, Comparator.comparingInt(Teacher::getNo)); 复制代码
parallelSort在对基本类型进行并行排序时没有什么问题,但对对象进行操作时,并且随机值大时,容易抛java.lang.IllegalArgumentException: Comparison method violates its general contract!这个异常,查了一些资料,还是没有找到根本原因,疑惑点如下
1. 如果说少考虑了相等的情况,为什么%9000就可以?
2. 为什么%9000可以,%2100000000不行
3. 去掉取模运算,有时候抛异常,有时候不抛异常
4. 如果有道友能指点一下,还请赐教!
该方法用得比较少,它通过利用前面所有元素的计算结果,对目标元素进行相同逻辑的运算,并将运算结果传递给下一个元素使用, 用例如下
int[] a = new int[]{10000,565,234,654,8}; Arrays.parallelPrefix(a, Integer::sum); log.info(Arrays.toString(a)); //非基本类型使用该方法时,需要返回一个新的对象,因为本质是赋值一个新的对象地址,lambda表达式中的teacher是上一轮的计算结果,可打印出来验证 Arrays.parallelPrefix(teachers, (teacher, teacher2) -> { Teacher temp = new Teacher(); temp.setNo(teacher.getNo() + teacher2.getNo()); return temp; }); log.info(Arrays.toString(teachers)); 复制代码
内部使用的是二分查找,要求数组必须有序,返回目标元素的索引值,索引值小于0时代表找不到该元素
支持基本类型数组及对象数组的二分查找和区域二分查找
int[] a = new int[]{1,2,3,4,8}; int index = Arrays.binarySearch(a,3); log.info(String.valueOf(index)); index = Arrays.binarySearch(a,1,a.length-1,8); log.info(String.valueOf(index)); // 没有实现Comparable接口的对象 initTeacher(teachers); Teacher key = new Teacher(); key.setNo(3); index = Arrays.binarySearch(teachers, key, Comparator.comparingInt(Teacher::getNo)); if(index > 0){ log.info(String.valueOf(teachers[index])); } // 实现了Comparable接口的对象 initStudent(students); Student student = new Student(); student.setNo(2); index = Arrays.binarySearch(students,student); if(index > 0){ log.info(students[index].toString()); } 复制代码
fill函数相当于初始化函数,没什么特别的,但在对象的填充是注意不要被坑,因为它仅仅是一层浅复制,如果源信息做出了修改,是会影响到复制得到的数组的
int[] a = new int[5]; Arrays.fill(a,8); log.info(Arrays.toString(a)); int[] b = new int[5]; Arrays.fill(b,2,4,8); log.info(Arrays.toString(b)); //支持long[],int[],short[],char[],byte[],boolean[],double[],float[],Object[]类型的填充 Student[] students = new Student[3]; Student student = new Student(); student.setNo(6); Arrays.fill(students,student); student.setNo(1); log.info(Arrays.toString(students));//为什么是1而不是6? 复制代码
copy函数也是一个浅复制
Teacher[] teachers = new Teacher[5]; for (int i = 0; i < 5; i++) { teachers[i] = new Teacher(); teachers[i].setNo(i); } Teacher[] copy = Arrays.copyOf(teachers, 3); Teacher[] range = Arrays.copyOfRange(teachers, 2, 4); teachers[2].setNo(8888); log.info(Arrays.toString(copy)); log.info(Arrays.toString(range)); //支持byte[],short[],int[],long[],char[],float[],double[],boolean[]等类型数组的复制 复制代码
tryAdvance方法表示每次消费一个被分割出来的元素 forEachRemaining方法表示剩下的被分割出来的元素全部用指定的方法去消费
int[] a = new int[]{1,2,3,4,8}; Spliterator.OfInt spliterator = Arrays.spliterator(a); spliterator.tryAdvance((IntConsumer) value -> System.out.println(value * value)); spliterator.tryAdvance((IntConsumer) value -> System.out.println(value * value)); spliterator.forEachRemaining((IntConsumer) System.out::println); 复制代码
java8新添加的特性,这里只演示一下stream的简单用法,后面会出一篇专门的文章来分享这个东西。
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 8); List<Integer> collect = integers.stream().map(e -> e * e).collect(Collectors.toList()); log.info(collect.toString()); 复制代码