• 35648

    文章

  • 23

    评论

  • 20

    友链

  • 最近新加了很多技术文章,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议65~69) 原

欢迎来到阿八个人博客网站。本 阿八个人博客 网站提供最新的站长新闻,各种互联网资讯。 喜欢本站的朋友可以收藏本站,或者加QQ:我们大家一起来交流技术! URL链接:https://www.abboke.com/jsh/2019/0718/8930.html

撸了今年阿里、网易和美团的面试,我有一个重要发现.......>>>

如果你浪费了自己的年龄,那是挺可悲的。因为你的青春只能持续一点儿时间——很短的一点儿时间。 —— 王尔德

建议65:避开基本类型数组转换列表陷阱

我们在开发中经常会使用Arrays和Collections这两个工具类和列表之间转换,非常方便,但也有时候会出现一些奇怪的问题,来看如下代码:

public class Client65 {
    public static void main(String[] args) {
        int data [] = {1,2,3,4,5};
        List list= Arrays.asList(data);
        System.out.println("列表中的元素数量是:"+list.size());
    }
}

也许你会说,这很简单,list变量的元素数量当然是5了。但是运行后打印出来的列表数量为1。

  事实上data确实是一个有5个元素的int类型数组,只是通过asList转换成列表后就只有一个元素了,这是为什么呢?其他4个元素到什么地方去了呢?

  我们仔细看一下Arrays.asList的方法说明:输入一个变长参数,返回一个固定长度的列表。注意这里是一个变长参数,看源码:

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

asList方法输入的是一个泛型变长参数,基本类型是不能泛型化的,也就是说8个基本类型不能作为泛型参数,要想作为泛型参数就必须使用其所对应的包装类型。

解决方法:

Integer data [] = {1,2,3,4,5};

把int替换为Integer即可让输出元素数量为5.需要说明的是,不仅仅是int类型的数组有这个问题,其它7个基本类型的数组也存在相似的问题,这就需要大家注意了,在把基本类型数组转换为列表时,要特别小心asList方法的陷阱,避免出现程序逻辑混乱的情况。

建议66:asList方法产生的List对象不可修改

上一个建议指出了asList方法在转换基本类型数组时存在的问题,接着我们看一下asList方法返回的列表有何特殊的地方,代码如下: 

package OSChina.Client;

import java.util.Arrays;
import java.util.List;

public class Client5 {
    public static void main(String[] args) {
        // 五天工作制
        Week days[] = { Week.Mon, Week.Tue, Week.Wed, Week.Thu, Week.Fri };
        // 转换为列表
        List<Week> list = Arrays.asList(days);
        // 增加周六为工作日
        list.add(Week.Sat);
        /* do something */
    }
}
enum Week {
    Sun, Mon, Tue, Wed, Thu, Fri, Sat
}

UnsupportedOperationException,不支持的操作,居然不支持list的add方法,这是什么原因呢?

此ArrayList非java.util.ArrayList,而是Arrays工具类的一个内部类

我们深入地看看这个ArrayList静态内部类,它仅仅实现了5个方法:

① size:元素数量

② get:获得制定元素

③ set:重置某一元素值

④ contains:是否包含某元素

⑤ toArray:转化为数组,实现了数组的浅拷贝

对于我们经常使用list.add和list.remove方法它都没有实现,也就是说asList返回的是一个长度不可变的列表,数组是多长,转换成的列表也就是多长,换句话说此处的列表只是数组的一个外壳,不再保持列表的动态变长的特性,这才是我们关注的重点。有些开发人员喜欢这样定义个初始化列表: 

List<String> names= Arrays.asList("张三","李四","王五");

一句话完成了列表的定义和初始化,看似很便捷,却隐藏着重大隐患---列表长度无法修改。想想看,如果这样一个List传递到一个允许添加的add操作的方法中,那将会产生何种结果,如果有这种习惯的javaer,请慎之戒之,除非非常自信该List只用于只读操作。

建议67:不同的列表选择不同的遍历算法

测试来看简单for循环比foreach能快那么一丢丢。

建议68:频繁插入和删除时使用LinkedList

ArrayList在进行插入元素时:

    public void add(int index, E element) {
        //检查下标是否越界
        rangeCheckForAdd(index);
        //若需要扩容,则增大底层数组的长度
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //给index下标之后的元素(包括当前元素)的下标加1,空出index位置
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //赋值index位置元素
        elementData[index] = element;
        //列表长度加1
        size++;
    }

注意看arrayCopy方法,只要插入一个元素,其后的元素就会向后移动一位,虽然arrayCopy是一个本地方法,效率非常高,但频繁的插入,每次后面的元素都要拷贝一遍,效率变的就低了。而使用LinkedList就显得更好了,LinkedList是一个双向列表,它的插入只是修改了相邻元素的next和previous引用。

原理不说了。

修改元素:LinkedList不如ArrayList,因为LinkedList是按顺序存储的,因此定位元素必然是一个遍历过程,效率大打折扣。而ArrayList的修改动作是数组元素的直接替换,简单高效。

LinkedList:删除和插入效率高;ArrayList:修改元素效率高。

建议69:列表相等只关心元素数据

判断集合是否相等只须关注元素是否相等即可,不用看容器

相关文章

暂住......别动,不想说点什么吗?
  • 全部评论(0
    还没有评论,快来抢沙发吧!