一、字符串操作
1.1 新建字符串应采用直接赋值代替new操作
由于存在字符串常量池,使用赋值语句赋值时,如果常量池中存在字符,会直接复用
public static void main(String[] args) {
String s1 = "北京天津深圳";
String s2 = "北京天津深圳";
String s3 = new String("北京天津深圳");
System.out.println(s1 == s2);// true
System.out.println(s1 == s3);// false
System.out.println(s2 == s3);// false
}
s1 s2引用常量池同一地址,所以返回true
由于s3是new的方式创建的,所以未复用常量池的常量,所以不等于s1和s2
收益测试(单位:微秒μs)
优化前 | 优化后 | 性能提升 |
---|---|---|
32 | 17 | 15% |
1.2 尽量确定StringBuffer | StringBuilder的大小
public static void main(String[] args) {
// 优化前 26ms
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 100000; i++) {
sb.append("sssss" + i);
}
// 优化后 17ms
StringBuffer sb = new StringBuffer(100000);
for (int i = 0; i < 100000; i++) {
sb.append("sssss" + i);
}
}
收益测试(单位:毫秒ms)
优化前 | 优化后 | 性能提升 |
---|---|---|
26 | 17 | 9% |
1.3 字符串匹配避免直接使用String类的matches方法
通常匹配字符串有3种方法
indexOf() 效率最高,执行最快,不支持正则
String类的matches方法,性能最差,支持正则,在循环体中执行时,每次都是重新创建Pattern
使用Pattern和Matcher类,支持正则,频繁比较时,性能优于String类的matches方法
public static void main(String[] args) {
// indexOf
for (int i = 0; i < 1000; i++) {
String ss = "字符串匹配避免直接使用String类的matches方法,应使用Pattern和Matches类";
ss.indexOf("matches方法");
}
// String.matches()
for (int i = 0; i < 1000; i++) {
String ss = "字符串匹配避免直接使用String类的matches方法,应使用Pattern和Matches类";
ss.matches("matches方法");
}
// Pattern and Matcher
Pattern pattern = Pattern.compile("matches方法");
for (int i = 0; i < 1000; i++) {
String ss = "字符串匹配避免直接使用String类的matches方法,应使用Pattern和Matches类";
pattern.matcher(ss);
}
}
收益测试(单位:微秒μs)
单条数据
indexOf | String.matches() | Pattern and Mtcher |
---|---|---|
10 | 41 | 101 |
多条数据 (1000条)
indexOf | String.matches() | Pattern and Mtcher |
---|---|---|
781 | 11469 | 1874 |
1.4 字符串替换避免对大对象使用String类的replaceAll()方法,应使用Pattern和Matches类
public static void main(String[] args) {
// 优化前
String ss = "字符串匹配避免直接使用String类的matches方法,应使用Pattern和Matches类";
ss.replaceAll("matches方法", "替换为java");
// 优化后
String ss = "字符串匹配避免直接使用String类的matches方法,应使用Pattern和Matches类";
Pattern pattern = Pattern.compile("matches方法");
pattern.matcher(ss).replaceAll("替换为java");
}
收益测试(单位:微秒μs)
优化前 | 优化后 | 性能提升 |
---|---|---|
121 | 86 | 35% |
1.5 字符串连接使用StringBuffer | StringBuilder ,不要直接使用“+”号
由于String是不可变对象,使用+号连接时,会创建大量临时变量,影响性能,建议如果多余3个+号的连接采用StringBuffer或StringBuilder
收益测试见1.2
二、循环体操作
2.1 循环终止条件尽量避免使用复杂表达式,减少重复计算
2.2 循环体内避免重复构造资源对象
2.3 循环体内避免使用异常处理
2.4 循环体内的循环变量的自增应使用 ++i 代替 i++
三、变量和类型
3.1 避免创建不必要的中间变量
// 优化前
public int add(int a, int b) {
int c = a + b;
return c;
}
// 优化后
public int add(int a, int b) {
return a + b;
}
收益测试(单位:纳秒ns)
优化前 | 优化后 | 性能提升 |
---|---|---|
9300 | 900 | 84% |
3.1 尽量避免随意使用静态变量
3.2 尽量使用final修饰符
3.4 尽量使用局部变量
四、运算操作
4.1 用短路逻辑运算符(&&或||)替换非短路逻辑运算符(&或|)
4.2 使用位移运算符替代 a*b 或 a/b 的操作
4.3 使用直接比较法替代Min或Max函数
public int min(int a) {
return Math.min(a, 50);
}
public int min(int a) {
return a < 50 ? a : 50;
}
引用外部库需要消耗一定的资源,简单的比较大小函数使用3目运算符更快
例外:Math库中比较方法,+0 大于 -0
五、集合操作
5.1 集合的使用应确定容量大小
原理同1.2