[Java]《编写高质量代码》笔记(2/2)

《编写高质量代码》笔记(1/2)

数组和集合

警惕数组的浅拷贝

通过copyOf的方法得到的数组是一个浅拷贝,而且,数组的clone方法也只能得到浅拷贝。

需要注意的是,集合并没有提供拷贝的方法,这时不要使用诸如List.toArray的方法尝试利用ArraycopyOf方法,这样就恰好撞到枪口上了。

在明确场景下,为集合指定初始容量

常用的ArrayList会按照1.5倍的速度扩容,每次扩容都是一次数组的拷贝,如果数据量大,这样的拷贝会非常耗资源。与之类似,Vector默认按照2倍的速度扩容,但是这个速率可以在构造函数中自己指定。

原始类型数组不能作为asList的参数

1
2
int[] data = {1,2,3,4,5};
List list = Arrays.asList(data);

这时list的长度为1,且list[0]data数组,修改方法如下:

1
2
Integer[] data = {1,2,3,4,5};
List list = Arrays.asList(data);

asList方法产生的List对象不可更改

asList产生的List对象仅有以下五个方法:

  • size
  • toArray
  • get
  • set
  • contains

而常用的addremove方法都不支持,这是JDK设计的缺陷,值得我们注意。

频繁插入和删除时使用LinkedList

ArrayList修改的效率高,但插入和删除都完败LinkedList

列表相等只关注元素数据

AbstractList中定义了equals的方法,其实现中只比较各个元素是否相等。

推荐使用subList处理局部列表

subList产生的列表只是一个视图(View),所有的修改直接作用于原列表。

例如要删除list的第20到30项元素,可以这样写:

1
list.subList(20, 30).clear();

但是值得注意的是,subList生成子列表后,要将原列表置为只读状态,一旦修改,再去操作子列表时,会抛出ConcurrentModificationException异常。

多线程中使用Vector或HashTable

VectorArrayList的多线程版本。

HashTableHashMap的多线程版本。

集合大家族

  • List
    • ArrayList:动态数组
    • LinkedList:双向链表
    • Vector:线程安全的动态数组
    • Stack:栈
  • Set
    • EnumSet:枚举类型专用的
    • HashSet:可以快速插入和查找
    • TreeSet:自动排序
  • Map
    • TreeMap:根据Key值自动排序
    • HashMap:可以快速插入和查找
    • HashTable:线程安全的HashMap
    • Properties:是HashTable的子类,可以从Property文件中加载数据
    • EnumMap:Key必须是枚举类型
    • WeakHashMap:其对象的存在并不会阻止GC对键值对的回收(不会内存泄漏,但存在安全隐患)
  • Queue
    • ArrayBlockingQueue:数组实现的有界阻塞队列
    • PriorityBlockingQueue:依照优先级组件的队列
    • LinkedBlockingQueue:通过链表实现的有界阻塞队列
    • PriorityQueue:优先级无界队列
    • ArrayDeque:数组实现的双端队列
    • LinkedBlockingDeque:链表实现的双端队列
    • LinkedList:也分在了List

异常

提倡异常的封装

自己封装异常可以提高系统的友好性和可维护性,要避免使用catch来捕捉所有异常。

不要在finally块中return

finally块中的return会覆盖try中的return,而且会使throw的异常被屏蔽。

多线程和并发

线程优先级只使用三个等级

Java的线程共有10个等级,这个优先级只是概率性的,并不是优先级高的就一定先运行,建议只使用MIN_PRIORITYNORM_PRIORITYMAX_PRIORITY

Lock和synchronized是不一样的

  • Lock支持更细粒度的锁控制:可以做到读写分离等等
  • Lock是无阻塞锁,而synchronized是阻塞锁:等待状态≠阻塞状态(虽然对外部表现为阻塞)
  • Lock可实现公平锁,synchronized是非公平锁:Lock会选择等待时间最长的
  • Lock是代码级的,synchronized是JVM级的:synchronized的性能更好

总之,灵活、强大选择Lock,快捷、安全选择synchronized

其它

若非必要,不要克隆对象

克隆对象的效率比构造对象的效率要低。

POLA

Principle Of Least Surprise,最小惊诧原则。要使用最常见而不是最新颖的功能。不要为了炫技而“吓”了你的同伴或用户。