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

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

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

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

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

通过 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后端源码分析)