数组和集合
警惕数组的浅拷贝
通过copyOf的方法得到的数组是一个浅拷贝,而且,数组的clone方法也只能得到浅拷贝。
需要注意的是,集合并没有提供拷贝的方法,这时不要使用诸如List.toArray的方法尝试利用Array的copyOf方法,这样就恰好撞到枪口上了。
在明确场景下,为集合指定初始容量
常用的ArrayList会按照1.5倍的速度扩容,每次扩容都是一次数组的拷贝,如果数据量大,这样的拷贝会非常耗资源。与之类似,Vector默认按照2倍的速度扩容,但是这个速率可以在构造函数中自己指定。
原始类型数组不能作为asList的参数
1  | int[] data = {1,2,3,4,5};  | 
这时list的长度为1,且list[0]为data数组,修改方法如下:
1  | Integer[] data = {1,2,3,4,5};  | 
asList方法产生的List对象不可更改
asList产生的List对象仅有以下五个方法:
sizetoArraygetsetcontains
而常用的add和remove方法都不支持,这是JDK设计的缺陷,值得我们注意。
频繁插入和删除时使用LinkedList
ArrayList修改的效率高,但插入和删除都完败LinkedList。
列表相等只关注元素数据
AbstractList中定义了equals的方法,其实现中只比较各个元素是否相等。
推荐使用subList处理局部列表
subList产生的列表只是一个视图(View),所有的修改直接作用于原列表。
例如要删除list的第20到30项元素,可以这样写:
1  | list.subList(20, 30).clear();  | 
但是值得注意的是,subList生成子列表后,要将原列表置为只读状态,一旦修改,再去操作子列表时,会抛出ConcurrentModificationException异常。
多线程中使用Vector或HashTable
Vector是ArrayList的多线程版本。
HashTable是HashMap的多线程版本。
集合大家族
ListArrayList:动态数组LinkedList:双向链表Vector:线程安全的动态数组Stack:栈
SetEnumSet:枚举类型专用的HashSet:可以快速插入和查找TreeSet:自动排序
MapTreeMap:根据Key值自动排序HashMap:可以快速插入和查找HashTable:线程安全的HashMapProperties:是HashTable的子类,可以从Property文件中加载数据EnumMap:Key必须是枚举类型WeakHashMap:其对象的存在并不会阻止GC对键值对的回收(不会内存泄漏,但存在安全隐患)
QueueArrayBlockingQueue:数组实现的有界阻塞队列PriorityBlockingQueue:依照优先级组件的队列LinkedBlockingQueue:通过链表实现的有界阻塞队列PriorityQueue:优先级无界队列ArrayDeque:数组实现的双端队列LinkedBlockingDeque:链表实现的双端队列LinkedList:也分在了List中
异常
提倡异常的封装
自己封装异常可以提高系统的友好性和可维护性,要避免使用catch来捕捉所有异常。
不要在finally块中return
finally块中的return会覆盖try中的return,而且会使throw的异常被屏蔽。
多线程和并发
线程优先级只使用三个等级
Java的线程共有10个等级,这个优先级只是概率性的,并不是优先级高的就一定先运行,建议只使用MIN_PRIORITY、NORM_PRIORITY和MAX_PRIORITY。
Lock和synchronized是不一样的
Lock支持更细粒度的锁控制:可以做到读写分离等等Lock是无阻塞锁,而synchronized是阻塞锁:等待状态≠阻塞状态(虽然对外部表现为阻塞)Lock可实现公平锁,synchronized是非公平锁:Lock会选择等待时间最长的Lock是代码级的,synchronized是JVM级的:synchronized的性能更好
总之,灵活、强大选择Lock,快捷、安全选择synchronized
其它
若非必要,不要克隆对象
克隆对象的效率比构造对象的效率要低。
POLA
Principle Of Least Surprise,最小惊诧原则。要使用最常见而不是最新颖的功能。不要为了炫技而“吓”了你的同伴或用户。