作为Java程序员,你真的了解java.util.Arrays么

嗨~大家周末愉快啊,我是阿壮,一个 Java 程序员,最近在工作之余,即没 bug 要改了,也没需求了,又不能让老板看到自己在摸鱼,无聊的我开始 ctrl+鼠标左键,漫无目的的看着眼前的 JDK 源码。今天来更大家分享以下我遇到过的java.util.Arrays下的坑。

主要分析三个问题,并给出对于的解决方案

  1. 通过 asList 返回的固定大侠的 List 不支持添加元素
  2. 对原始数组的修改会影响到我们获得的那个 List
  3. 不能直接使用 Arrays.asList 来转换基本类型数组

请允许我使用巨佬 Java 之父 James Gosling 写的JDK源码作为今天的开始。

作为Java程序员,你真的了解java.util.Arrays么_第1张图片

通过 asList 返回的固定大侠的 List 不支持添加元素

代码

public static void main(String[] args) {
        String[] arr = new String[]{"aa", "bb"};
        List list = Arrays.asList(arr);
        list.add("cc");
    }

执行结果

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)
    at Test.main(Test.java:8)

原因是 java.util.Arrays.ArrayList 类实现了 set(), get(),contains()方法,但是并没有实现增加元素的方法(事实上是可以调用 add 方法,但是没有具体实现,仅仅抛出 UnsupportedOperationException 异常),因此它的大小也是固定不变的。可以通过 set 方法进行设置值,默认长度是 10。

解决方案

新建一个 ArrayList

代码:

public static void main(String[] args) {
        String[] arr = {"aa", "bb", "cc"};
        List list = Arrays.asList(arr);
        ArrayList strings = new ArrayList<>(list);
        strings.add("dd");
        System.out.println(strings.toString());
    }

执行结果:

[aa, bb, cc, dd]

通过集合工具类 Collections.addAll()方法(最高效,推荐)

通过 Collections.addAll(arrayList, strArray)方式转换,根据数组的长度创建一个长度相同的 List,然后通过 Collections.addAll()方法,将数组中的元素转为二进制,然后添加到 List 中,这是最高效的方法。

代码:

public static void main(String[] args) {
        String[] arr = {"aa", "bb", "cc"};
        ArrayList strings = new ArrayList<>(arr.length);
        Collections.addAll(strings, arr);
        strings.add("dd");
        System.out.println(strings.toString());
    }

执行结果:

[aa, bb, cc, dd]

Stream 优雅的写法

代码:

public static void main(String[] args) {
        String[] arr = {"aa", "bb", "cc"};
        List list = Stream.of(arr).collect(Collectors.toList());
        list.add("dd");
        System.out.println(list.toString());
    }

执行效果:

[aa, bb, cc, dd]

底层先将数组转换为流,再使用 addAll()的方式,执行效率次于Collections.addAll()方式,但是写法优雅呀。

对原始数组的修改会影响到我们获得的那个 List

代码

 public static void main(String[] args) {
        String[] arr = {"aa", "bb", "cc"};
        List list = Arrays.asList(arr);
        arr[1] = "dd";
        System.out.printf("arr:%s list:%s", Arrays.toString(arr), list);
    }

执行结果

arr:[aa, dd, cc] list:[aa, dd, cc]

原因是 Arrays 内部类 ArrayList 其实是直接使用了原始的数组,把通过 Arrays.asList 获得的 List 交给其他方法处理,很容易因为共享了数组,相互修改产生 Bug。

不能直接使用 Arrays.asList 来转换基本类型数组

代码

public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        List list = Arrays.asList(arr);
        System.out.println(list.size());
    }

执行结果

1

原因是 asList 方法的参数必须是对象或者对象数组,而原生数据类型不是对象,当传入一个原生数据类型数组时,asList 的真正得到的参数就不是数组中的元素,而是数组对象本身。

解决方案

Java8 可通过 stream 流将 3 种基本类型数组转为 List

如果 JDK 版本在 1.8 以上,可以使用流 stream 来将下列 3 种数组快速转为List,分别是int[]long[]double[],其他数据类型比如short[]byte[]char[],在 JDK1.8 中暂不支持。

代码:

public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        List list = Arrays.stream(arr).boxed().collect(Collectors.toList());
        System.out.println(list);
    }

执行效果:

[1, 2, 3]

我是阿壮,一个后端程序员,微信搜一搜:科技猫,持续分享原创编程技术,实用软件,科技资讯,我们下期间

你可能感兴趣的:(java后端源码分析)