Java 高质量编程建议(笔记8)

来源:互联网 发布:linux下安装nginx 编辑:程序博客网 时间:2024/05/18 17:00
Ad-60:性能考虑,数组是首选
    1)Java中JDK提供了List、Set、Map等集合类,方便各种应用场景的编码,但是这些集合的底层实现还是依赖于数组;
    2)Java中集合类型是泛型,而泛型支持的是对象类型,不支持基本类型,但是数组支持基本类型;
    3)由于集合类型不支持基本类型, 而数组支持,在对大量数据做运算情况下, 数组的效率比集合类型高,集合类型的元素存入时需要进行包装,再取出来时需要拆箱;
    4)基本类型是在栈内存中,而对象类型的对象实例则在堆内存中;前者访问速度更快;
   
Ad-61:若有必要,使用变长数组
    1)Java中数组是定长的,一旦初始化声明就不可改变数组的长度;
    2)不存在变长数组,但是可以通过“动态”扩容数组,利用Arrays.copyOf创建一个新数组,并拷贝旧数组的值到新数组中;
    3)Java的集合类,都采用了“动态”扩容数组的方式支持集合元素数量不固定;
   
Ad-62:警惕数组的浅拷贝
    1)Java中数组本身是一个对象,而所有的对象的拷贝取决于是否提供clone方法和clone方法的实现,数组也是一个对象类,其clone方法是浅拷贝;
    2)数组的拷贝通常使用Arrays.copyOf,如果数组存放的是对象类型,copyOf拷贝对象的引用,如果数组存放的是基本类型,copyOf拷贝其值,因此Arrays.copyOf是浅拷贝,不会调用对象的clone方法;
    3)集合类型的clone方法也是浅拷贝;
  
Ad-63:在明确的场景下,为集合指定初始容量
    1)前面已经讲过,集合类型的底层实现也是数组,而却数组的长度是定长的,也就是说,集合类型的在创建的时候,也会创建一个固定长度的数组,我们常用的集合类型都是通过new 集合类构造方法来创建一个集合类的对象,通常不指定其初始容量;
    2)集合类型的操作通常是通过add,remove来对集合进行操作,增加或删除元素,这样当add增加的元素超过初始时容量时,集合内部也是要对数组进行扩容的,集合类型一般都有私有方法ensureCapactiy进行扩容;
    3)不同集合类型默认的初始容量不同,扩容量的步长也不同;
       
    4)集合类型扩容的方法都是通过Arrays.copyOf完成的,因此扩容是比较耗时的操作,因此明确了应用场景的情况下,尽量为集合指定初始容量,避免添加元素过程中动态扩容,导致性能下降;
   
Ad-64:多种最值算法, 适时选择
    1)通常需要计算一个序列/一个组的最大值/最小值,实现方式有多种,可以利用Java提供的排序进行先排序,然后取最值,但是效率并不是最好的;
    2)最好使用数组,然后通过比较来获取最值,让要取多个最值是,可以利用堆排技术;
    3)如果数据存在重复,则可以使用Set先过滤掉重复的数据;
    4)如果重复数据必须存在,谨慎考虑二分法查找,避免查找的位置不是所需;
   
   
Ad-65:避开基本类型数组转换列表陷阱
    1)在Java中经常使用Arrays和Collections工具类在数组和列表之间进行转换;
    2)Arrays.asList将对象类型变长参数转换为列表, 其方法是参数类型是泛型的,但是基本类型不是泛型,而数组是泛型,因此如果将基本类型的数组作为asList的参数传入,得到的将是一个List,其元素时一个数组,而不是基本类型的包装类型;
    3)asList的方法定义和实现
    public static <T> List<T> asList(T...a)
    {
        return new ArrayList<T>(a);
    }
   
Ad-66:asList方法产生的List对象不可更改
    1)asList方法返回的是ArrayList,但是这个ArrayList与java.util.ArrayList的ArrayList不同,asList返回的ArrayList是一个内部类,只能通过构造函数初始化元素,add和remove没有实现,而内部的数组是final修饰的;
 
Ad-67:不同的列表选择不同的遍历方法
    1)ArrayList数组链表实现了RandomAccess接口(随机存取接口)标志着ArrayList是一个可以随机存取的列表,表示数据元素之间没有关系;
    2)Java中,RandomAccess、Cloneable和Serializable三个接口都是标志性接口,不需要实现,表明其类具备接口描述的特征
        2.1)实现了Cloneable表明可以拷贝;
        2.2)实现了Serializable表明可以被序列化;
        2.3)实现了RandomAccess表明类可以随机存取;
    3)Java中foreach的语法是iterator的变形用法,iterator提供了一种方法访问一个容器中对象中的各个元素,同时又无需暴露对象的内部实现细节;
    4)iterator访问是根据元素之间的顺序关系来访问的,但是ArrayList实现了RandomAccess,即元素之间没有关联关系,如果要通过iterator访问,相当于要重新计算元素之间的关系因此对于ArrayList来说,通过下标访问比通过foreach访问效率要高;
    5)相反,对于LinkedList来说,它是一个双向链表,每个元素都保留了前后元素的引用,通过iterator能很方便的遍历元素,当然也可以下标遍历,但是LinkedList的下标实现存取的时候,都需要从头或尾遍历到第i个元素,如果i<size/2,从头开始向后遍历,否则从尾部开始向前遍历,每次get(i)都需循环遍历,要通过下标遍历完N个元素的数组,时间效率为O(N^2)因此对于LinkedList,使用foreach效率更高;