Reading Guide
There are only two substances in the world: high efficiency and low efficiency; there are only two kinds of people in the world: high efficiency and low efficiency.--Shaw
Constant-Variable
Assigning constants directly prohibits declaration of new objects
Assigning a constant value directly creates an object reference that points to the constant value.
Counterexamples
Long i=new Long(1L); String s=new String("abc");
Positive examples
Long i=1L;
String s="abc";
Define member variable values as static constants whenever possible without changing them
In each object instance of a class, each member variable has a copy, while the member static constant has only one instance.
Counterexamples
public class HttpConnection{ private final long timeout=5L; ... }
Positive examples
public class HttpConnection{ private static final long timeout=5L; ... }
Use basic data types whenever possible and avoid automatic boxing and unboxing
The basic data types in Java are double, float, long, int, short, char, boolean, which correspond to the wrapper classes Double, Float, Long, Integer, Short, Character, Boolean, respectively.
Jvm supports automatic conversion of basic types to object wrapper classes and is called automatic boxing and unboxing.Packing and unpacking both require CPU and memory resources, so try to avoid automatic packing and unpacking.
Counterexamples
Integer sum = 0; int[] values = { 1, 2, 3, 4, 5 }; for (int value : values) { sum+=value; }
Positive examples
int sum = 0; int[] values = { 1, 2, 3, 4, 5 }; for (int value : values) { sum+=value; }
If the initial value of a variable is overridden, it is not necessary to assign an initial value to the variable
Counterexamples
public static void main(String[] args) { boolean isAll = false; List<Users> userList = new ArrayList<Users>(); if (isAll) { userList = userDAO.queryAll(); } else { userList=userDAO.queryActive(); } } public class Users { } public static class userDAO { public static List<Users> queryAll() { return null; } public static List<Users> queryActive() { return null; } }
Positive examples
public static void main(String[] args) { boolean isAll = false; List<Users> userList; if (isAll) { userList = userDAO.queryAll(); } else { userList=userDAO.queryActive(); } } public class Users { } public static class userDAO { public static List<Users> queryAll() { return null; } public static List<Users> queryActive() { return null; } }
Use basic types of temporary variables within functions whenever possible
Within a function, parameters of the basic type and temporary variables are stored on the stack (Stack) for faster access; parameters of the object type and references to temporary variables are stored on the stack (Stack), and contents are stored on the stack (Heap) for slower access.In a class, any type of member variable is stored in a heap (Heap) and is accessed slowly.
Counterexamples
public final class Accumulator { private double result = 0.0D; public void addAll(@NonNull double[] values) { for (double value : values) { result += value; } } }
Positive examples
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; } }
Try not to define variables outside the circulation
In older versions of JDK, it is recommended that variables not be defined in the loop as much as possible, but they have been optimized in the new version of JDK.By analyzing the compiled byte code, there is no essential difference between variable definitions in vitro and in vivo, and the operating efficiency is basically the same.Instead, according to the principle of minimizing the scope of local variables, variable definitions are more scientific and easier to maintain in the loop, avoiding the problem of delaying recycling by prolonging the life cycle of an object.
Counterexamples
UserVO userVo; List<UserVO> userDOList=new ArrayList<>(5); for(UserVO vo:userDOList) { userVo=new UserVO(); ... }
Positive examples
List<UserVO> userDOList=new ArrayList<>(5); for(UserVO vo:userDOList) { UserVO userVo=new UserVO(); ... }
Invariant static constants, use non-threaded security classes whenever possible
An immutable static constant that requires multithreaded access or can use a non-threaded security class.
Counterexamples
public static final Map<String, Class> CLASS_MAP; static { Map<String, Class> classMap=new ConcurrentHashMap<>(16); classMap.put("VARCHAR", java.lang.String.class); ... CLASS_MAP=Collections.unmodifiableMap(classMap); }
Positive examples
public static final Map<String, Class> CLASS_MAP; static { Map<String, Class> classMap=new HashMap<>(16); classMap.put("VARCHAR", java.lang.String.class); ... CLASS_MAP=Collections.unmodifiableMap(classMap); }
Invariant member variables, use non-threaded security classes whenever possible
An immutable member variable that requires multithreaded access or can use a non-threaded security class.
Counterexamples
private List<Strategy> strategyList; private Map<String, Strategy> strategyMap; public void afterPropertiesSet() { if (CollectionUtils.isNotEmpty(strategyList)) { int size=(int)Math.ceil(strategyList.size()*4.0/3); Map<String, Strategy> map=new ConcurrentHashMap<>(size); strategyMap=Collections.unmodifiableMap(map); } }
Positive examples
private List<Strategy> strategyList; private Map<String, Strategy> strategyMap; public void afterPropertiesSet() { if (CollectionUtils.isNotEmpty(strategyList)) { int size=(int)Math.ceil(strategyList.size()*4.0/3); Map<String, Strategy> map=new HashMap<>(size); strategyMap=Collections.unmodifiableMap(map); } }
Object & Class
Prohibit using JSON to convert objects
JSON provides the ability to convert objects to JSON strings and JSON strings to objects, and is therefore used by some people to convert objects.This way of converting objects, although functionally sound, has performance problems.
Counterexamples
List<UserDO> userDOList=new ArrayList<>(); List<UserVO> userVOList=JSON.parseArray(JSON.toJSONString(userDOList), UserVO.class);
Positive examples
List<UserDO> userDOList=new ArrayList<>(); List<UserVO> userVOList=new ArrayList<>(); for(UserDO userDO:userDOList) { UserVO vo=new UserVO(); ... }
Try not to use reflection assignment objects
The main advantage of assigning objects with reflection is that it saves code, but the main disadvantage is that performance decreases.
Counterexamples
List<UserDO> userDOList=new ArrayList<>(); List<UserVO> userVOList=new ArrayList<>(); for(UserDO userDO:userDOList) { UserVO vo=new UserVO(); BeanUtils.copyProperties(userDO,vo); userVOList.add(vo); }
Positive examples
List<UserDO> userDOList=new ArrayList<>(); List<UserVO> userVOList=new ArrayList<>(); for(UserDO userDO:userDOList) { UserVO vo=new UserVO(); vo.setId(userDO.getId()); ... userVOList.add(vo); }
Replace internal anonymous classes with Lambda expressions
For most students new to JDK8, Lambda expressions are considered grammatical sugars for anonymous internal classes.In fact, Lambda expressions are implemented in most virtual machines using invokeDynamic instructions, which are more efficient than anonymous internal classes.
Counterexamples
List<User> userList=new ArrayList<>(); Collections.sort(userList,new Comparator<User>() { @Override public int compare(User o1, User o2) { Long userId1=o1.getId(); Long userId2=o2.getId(); return userId1.compareTo(userId2); } });
Positive examples
List<User> userList=new ArrayList<>(); Collections.sort(userList,(User o1,user o2)->{ Long userId1=o1.getId(); Long userId2=o2.getId(); return userId1.compareTo(userId2); });
Try to avoid defining unnecessary subclasses
More classes require more classes to load, so try to avoid defining unnecessary subclasses.
Counterexamples
public static final Map<String, Class> CLASS_MAP=Collections.unmodifiableMap(new HashMap<String, Class>(16){ private static final long serialVersionUID=1L; { put("VARCHAR", java.lang.String.class); } });
Positive examples
public static final Map<String, Class> CLASS_MAP; static { Map<String, Class> classMap=new HashMap<>(); classMap.put("VARCHAR", java.lang.String.class); CLASS_MAP=Collections.unmodifiableMap(classMap); }
Specify final modifiers for classes whenever possible
Specify a final modifier for a class so that it cannot be inherited.If a class is specified as final, all methods of that class are final, and the Java compiler will look for opportunities to converge all final methods.Convergence plays an important role in improving Java runtime efficiency. See Java runtime optimization for an average performance improvement of 50%.
Counterexamples
public class DateHelper{ ... }
Positive examples
public final class DateHelper{ ... }
Note: Beans need to be proxied dynamically when using Spring's AOP feature, which can lead to exceptions if the Bean class is modified with final.
Method
Declare methods that are independent of class member variables as static methods
The advantage of static methods is that they can be called directly without generating an instance of a class.Static methods no longer belong to an object, but to the class in which they belong.It can be accessed simply by its class name without consuming resources to create objects over and over again.Even private methods within a class should be declared static if class member variables are not used.
Counterexamples
public int getMonth(Date date) { Calendar calendar=Calendar.getInstance(); calendar.setTime(date); return calendar.get(calendar.MONTH)+1; }
Positive examples
public static int getMonth(Date date) { Calendar calendar=Calendar.getInstance(); calendar.setTime(date); return calendar.get(calendar.MONTH)+1; }
Use basic data types as method parameter types whenever possible to avoid unnecessary boxing, unboxing, and null pointer judgments
Counterexamples
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; }
Positive examples
public static double sum(double value1,double value2) { return value1+value2; }
Use basic data types as method return value types whenever possible, avoiding unnecessary boxing, unboxing, and null pointer judgments
In the methods of JDK class libraries, many methods return values using basic data types, first to avoid unnecessary boxing and unboxing, and second to avoid null pointer judgment of return values.For example:
- Collection.isEmpty()
- Map.size()
Counterexamples
public static void main(String[] args) { UserDO userDO=new UserDO(); boolean isValid=isValid(userDO); if (Objects.isNull(isValid)&&Objects.isNull(isValid)) { } } public static Boolean isValid(UserDO userDO) { if (Objects.isNull(userDO)) { return false; } return Boolean.TRUE.equals(userDO.getIsValid()); }
Positive examples
public static void main(String[] args) { UserDO userDO=new UserDO(); if (isValid(userDO)) { } } public static Boolean isValid(UserDO userDO) { if (Objects.isNull(userDO)) { return false; } return Boolean.TRUE.equals(userDO.getIsValid()); }
Protocol method parameter value is not null, avoiding unnecessary null pointer judgment
Protocol programming can label parameters at @NonNull and @Nullable, depending on the caller's awareness.
Counterexamples
public static Boolean isValid(UserDO userDO) { if (Objects.isNull(userDO)) { return false; } return Boolean.TRUE.equals(userDO.getIsValid()); }
Positive examples
public static Boolean isValid(@NonNull UserDO userDO) { if (Objects.isNull(userDO)) { return false; } return Boolean.TRUE.equals(userDO.getIsValid()); }
Protocol method return value is not null, avoiding unnecessary null pointer judgment
Protocol programming, which can label parameters at @NonNull and @Nullable, depends solely on the implementer's awareness.
Counterexamples
public static void main(String[] args) { OrderService orderService=null; List<OrderVO> orderList=orderService.queryUserOrder((long) 5); } public interface OrderService{ public List<OrderVO> queryUserOrder(Long userId); }
Positive examples
public static void main(String[] args) { OrderService orderService=null; List<OrderVO> orderList=orderService.queryUserOrder((long) 5); } public interface OrderService{ @NonNull public List<OrderVO> queryUserOrder(Long userId); }
The invoked method already supports null processing, and the invoked method does not need to be null anymore
Counterexamples
UserDO userDO = null; if (StringUtils.isNotBlnk(values)) { userDO = JSON.parseObject(values, UserDO.class); }
Positive examples
UserDO userDO = JSON.parseObject(values, UserDO.class);
Avoid unnecessary function encapsulation whenever possible
Method calls can lead to stack entry and stack exit, consuming more CPU and memory, and unnecessary function encapsulation should be avoided as much as possible.Of course, in order to make the code simpler, clearer, and easier to maintain, it's worth increasing the performance penalty caused by certain method calls.
Counterexamples
public static void main(String[] args) { boolean isVip=isVip(User.getVip()); } public static boolean isVip(boolean isVip) { return Boolean.TRUE.equals(isVip); }
Positive examples
public static void main(String[] args) { boolean isVip=Boolean.TRUE.equals(User.getVip()); }
Specify final modifiers for methods whenever possible
The method specifies a final modifier so that the method cannot be overridden, and the Java compiler will look for opportunities to converge all final methods.Convergence plays an important role in improving Java runtime efficiency. See Java runtime optimization for an average performance improvement of 50%.
Note: All private methods are implicitly assigned a final modifier, so there is no need to specify a final modifier for them.
Counterexamples
public class User { public int getAge() { return 10; } }
Positive examples
public class User { public final int getAge() { return 10; } }
Note: Bean s need to be proxied dynamically when using Spring's AOP feature, and methods will not be proxied if final modifications are added.
Expression
Minimize method duplicate calls
Counterexamples
List<User> userList=new ArrayList<>(); for (int i = 0; i < userList.size(); i++) { ... }
Positive examples
List<User> userList=new ArrayList<>(); int userLength=userList.size(); for (int i = 0; i < userLength; i++) { ... }
Avoid unnecessary method calls whenever possible
Counterexamples
List<User> userList=userDAO.queryActive(); if (isAll) { userList=userDAO.queryAll(); }
Positive examples
List<User> userList; if (isAll) { userList=userDAO.queryAll(); }else { userList=userDAO.queryActive(); }
Use shift instead of positive integer multiplication and division whenever possible
Shift operations can greatly improve performance.For positive integer calculations multiplied by 2^n(n is a positive integer), a shift operation can be used instead.
Counterexamples
int num1=a*4; int num2=a/4;
Positive examples
int num1=a<<2; int num2=a>>2;
Extract common expressions to avoid duplicate calculations
Extract the common expression, calculate the value only once, and reuse the value.
Counterexamples
double distance=Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
Positive examples
double dx=x2-x1; double dy=y2-y1; double distance=Math.sqrt(dx*dx+dy*dy); //or double distance=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
Try not to use in conditional expressions! Reverse
Use! Negative calculates more than once and optimizes if not necessary.
Counterexamples
if(!(a>=10)){ .... }else{ .... }
Positive examples
if(a<10){ ... }else{ ... }
For Multi-constant selection branches, try using the switch statement instead of the if-else statement
if-else statement, each if condition statement is loaded with a calculation until the if condition statement is true.The switch statement is optimized for jumping, and Java is implemented using tableswitch or lookupswitch instructions, which are more efficient for Multi-constant selection branch processing.
Experiments have shown that if-else statements are more efficient when the probability of each branch is the same, and switch statements are more efficient when the probability of each branch is lower than five branches.
Counterexamples
if(i==1){ .... }else if(i==2){ ... }else if(i==...){ ... }else{ ... }
Positive examples
switch (i) { case 1: ... break; case 2: ... break; case 3: ... break; default: ... break; }
Note: If the business is complex, the Map implementation strategy pattern can be used
Character string
Try not to use regular expression matching
Regular expression matching is inefficient, use string matching whenever possible.
Counterexamples
String source="a::1,b::2,c::3"; String target=source.replaceAll("::", "="); String[] targets=source.split("::");
Positive examples
String source="a::1,b::2,c::3"; String target=source.replaceAll("::", "="); String[] targets=StringUtils.split(source,"::");
Replace strings with characters whenever possible
The length of the string is uncertain and the length of the character is fixed to 1, which naturally improves the efficiency of finding and matching.
Counterexamples
String source="a:1,b:2,c:3"; int index=source.indexOf(":"); String target=source.replace(":", "=");
Positive examples
String source="a:1,b:2,c:3"; int index=source.indexOf(':'); String target=source.replace(':', '=');
String Builder for string stitching whenever possible
String is a final class whose contents cannot be modified, so each string stitching generates a new object.
StringBuilder requested a block of memory at initialization, where subsequent string splicing will be performed without requesting new memory or generating new objects.
Counterexamples
String s = ""; for (int i = 0; i < 10; i++) { s += i + ","; }
Positive examples
StringBuilder s = new StringBuilder(); for (int i = 0; i < 10; i++) { s.append(i).append(","); }
Do not use "" + to convert strings
String.valueOf is recommended for string conversion using''+', which is convenient but inefficient.
Counterexamples
int i = 123; String s = "" + i;
Positive examples
int i = 123; String s = String.valueOf(i);
array
Do not use circular copy arrays, try System.arraycopy copy copy arrays
System.arraycopy copy copy arrays are recommended or Arrays.copyOf copy arrays can be used.
Counterexamples
int[] source = new int[] { 1, 2, 3, 4, 5 }; int[] targets = new int[source.length]; for (int i = 0; i < source.length; i++) { targets[i] = source[i]; }
Positive examples
int[] source = new int[] { 1, 2, 3, 4, 5 }; int[] targets = new int[source.length]; System.arraycopy(source, 0, targets, 0, targets.length);
When converting a collection to a type T array, pass in an empty array T[0]
There are two ways to convert a collection to an array: toArray(new T[n]) and toArray(new T[0]).In older Java versions, toArray(new T[n]) was recommended because reflection calls required for locks were very slow when creating arrays.After OpenJDK6, reflection calls are inherent, resulting in improved performance, and toArray(new T[0]) is more efficient than toArray(new T[n]).
In addition, toArray(new T[n]) obtains the list size once more than toArray(new T[0]), which can also cause toArray(new T[n]) to be less efficient if it takes too long to calculate the list size.
Counterexamples
List<Integer> integerList=Arrays.asList(1,2,3,4,5); Integer[] integers=integerList.toArray(new Integer[integerList.size()]);
Positive examples
List<Integer> integerList=Arrays.asList(1,2,3,4,5); Integer[] integers=integerList.toArray(new Integer[0]); //Do not use new Integer[]{}
Suggestion: Collections should provide a toArray (Class <T> clazz) method to avoid useless empty array initialization (new T[0]);
When converting a collection to an Object array, use the toArray() method whenever possible
When converting an Object array, it is not necessary to use toArray[new Object[0], but toArray() can be used directly.It avoids type judgments and empty array requests, so it is more efficient.
Counterexamples
List<? extends Object> objectList=Arrays.asList(1,"2",3); Object[] objects=objectList.toArray(new Object[0]);
Positive examples
List<? extends Object> objectList=Arrays.asList(1,"2",3); Object[] objects=objectList.toArray();
aggregate
When initializing a collection, specify the collection size whenever possible
Java collections are initialized with a default size that expands when the default size no longer meets the data requirements, possibly with a time complexity of 0(n).Therefore, by specifying the predicted set size as much as possible, you can avoid or reduce the number of times the set is expanded.
Counterexamples
List<UserDO> userdoList=new ArrayList<UserDO>(); Set<Long> userSet=new HashSet<Long>(); Map<Long, UserDO> userMap=new HashMap<Long, UserDO>(); List<UserVO> userList=new ArrayList<UserVO>(); for (UserDO userDO:userdoList) { userSet.add(userDO.getId()); userMap.put(userDO.getId(), userDO); userList.add(transUser(userDO)); }
Positive examples
List<UserDO> userdoList = new ArrayList<UserDO>(); int userSize = userdoList.size(); Set<Long> userSet = new HashSet<Long>(userSize); Map<Long, UserDO> userMap = new HashMap<Long, UserDO>((int) Math.ceil(userSize * 4.0 / 3)); List<UserVO> userList = new ArrayList<UserVO>(userSize); for (UserDO userDO : userdoList) { userSet.add(userDO.getId()); userMap.put(userDO.getId(), userDO); userList.add(transUser(userDO)); }
Do not use circular copy collections, try to use methods provided by JDK to copy collections
The method provided by JDK allows you to specify the capacity of a collection in one step, avoiding wasting time and space by expanding multiple times.At the same time, the bottom level of these methods is to call the System.arraycopy method implementation, which makes batch copying of data more efficient.
Counterexamples
List<UserDO> user1List=new ArrayList<UserDO>(); List<UserDO> user2List=new ArrayList<UserDO>(); List<UserDO> userList=new ArrayList<UserDO>(user1List.size()+user2List.size()); for (UserDO user1:user1List) { userList.add(user1); } for (UserDO user2:user2List) { userList.add(user2); }
Positive examples
List<UserDO> user1List=new ArrayList<UserDO>(); List<UserDO> user2List=new ArrayList<UserDO>(); List<UserDO> userList=new ArrayList<UserDO>(user1List.size()+user2List.size()); userList.addAll(user1List); userList.addAll(user2List);
Convert arrays to lists using Arrays.asList whenever possible
The principle is similar to "Do not use circular copy sets, try to use the method copy sets provided by JDK".
Counterexamples
List<String> typeList=new ArrayList<String>(8); typeList.add("Short"); typeList.add("Integer"); typeList.add("Long"); String[] names=new String[] {}; List<String> nameList=new ArrayList<String>(); for (String name:names) { nameList.add(name); }
Positive examples
List<String> typeList=Arrays.asList("Short","Integer","Long"); String[] names=new String[] {}; List<String> nameList=Arrays.asList(); nameList.addAll(Arrays.asList(names));
Sets to be used for direct iteration
Direct iteration requires the collection to be used, without obtaining data through other operations.
Counterexamples
Map<Long, UserDO> userMap=new HashMap<Long, UserDO>(); for (long userId:userMap.keySet()) { UserDO userDO=userMap.get(userId); }
Positive examples
Map<Long, UserDO> userMap=new HashMap<Long, UserDO>(); for (Map.Entry<Long, UserDO> userEntry:userMap.entrySet()) { Long userId=userEntry.getKey(); UserDO userDO=userEntry.getValue(); }
Do not use the size method to detect nulls, you must use the isEmpty method to detect nulls
There is no problem using the size method to detect nulls logically, but using the isEmpty method makes the code easier to read and provides better performance.The time complexity of any isEmpty method implementation is 0 (1), but some size methods may have a time complexity of 0(n).
Counterexamples
List<UserDO> userList=new ArrayList<UserDO>(); if (userList.size()==0) { } Map<Long, UserDO> userMap=new HashMap<Long, UserDO>(); if (userMap.size()==0) { }
Positive examples
List<UserDO> userList=new ArrayList<UserDO>(); if (userList.isEmpty()) { } Map<Long, UserDO> userMap=new HashMap<Long, UserDO>(); if (userMap.isEmpty()) { }
List with non-random access, try to use iteration instead of random access
Lists can be divided into random access and non-random access, which can be determined by whether the RandomAccess interface is implemented or not.Random access to lists, getting data directly through get, does not affect efficiency.Instead of randomly accessing lists, getting data through get is extremely inefficient.
Counterexamples
List<UserDO> userList=new ArrayList<UserDO>(); int size=userList.size(); for (int i = 0; i < size; i++) { }
Positive examples
List<UserDO> userList=new ArrayList<UserDO>(); for (UserDO userDO:userList) { }
In fact, iterations should be used to traverse regardless of whether the list branch does not support random access.
Although using HashSet to determine the value exists
In Java collection class libraries, the Contains method of List has an average time complexity of 0(n), while HashSet has a time complexity of 0 (1).If you need to call the contains method frequently to find data, you can first convert the List to HashSet.
Counterexamples
List<Long> userIdList=new ArrayList<Long>(); List<UserDO> userList=new ArrayList<UserDO>(); for (UserDO userDO:userList) { if (userIdList.contains(userDO.getId())) { } }
Positive examples
Set<Long> userIdSet=new HashSet<Long>(); List<UserDO> userList=new ArrayList<UserDO>(); for (UserDO userDO:userList) { if (userIdSet.contains(userDO.getId())) { } }
Avoid judging existence before acquiring
If you need to judge the existence before acquiring, you can directly obtain and judge the null, thus avoiding the second lookup operation.
Counterexamples
public UserVO transUser(UserDO userDO,Map<Long, RoleDo> roleMap) { UserVO userVO=new UserVO(); userVO.setId(userDO.getId()); if (roleMap.containsKey(userDO.getId())) { } return null; }
Positive examples
public UserVO transUser(UserDO userDO,Map<Long, RoleDo> roleMap) { UserVO userVO=new UserVO(); userVO.setId(userDO.getId()); RoleDo role=roleMap.get(userDO.getId()); if (Objects.nonNull(role)) { } return null; }
abnormal
Catch the corresponding exception directly
Capture exceptions directly, avoid instanceof judgment, and make your code more efficient and concise.
Counterexamples
try { } catch (Exception e) { if (e instanceof IIOException) { System.out.println("Save data IO abnormal"); }else { System.out.println("Save Data Other Exceptions"); } }
Positive examples
try { } catch (IIOException e) { System.out.println("Save data IO abnormal"); } catch (Exception e) { System.out.println("Save Data Other Exceptions"); }
Avoid catching exceptions in loops whenever possible
When the loop body throws an exception, it is not necessary to catch the exception in the loop body when the loop does not need to continue executing.Because too many catch exceptions can reduce program execution efficiency.
Counterexamples
public Double sum(List<String> valueList) { double sum=0.0D; for (String value:valueList) { try { sum+=Double.parseDouble(value); } catch (Exception e) { return null; } } return sum; }
Positive examples
public Double sum(List<String> valueList) { double sum = 0.0D; try { for (String value : valueList) { sum += Double.parseDouble(value); } } catch (Exception e) { return null; } return sum; }
Prohibit use of exception control business processes
Exceptions are less efficient to handle than conditional expressions.
Counterexamples
public static boolean isValid(UserDO user) { try { return Boolean.TRUE.equals(user.getId()); } catch (Exception e) { return false; } }
Positive examples
public static boolean isValid(UserDO user) { if (Objects.isNull(user)) { return false; } return Boolean.TRUE.equals(user.getId()); }
Buffer
Specify buffer size whenever possible during initialization
When initializing, specify the expected container size of the buffer to avoid wasting time and space by multiple expansion.
Counterexamples
StringBuffer buffer=new StringBuffer(); StringBuilder buider=new StringBuilder();
Positive examples
StringBuffer buffer=new StringBuffer(1024); StringBuilder buider=new StringBuilder(1024);
Reuse the same buffer whenever possible
For buffers, the Java virtual machine takes time to generate objects and garbage collection.So try to reuse buffers as much as possible.
Counterexamples
StringBuffer buider1=new StringBuffer(128); buider1.append("abcdef"); StringBuffer buider2=new StringBuffer(128); buider2.append("abcdef");
Positive examples
StringBuffer buider1=new StringBuffer(128); buider1.append("abcdef"); buider1.setLength(0); buider1.append("abcdef");
Note: where the setLength method is used to restart the buffer from 0.
Try to design the same buffer
To improve program efficiency, use the same buffer as possible in design.
Counterexamples
public static String toXml(UserDO user) { StringBuilder buider=new StringBuilder(128); buider.append("<UserDO>"); buider.append(toXml(user.getId())); buider.append("</UserDO>"); return buider.toString(); } public static String toXml(Long value) { StringBuilder builder=new StringBuilder(128); builder.append("<Long>"); builder.append(value); builder.append("</Long>"); return builder.toString(); } //call UserDO user=new UserDO(); String xml=toXml(user);
Positive examples
public static String toXml(StringBuilder buider,UserDO user) { buider.append("<UserDO>"); buider.append(toXml(buider,user.getId())); buider.append("</UserDO>"); return buider.toString(); } public static String toXml(StringBuilder builder,Long value) { builder.append("<Long>"); builder.append(value); builder.append("</Long>"); return builder.toString(); } //call StringBuilder builder=new StringBuilder(128); UserDO user=new UserDO(); String xml=toXml(builder,user);
Remove the buffer request for each transformation method and request a buffer for each transformation method to use.In terms of time, a large amount of buffer application release time is saved; in terms of space, a large amount of buffer temporary storage space is saved.
Minimize IO operations with buffered streams
- BufferedReader
- BufferedWriter
- BufferedInputStream
- BufferedOutputStream
- ....
You can significantly reduce the number of IOs and increase the speed of IO.
Counterexamples
try { FileInputStream inputStream = new FileInputStream("a.txt"); FileOutputStream outputStream = new FileOutputStream("b.txt"); int size = 0; byte[] temp = new byte[1024]; while ((size = inputStream.read(temp)) != -1) { outputStream.write(temp, 0, size); } } catch (IIOException e) { System.out.println(e.getMessage()); }
Positive examples
try { BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("a.txt")); BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("b.txt")); int size = 0; byte[] temp = new byte[1024]; while ((size = inputStream.read(temp)) != -1) { outputStream.write(temp, 0, size); } } catch (IIOException e) { System.out.println(e.getMessage()); }
The size of the buffer stream can be specified manually according to the actual situation to maximize the buffer effect of the buffer stream.
thread
Use non-threaded security classes whenever possible in a single thread
Using non-threaded security classes avoids unnecessary synchronization overhead.
Counterexamples
StringBuffer buffer=new StringBuffer(128); buffer.append("abcd");
Positive examples
StringBuilder buffer=new StringBuilder(128); buffer.append("abcd");
In multithreaded environments, use thread-safe classes whenever possible
Using thread-safe classes is simpler and more efficient than synchronizing code you implement yourself.
Counterexamples
private volatile int count=0; public void access() { synchronized (this) { count++; } }
Positive examples
private final AtomicInteger countInteger=new AtomicInteger(0); public void access() { countInteger.incrementAndGet(); }
Minimize the scope of synchronization blocks
In one method, there may be only a small part of the logic that requires synchronization control, which can affect the efficiency of execution.Therefore, minimize the scope of synchronized code blocks and synchronize only the code that needs to be synchronized.
Counterexamples
private volatile int count=0; public synchronized void access() { count++; //...Asynchronous operation }
Positive examples
private volatile int count=0; public void access() { synchronized (this) { count++; } //...Asynchronous operation }
Merge as many blocks of synchronous code as possible
Synchronization code blocks have performance overhead. If you are sure you can merge them into the same synchronization code block, you should try to merge the same synchronization code as quickly as possible.
Counterexamples
//Processing a single order public synchronized void handleOrder(OrderDO order) { } //Process all orders public void handleOrder(List<OrderDO> orderList) { for (OrderDO order:orderList) { handleOrder(order); } }
Positive examples
// Processing a single order public void handleOrder(OrderDO order) { } // Process all orders public synchronized void handleOrder(List<OrderDO> orderList) { for (OrderDO order : orderList) { handleOrder(order); } }
Minimize thread overhead by using thread pools
There are two overhead requirements in multithreading: thread creation and context switching.With thread pools, these overhead can be avoided as much as possible.
Counterexamples
public void executeTask(Runnable runnable) { new Thread(runnable).start(); }
Positive examples
private static final ExecutorService EXECUTOR_SERVICE=Executors.newFixedThreadPool(10); public static void executeTask(Runnable runnable) { EXECUTOR_SERVICE.execute(runnable); }
Reference: https://mp.weixin.qq.com/s/izVH7nVkQVpYbyJKN35uLA