1. 优化你的程序,拒绝创建不必要的对象
如果你的变量,后面的逻辑判断,一定会被赋值;或者说,只是一个字符串变量,直接初始化字符串常量就可以了,没有必要愣是要new String().
反例:
String s = new String ("欢迎关注公众号");
正例:
String s = “欢迎关注公众号”
2. 初始化集合时,指定容量
阿里的开发手册,也明确提到这个点:
假设你的map要存储的元素个数是15个左右,最优写法如下
//initialCapacity = 15/0.75+1=21
Map map = new HashMap(21);
又因为hashMap的容量跟2的幂有关,所以可以取32的容量
Map map = new HashMap(32);
3. 注意检验空指针,不要轻易相信业务,说正常逻辑某个参数不可能为空。
NullPointerException 在我们日常开发中非常常见,我们代码开发过程中,一定要对空指针保持灵敏的嗅觉。
主要有这几类空指针问题:
-
包装类型的空指针问题
-
级联调用的空指针问题
-
Equals方法左边的空指针问题
-
ConcurrentHashMap 类似容器不支持 k-v为 null。
-
集合,数组直接获取元素
-
对象直接获取属性
「反例:」
public class NullPointTest {
public static void main(String[] args) {
String s = null;
if (s.equals("666")) { //s可能为空,会导致空指针问题
System.out.println("干货满满");
}
}
}
4. 如果变量的初值一定会被覆盖,就没有必要给变量赋初值。
「反例:」
List<UserInfo> userList = new ArrayList<>();
if (isAll) {
userList = userInfoDAO.queryAll();
} else {
userList = userInfoDAO.queryActive();
}
「正例:」
List<UserInfo> userList ;
if (isAll) {
userList = userInfoDAO.queryAll();
} else {
userList = userInfoDAO.queryActive();
}
5. 注意Arrays.asList的几个坑
-
「基本类型不能作为 Arrays.asList方法的参数,否则会被当做一个参数。」
public class ArrayAsListTest {
public static void main(String[] args) {
int[] array = {1, 2, 3};
List list = Arrays.asList(array);
System.out.println(list.size());
}
}
//运行结果
1
-
「Arrays.asList 返回的 List 不支持增删操作。」
public class ArrayAsListTest {
public static void main(String[] args) {
String[] array = {"1", "2", "3"};
List list = Arrays.asList(array);
list.add("5");
System.out.println(list.size());
}
}
// 运行结果
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at object.ArrayAsListTest.main(ArrayAsListTest.java:11)
Arrays.asList 返回的 List 并不是我们期望的 java.util.ArrayList,而是 Arrays 的内部类ArrayList。内部类的ArrayList没有实现add方法,而是父类的add方法的实现,是会抛出异常的呢。
-
「使用Arrays.asLis的时候,对原始数组的修改会影响到我们获得的那个List」
public class ArrayAsListTest {
public static void main(String[] args) {
String[] arr = {"1", "2", "3"};
List list = Arrays.asList(arr);
arr[1] = "4";
System.out.println("原始数组"+Arrays.toString(arr));
System.out.println("list数组" + list);
}
}
//运行结果
原始数组[1, 4, 3]
list数组[1, 4, 3]
正确写法:ArrayList<Integer> integersList = new ArrayList<>(Arrays.asList(1,2,3));
6. 注意 ArrayList.toArray() 强转的坑
public class ArrayListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>(1);
list.add("codeAmaz");
String[] array21 = (String[])list.toArray();//类型转换异常
}
}
因为返回的是Object类型,Object类型数组强转String数组,会发生ClassCastException。解决方案是,使用toArray()重载方法toArray(T[] a)
String[] array1 = list.toArray(new String[0]);//可以正常运行
或者使用jdk8 stream流
Integer[] integersArray2 = integersList.stream().toArray(Integer[]::new);
7.多线程异步优先考虑恰当的线程池,而不是new thread,同时考虑线程池是否隔离
为什么优先使用线程池?使用线程池有这几点好处呀
-
它帮我们管理线程,避免增加创建线程和销毁线程的资源损耗。
-
提高响应速度。
-
重复利用。
同时呢,尽量不要所有业务都共用一个线程池,需要考虑线程池隔离。就是不同的关键业务,分配不同的线程池,然后线程池参数也要考虑恰当哈。之前写过几篇线程池的,觉得还不错,有兴趣的朋友可以看一下哈
8.优化程序结构,尽量减少方法的重复调用
「反例:」
public static void listDetail(List<UserInfo> userInfoList) {
for (int i = 0; i < userInfoList.size(); i++) {
//重复调用userList.size()方法了
}
}
「正例:」
public static void listDetail(List<UserInfo> userInfoList) {
int length = userInfoList.size();
for (int i = 0; i < length; i++) {
//减少调用userList.size()方法,只在length变量调了一次。
}
}
9使用spring事务功能时,注意这几个事务未生效的坑
日常业务开发中,我们经常跟事务打交道,事务失效主要有以下几个场景:
-
底层数据库引擎不支持事务
-
在非public修饰的方法使用
-
rollbackFor属性设置错误
-
本类方法直接调用
-
异常被try...catch吃了,导致事务失效。
10.直接迭代需要使用的集合,无须在额外操作
直接迭代需要使用的集合,无需通过其它操作获取数据,比较典型就是Map的迭代遍历:
「反例:」
Map<Long, UserDO> userMap = ...;
for (Long userId : userMap.keySet()) {
UserDO user = userMap.get(userId);
...
}
「正例:」
Map<Long, UserDO> userMap = ...;
for (Map.Entry<Long, UserDO> userEntry : userMap.entrySet()) {
Long userId = userEntry.getKey();
UserDO user = userEntry.getValue();
...
}