Java编码技巧之高效代码 1 成员变量无需更改的时候,尽量定义位静态的 无论一个类实例化多少对象,它的静态变量只有一份拷贝
反列: 1 2 3 4 public class HttpConnection { private final long timeout = 5L ; ... }
正列: 1 2 3 4 public class HttpConnection { private static final long TIMEOUT = 5L ; ... }
代码实战 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class Static { private static int count=0 ; public static int getCount () { return count; } private static void add () { count++; } Static() { add(); } public static void main (String[] args) { Static static1 = new Static (); System.out.println("start:" +static1.getCount()); for (int i=0 ;i<10 ;i++){ static1=new Static (); } System.out.println("end:" +static1.getCount()); } } 控制台输出: start:1 end:11 如果不使用静态变量 start:1 end:1
2 如果变量的初值会被覆盖,就没有必要给变量赋初值 反例: 1 2 3 4 5 6 List<UserDO> userList = new ArrayList <>(); if (isAll) { userList = userDAO.queryAll(); } else { userList = userDAO.queryActive(); }
正列: 1 2 3 4 5 6 List<UserDO> userList; if (isAll) { userList = userDAO.queryAll(); } else { userList = userDAO.queryActive(); }
3 尽量使用函数内的基本类型临时变量 在函数中,基本类型的的参数和变量都保存在栈中,访问速度快 引用类型的参数和临时变量引用都保存在栈中,而实际内容在堆中存储,访问较慢,在类中,任何类型的成员变量都保存在堆中,访问慢
反例: 1 2 3 4 5 6 7 8 9 public final class Accumulator { private double result = 0.0D ; public void addAll (@NonNull double [] values) { for (double value : values) { result += value; } } ... }
正列: 1 2 3 4 5 6 7 8 9 10 11 public final class Accumulator { private double result = 0.0D ; public void addAll (@NonNull double [] values) { double sum = 0.0D ; for (double value : values) { sum += value; } result += sum; } ... }
4 尽量不使用反射赋值对象 用反射赋值对象,主要优点是节省了代码量,主要缺点却是性能有所下降 (BeanUtils.copyProperties)
反例: 1 2 3 4 5 6 7 List<UserDO> userDOList = ...; List<UserVO> userVOList = new ArrayList <>(userDOList.size()); for (UserDO userDO : userDOList) { UserVO userVO = new UserVO (); BeanUtils.copyProperties(userDO, userVO); userVOList.add(userVO); }
正列: 1 2 3 4 5 6 7 8 List<UserDO> userDOList = ...; List<UserVO> userVOList = new ArrayList <>(userDOList.size()); for (UserDO userDO : userDOList) { UserVO userVO = new UserVO (); userVO.setId(userDO.getId()); ... userVOList.add(userVO); }
5 尽量使用基本数据类型作为方法参数类型,避免不必要的装箱和拆箱和空指针判断 反例: 1 2 3 4 5 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; }
正列: 1 2 3 public static double sum (double value1, double value2) { return value1 + value2; }
6 尽量使用基本数据类型作为方法返回值类型,避免不必要的装箱和拆箱和空指针判断 在JDK类库的方法中,很多方法返回值都采用了基本数据类型,首先是为了避免不必要的装箱和拆箱,其次是为了避免返回值的空指针判断。比如:Collection.isEmpty()和Map.size()。
反例: 1 2 3 4 5 6 7 8 9 10 11 12 13 public static Boolean isValid (UserDO user) { if (Objects.isNull(user)) { return false ; } return Boolean.TRUE.equals(user.getIsValid()); } UserDO user = ...;Boolean isValid = isValid(user);if (Objects.nonNull(isValid) && isValid.booleanValue()) { ... }
正列: 1 2 3 4 5 6 7 8 9 10 11 12 public static boolean isValid (UserDO user) { if (Objects.isNull(user)) { return false ; } return Boolean.TRUE.equals(user.getIsValid()); } UserDO user = ...;if (isValid(user)) { ... }
7 尽量减少方法的重复调用 反例: 1 2 3 4 List<UserDO> userList = ...; for (int i = 0 ; i < userList.size(); i++) { ... }
正列: 1 2 3 4 5 List<UserDO> userList = ...; int userLength = userList.size();for (int i = 0 ; i < userLength; i++) { ... }
8 尽量不要在循环体外定义对象引用 在老版JDK里,建议“尽量不要在循环体内定义对象引用”,但是在新版JDK已经做了优化。通过对编译后的字节码分析,对象引用定义在循环体外和循环体内没有本质的区别,运行效率基本上一样。反而,根据“ 局部变量作用域最小化 ”,变量定义在循环体内更科学更便于维护,避免了大对象延长生命周期导致延缓回收问题 。
反例: 1 2 3 4 5 6 7 8 9 UserVO userVO; List<UserDO> userDOList = ...; List<UserVO> userVOList = new ArrayList <>(userDOList.size()); for (UserDO userDO : userDOList) { userVO = new UserVO (); userVO.setId(userDO.getId()); ... userVOList.add(userVO); }
正列: 1 2 3 4 5 6 7 8 List<UserDO> userDOList = ...; List<UserVO> userVOList = new ArrayList <>(userDOList.size()); for (UserDO userDO : userDOList) { UserVO userVO = new UserVO (); userVO.setId(userDO.getId()); ... userVOList.add(userVO); }
9 尽量不要使用正则表达式匹配 正则表达式匹配效率较低,尽量使用字符串匹配操作。
反例: 1 2 3 String source = "a::1,b::2,c::3,d::4" ;String target = source.replaceAll("::" , "=" );Stringp[] targets = source.split("::" );
正列: 1 2 3 String source = "a::1,b::2,c::3,d::4" ;String target = source.replace("::" , "=" );Stringp[] targets = StringUtils.split(source, "::" );
10 尽量重复使用同一缓冲区 针对缓冲区,Java虚拟机需要花时间生成对象,还要花时间进行垃圾回收处理。所以,尽量重复利用缓冲区。
反例: 1 2 3 4 5 6 StringBuilder builder1 = new StringBuilder (128 );builder1.append("update t_user set name = '" ).append(userName).append("' where id = " ).append(userId); statement.executeUpdate(builder1.toString()); StringBuilder builder2 = new StringBuilder (128 );builder2.append("select id, name from t_user where id = " ).append(userId); ResultSet resultSet = statement.executeQuery(builder2.toString());
正列: 1 2 3 4 5 6 StringBuilder builder = new StringBuilder (128 );builder.append("update t_user set name = '" ).append(userName).append("' where id = " ).append(userId); statement.executeUpdate(builder.toString()); builder.setLength(0 ); builder.append("select id, name from t_user where id = " ).append(userId); ResultSet resultSet = statement.executeQuery(builder.toString());
11 在多线程中,尽量使用线程安全类 使用线程安全类,比自己实现的同步代码更简洁更高效。
反例: 1 2 3 4 5 6 7 private volatile int counter = 0 ;public void access (Long userId) { synchronized (this ) { counter++; } ... }
正列: 1 2 3 4 5 private final AtomicInteger counter = new AtomicInteger (0 );public void access (Long userId) { counter.incrementAndGet(); ... }