目录
编码优化
(一)、对象与基本类型
1. clone() 方式创建对象的选择
private static Person per = new Person();
public static Person getPerson() throws CloneNotSupportedException{
return (Person) per.clone();
}
注意:该方式是浅拷贝,类需要实现 Cloneable 接口,拷贝的新对象会包含一些原来对象的信息,当构造器中有复杂逻辑执行时,clone()方式创建对象才比new快(clone() 是对内存中数据块的拷贝,没有调用构造器)。
2.避免对boolean判断
当表达式结果为Boolean类型时,避免将表达式结果再与‘true’或‘false’进行比较。
if( str.endsWith("a")); //推荐
if(str.endsWith("a") == true ); //不推荐
3.静态方法的选择
如果不需要去访问对象的外部,那么就把方法声明为static的,如工具类中的方法。 静态方法通过“类名.方法名”的方式调用,无须创建对象,不需要虚拟导向表,可以更快的调用。
4.多使用局部变量
局部变量的访问速度远高于成员变量
5.运算符的选择
使用 || 代替 | ,使用 && 代替 & ,使用 >> 、<< 、>>> 代替部分算术运算
6.数据维数的选择
二维数组的访问速度优于一维数组,但二维数组比一维数组要占用更多的内存。
7.表达式优化
int a1,a2,a3;
//方式1
int b1 = a1*a2*a3*13;
int b2 = a1*a2*a3*17;
int b3 = a1*a2*a3*19;
//优化方式
int c0 = a1*a2*a3;
int b1 = c0*13;
int b2 = c0*17;
int b3 = c0*19;
8.避免重复初始化变量
java会把变量初始化为一个确定的值,对象为null,整数类型为0,浮点类型为0.0,布尔类型为false,
9.数值字面量的改进
int a = 0b10; //二进制,数字前加"0b"或"0B"
System.out.println(a); //2
int b = 017; //八进制,数字前加"0"
System.out.println(b); //15
int c = 0x15; //十六进制,数字前加"0x"或"0X"
System.out.println(c); //21
int d = 50_000_000; //加"_"增加可读性,相当于50,000,000
System.out.println(d); //50000000
10.赋空变量
赋空变量是指将null值显示的赋给变量。这样使该变量的引用失去作用域,不再有对该变量的引用,它就可以被当做垃圾收集了。(对于局部变量,当方法执行完毕,局部变量就失去了作用域,栈就会删除对该变量的引用)
(二)、集合类
List | 原理 | 同步性 | 重复值 | null 元素 | 初始大小 | 数据增长 | 读写速度 |
LinkedList | 基于链表 | 不同步 | 允许 | 允许 | 0 | 每次都新建Entry对象 | 慢 |
ArrayList | 基于数组 | 不同步 | 允许 | 允许 | 创建时为0,添加第一个元素时为10 | 不足时增加50% | 快 |
Vector | 基于数组 | 同步 | 允许 | 允许 | 创建时为0,添加第一个元素时为10 | 不足时增加一倍 | —— |
对于ArrayList,若能提前估算容量,设定初始大小,避免在添加数据过程中进行扩容操作,可提高性能
Set | 原理 | 同步性 | 重复值 | null 元素 | 初始大小 | 数据增长 | 读写速度 | 内存占用 | 有序性 |
HashSet | HashMap | 不同步 | 不允许 | 允许 | 16 | 达到0.75时增加一倍 | 快 | 多 | 无序 |
TreeSet | TreeMap (基于红黑树) | 不同步 | 不允许 | 不允许 | 16 | 达到0.75时增加一倍 | 慢 | 少 | 有序性 |
Map | 原理 | 同步性 | null 元素 | 初始大小 | 数据增长 |
HashMap | 哈希表 | 不同步 | 允许 | 16 | 达到0.75时增加一倍 |
Hashtable | 哈希表 | 同步 | 不允许 | 11 | 达到0.75时增加一倍 |
集合在遍历过程中需要进行元素的增减操作,使用迭代器,否则会出现ConcurrentModificationException。
1.subList 方法
subList() 方法可以获取原来集合的一部分数据,但这两个集合间存在关联,对子集合的修改会相应的反映到原集合上;对原集合的修改,若是对元素值的改变,子集合也会相应改变,如是对集合元素的增减,子集合会抛出ConcurrentModificationException。
2.asList 方法
判断某个元素是否在数组中时,可以使用 Arrays.asList(T[] array).contains(T obj),避免迭代循环。
(三)、字符串
1.使用 ' ' 代替 " "
例: String a = "abc" + "d"; 优化为 : String a = "abc" + 'd';
2.charAt代替startsWith
例如: if(str.startsWith("a")); 优化为: if('a' == str.charAt(0));
3.使用StringTokenizer 类进行短字符串分割
对于长度在几十个字符以内的字符串,使用StringTokenizer 时效率较高
String str = "abc*bdd*sd";
StringTokenizer t = new StringTokenizer(str, "*");
while(t.hasMoreTokens()){
System.out.println(t.nextToken());
}
4.字符串拼接
对长字符串进行拼接时,使用 StringBuffer 或 StringBuilder 效率更高。
这两个类都是AbstractStringBuilder的子类,StringBuffer的方法几乎都是synchronized的,而StringBuilder的方法都是不同步的。
(四)、引用类型
java中提供了四个级别的引用,即强引用(FinalReference)、软引用(SoftReference)、弱引用(WeakReference)、虚引用(PhantomReference)。
1.强引用
系统中最常见的一种引用,无需引用就可以直接使用的对象。JVM宁可抛出OOM,也不会清理强引用对象。
String str = "Hello World";
2.软引用
JVM在抛出OOM之前,会清理所有的软引用对象。
List<Object> list = new ArrayList<>();//对象
SoftReference<List<Object>> soft = new SoftReference<>(list); //标记为软引用
list = soft.get();//从软引用中获取对象
(补充:将软引用用于对象缓存,将导致更高的堆占用,相应导致了更频繁的GC。另外,不同JVM对于软引用的策略不同,同一JVM中不同的垃圾收集器对于软引用的策略也不同,这将导致使用软引用的java程序在可移植性上造成限制)【《java性能调优指南》P63 】
3.弱引用
JVM在执行GC时,会清理所有的弱引用。
WeakReference<Object> weak = new WeakReference<>(obj);
4.虚引用
又叫“幽灵引用”,随时都会被GC清理掉,并且虚引用的get方法总返回null,因此无法通过虚引用获取被引用的对象。主要目的是在一个对象被实际回收之前得到通知,从而进行一些相关的清理工作,可以作为finalize方法的辅助使用。
Object obj = new Object();
ReferenceQueue<Object> que = new ReferenceQueue<>();
PhantomReference<Object> phantom = new PhantomReference<Object>(obj, que);
JVM对该对象进行GC时,会调用该对象的finalize方法,finalize方法运行之后,虚引用才会被添加到队列中。