Java Efficient Code 50 Cases

Keywords: Java JSON JDK Lambda

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

Posted by Shaba1 on Fri, 27 Dec 2019 20:53:05 -0800