一、 方法
1. 尽量指定类、方法的final修饰符
如果指定了一个类为final,则该类所有的方法都是final的。Java编译器会寻找机会内联所有的final方法,内联对于提升Java运行效率作用重大,具体参见Java运行期优化。此举能够使性能平均提高50%。
二、 变量
1. 循环内不要不断创建对象引用
例如:
for (int i = 1; i <= count; i++){
Object obj = new Object;
}
这种做法会导致内存中有count份Object对象引用存在,count很大的话,就耗费内存了,建议为改为:
Object obj = null;
for (int i = 0; i <= count; i++) {
obj = new Object;
}
这样的话,内存中只有一份Object对象引用,每次new Object的时候,Object对象引用指向不同的Object罢了,但是内存中只有一份,这样就大大节省了内存空间了。
2. 基本类型转换成字符串
把一个基本数据类型转为字符串,基本数据类型.toString是最快的方式、String.valueOf次之、数据+””最慢
3. 如果变量的初值会被覆盖,就没有必要给变量赋初值
反例:
List<UserDO> userList = new ArrayList<>();
if (isAll) {
userList = userDAO.queryAll();
} else {
userList = userDAO.queryActive();
}
正例:
List<UserDO> userList;
if (isAll) {
userList = userDAO.queryAll();
} else {
userList = userDAO.queryActive();
}
4. 尽量使用基本数据类型,避免不必要的装箱、拆箱和空指针判断
反例:
public static double sum(Double value1, Double value2) {
double double1 = Objects.isNull(value1) ? 0.0D : value1;
double double2 = Objects.isNull(value2) ? 0.0D : value2;
return double1 + double2;
}
double result = sum(1.0D, 2.0D);
正例:
public static double sum(double value1, double value2) {
return value1 + value2;
}
double result = sum(1.0D, 2.0D);
三、常量
1. 将常量声明为static final,并以大写命名
这样在编译期间就可以把这些内容放入常量池中,避免运行期间计算生成常量的值。另外,将常量的名字以大写命名也可以方便区分出常量与变量
2. 禁止使用JSON转化对象
虽然在功能上没有问题,但是在性能上却存在问题。
四、对象
1. 尽量重用对象
特别是String对象的使用,出现字符串连接时应该使用StringBuilder/StringBuffer代替。由于Java虚拟机不仅要花时间生成对象,以后可能还需要花时间对这些对象进行垃圾回收和处理,因此,生成过多的对象将会给程序的性能带来很大的影响。
五、循环
1. 不要在循环中使用try…catch…,应该把其放在最外层
除非不得已。如果毫无理由地这么写了,那是不合理的。
2. for、增强for、iterator的选择
参考文章:List遍历:for,foreach Iterator 速度比较
总结:iterator 性能更优
// 遍历Set
Set<String> set = new HashSet<>();
set.add("a");
set.add("a");
set.add("b");
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
// 遍历List
List<String> list = new ArrayList<>();
list.add("a");
list.add("a");
list.add("b");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
// 遍历Map
Map<String, String> nameMap = new HashMap<>();
nameMap.put("student1", "lihua");
Set<Map.Entry<String, String>> entries = nameMap.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while(iterator.hasNext()){
Map.Entry<String, String> entry = iterator.next();
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
六、集合
1. ArrayList和LinkedList
顺序插入和随机访问比较多的场景使用ArrayList,元素删除和中间插入比较多的场景使用LinkedList
2. 如果能估计到待添加的内容长度,尽量为指定初始长度
比如ArrayList、LinkedLlist、StringBuilder、StringBuffer、HashMap、HashSet等等,以StringBuilder为例:
(1)StringBuilder// 默认分配16个字符的空间
(2)StringBuilder(int size) // 默认分配size个字符的空间
(3)StringBuilder(String str) // 默认分配16个字符+str.length个字符空间
(4)List 默认长度是10
(5) Map 默认长度是16
只要达到它的最大容量,它就不得不创建一个新的字符数组然后将旧的字符数组内容拷贝到新字符数组中—-这是十分耗费性能的一个操作
七、字符串
1. 尽量避免使用split
除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。
2. 基本类型转换成字符串
把一个基本数据类型转为字符串,基本数据类型.toString是最快的方式、String.valueOf次之、数据+””最慢
3. 在字符串相加的时候,使用 ‘ ‘ 代替 " ",如果该字符串只有一个字符的话
例子:
public class STR {
public void method(String s) {
String string = s + "d" // violation.
string = "abc" + "d" // violation.
}
}
// 更正: 将一个字符的字符串替换成' '
public class STR {
public void method(String s) {
String string = s + "d // violation.
string = "abc" + 'd' // violation.
}
}
八、方法
1. 把跟类成员变量无关的方法声明成静态方法
静态方法的好处就是不用生成类的实例就可以直接调用。静态方法不再属于某个对象,而是属于它所在的类。只需要通过其类名就可以访问,不需要再消耗资源去反复创建对象。即便在类内部的私有方法,如果没有使用到类成员变量,也应该声明为静态方法。
反例:
public int getMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.get(Calendar.MONTH) + 1;
}
正例:
public static int getMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.get(Calendar.MONTH) + 1;
}