想要数组用的六,怎能不懂java。util。Arrays
java.util.Arrays 类就是为数组而生的专用工具类,基本上常见的对数组的操作,Arrays 类都考虑到了,这让我由衷地觉得,是时候给该类的作者 Josh Bloch、Neal Gafter、John Rose 点个赞了。
(我是怎么知道作者名的?看源码就可以,小伙伴们,装逼吧)
Arrays 都可以干嘛呢?常见的有:创建数组比较数组数组排序数组检索数组转流打印数组数组转 ListsetAll(没想好中文名)parallelPrefix(没想好中文名)
那接下来,小伙伴们是不是已经迫不及待想要和二哥一起来打怪进阶了。走你。01、创建数组
使用 Arrays 类创建数组可以通过以下三个方法:copyOf,复制指定的数组,截取或用 null 填充copyOfRange,复制指定范围内的数组到一个新的数组fill,对数组进行填充
1)copyOf,直接来看例子:String[] intro = new String[] { "沉", "默", "王", "二" }; String[] revised = Arrays.copyOf(intro, 3); String[] expanded = Arrays.copyOf(intro, 5); System.out.println(Arrays.toString(revised)); System.out.println(Arrays.toString(expanded));
revised 和 expanded 是复制后的新数组,长度分别是 3 和 5,指定的数组长度是 4。来看一下输出结果:[沉, 默, 王] [沉, 默, 王, 二, null]
看到没?revised 截取了最后一位,因为长度是 3 嘛;expanded 用 null 填充了一位,因为长度是 5。
2)copyOfRange,直接来看例子:String[] intro = new String[] { "沉", "默", "王", "二" }; String[] abridgement = Arrays.copyOfRange(intro, 0, 3); System.out.println(Arrays.toString(abridgement));
copyOfRange() 方法需要三个参数,第一个是指定的数组,第二个是起始位置(包含),第三个是截止位置(不包含)。来看一下输出结果:[沉, 默, 王]
0 的位置是"沉",3 的位置是"二",也就是说截取了从 0 位(包含)到 3 位(不包含)的数组元素。那假如说下标超出了数组的长度,会发生什么呢?String[] abridgementExpanded = Arrays.copyOfRange(intro, 0, 6); System.out.println(Arrays.toString(abridgementExpanded));
结束位置此时为 6,超出了指定数组的长度 4,来看一下输出结果:[沉, 默, 王, 二, null, null]
仍然使用了 null 进行填充。为什么要这么做呢?小伙伴们思考一下,我想是作者考虑到了数组越界的问题,不然每次调用 Arrays 类就要先判断很多次长度,很麻烦。
3)fill,直接来看例子:String[] stutter = new String[4]; Arrays.fill(stutter, "沉默王二"); System.out.println(Arrays.toString(stutter));
使用 new 关键字创建了一个长度为 4 的数组,然后使用 fill() 方法将 4 个位置填充为"沉默王二",来看一下输出结果:[沉默王二, 沉默王二, 沉默王二, 沉默王二]
如果想要一个元素完全相同的数组时, fill() 方法就派上用场了。02、比较数组
Arrays 类的 equals() 方法用来判断两个数组是否相等,来看下面这个例子:String[] intro = new String[] { "沉", "默", "王", "二" }; boolean result = Arrays.equals(new String[] { "沉", "默", "王", "二" }, intro); System.out.println(result); boolean result1 = Arrays.equals(new String[] { "沉", "默", "王", "三" }, intro); System.out.println(result1);
输出结果如下所示:true false
指定的数组为沉默王二四个字,比较的数组一个是沉默王二,一个是沉默王三,所以 result 为 true,result1 为 false。
简单看一下 equals() 方法的源码:public static boolean equals(Object[] a, Object[] 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 fence(1) at java.base/java.util.Spliterators.checkFromToBounds(Spliterators.java:387) 06、打印数组
关于数组的打印方式,我之前单独写过一篇文章:
打印Java数组最优雅的方式是什么?
里面谈了很多种数组打印的方式,因为数组是一个对象,直接 System.out.println 的话,结果是这样的:[Ljava.lang.String;@3d075dc0
那最优雅的方式,其实文章里面已经出现过很多次了,就是 Arrays.toString():public static String toString(Object[] a) { if (a == null) return "null"; int iMax = a.length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append("["); for (int i = 0; ; i++) { b.append(String.valueOf(a[i])); if (i == iMax) return b.append("]").toString(); b.append(", "); } }
小伙伴可以好好欣赏一下这段源码,感觉考虑得非常周到。07、数组转 List
尽管数组非常强大,但它自身可以操作的工具方法很少,比如说判断数组中是否包含某个值。转成 List 的话,就简便多了。String[] intro = new String[] { "沉", "默", "王", "二" }; List rets = Arrays.asList(intro); System.out.println(rets.contains("二"));
不过需要注意的是,Arrays.asList() 返回的是 java.util.Arrays.ArrayList,并不是 java.util.ArrayList,它的长度是固定的,无法进行元素的删除或者添加。rets.add("三"); rets.remove("二");
执行这两个方法的时候,会抛出异常:Exception in thread "main" java.lang.UnsupportedOperationException at java.base/java.util.AbstractList.add(AbstractList.java:153) at java.base/java.util.AbstractList.add(AbstractList.java:111)
要想操作元素的话,需要多一步转化:List rets1 = new ArrayList<>(Arrays.asList(intro)); rets1.add("三"); rets1.remove("二"); 08、setAll
Java 8 新增了 setAll() 方法,它提供了一个函数式编程的入口,可以对数组的元素进行填充:int[] array = new int[10]; Arrays.setAll(array, i -> i * 10); System.out.println(Arrays.toString(array));
这段代码什么意思呢?i 就相当于是数组的下标,值从 0 开始,到 9 结束,那么 i * 10 就意味着 0 * 10 开始,到 9 * 10 结束,来看一下输出结果:[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
比之前的 fill() 方法强大多了,对吧?不再填充的是相同的元素。09、parallelPrefix
parallelPrefix() 方法和 setAll() 方法一样,也是 Java 8 之后提供的,提供了一个函数式编程的入口,通过遍历数组中的元素,将当前下标位置上的元素与它之前下标的元素进行操作,然后将操作后的结果覆盖当前下标位置上的元素。int[] arr = new int[] { 1, 2, 3, 4}; Arrays.parallelPrefix(arr, (left, right) -> left + right); System.out.println(Arrays.toString(arr));
上面代码中有一个 Lambda 表达式((left, right) -> left + right),需要入门的小伙伴可以查看我之前写的一篇文章:
Lambda 表达式入门,看这篇就够了
那为了让小伙伴看得更明白一些,我们把上面这段代码稍微改造一下:int[] arr = new int[]{1, 2, 3, 4}; Arrays.parallelPrefix(arr, (left, right) -> { System.out.println(left + "," + right); return left + right; }); System.out.println(Arrays.toString(arr));
先来看一下输出结果:1,2 3,3 6,4 [1, 3, 6, 10]
也就是说, Lambda 表达式执行了三次:第一次是 1 和 2 相加,结果是 3,替换下标为 1 的位置第二次是 3 和 3 相加,结果是 6,也就是第一次的结果和下标为 2 的元素相加的结果第三次是 6 和 4 相加,结果是 10,也就是第二次的结果和下标为 3 的元素相加的结果
有点强大,对吧?