How to write a code as efficient and elegant as Arie

Posted by elite_prodigy on Mon, 25 Nov 2019 04:34:26 +0100

Reading Guide

Mr. Wang Yangming of the Ming Dynasty said when he talked about the doctrine of learning in Chuanxilu:

Selfish desires are born every day, like dust on the ground. If you do not sweep them every day, there will be another layer.With practical merit, you will see that the road is endless, and the deeper you explore, the whiter you will be.

The "bad taste" in the code, such as "selfish desire" such as "dust", is increasing every day. If you don't clean it up every day, the more it gets.If you work hard to remove these "bad smells", you can not only improve your coding level, but also make your code "completely white".Here, I have sorted out some "bad taste" in my daily work and cleaning methods for your reference.

Making your code perform better

When a Map's primary key and value are required, the entrySet() should be iterated over

Iterating keySet() is correct when only the primary key of the Map is required in the loop.However, iterating entrySet() is more efficient when primary keys and values are required, and performs better than iterating keySet() before get ing.

Counterexamples:

Map<String, String> map = ...;
for (String key : map.keySet()) {
    String value = map.get(key);
    ...
}

Example:

Map<String, String> map = ...;
for (Map.Entry<String, String> entry : map.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();
    ...
}

Collection.isEmpty() should be used to detect nulls

There is no problem using Collection.size() to detect null logic, but using Collection.isEmpty() makes the code easier to read and provides better performance.The time complexity of any Collection.isEmpty() implementation is O(1), but the time complexity of some Collection.size() implementations may be O(n).

Counterexamples:

if (collection.size() == 0) {
    ...
}

Example:

if (collection.isEmpty()) {
    ...
}

If you need to detect null s, you can use

CollectionUtils.isEmpty(collection) and CollectionUtils.isNotEmpty(collection).

Do not pass collection objects to yourself

In addition, passing a collection to itself may cause unexpected behavior because some methods require parameters to remain the same during execution.

Counterexamples:

List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
if (list.containsAll(list)) { // Nonsense, always returns true
    ...
}
list.removeAll(list); // Poor performance, use clear()

Collection initialization is as large as possible

java's collection classes are very convenient to use, but look at the source code, there are limitations on the size of the collection.The time complexity of each expansion is most likely O(n), so specifying a predictable set size as much as possible can reduce the number of times the set is expanded.

Counterexamples:

int[] arr = new int[]{1, 2, 3};
List<Integer> list = new ArrayList<>();
for (int i : arr) {
    list.add(i);
}

Example:

int[] arr = new int[]{1, 2, 3};
List<Integer> list = new ArrayList<>(arr.length);
for (int i : arr) {
    list.add(i);
}

String Builder for string stitching

Normal string splicing is optimized in compile-time java, but string splicing in loops cannot be optimized in compile-time java, so StringBuilder is needed to replace it.

Counterexamples:

String s = "";
for (int i = 0; i < 10; i++) {
    s += i;
}

Example:

String a = "a";
String b = "b";
String c = "c";
String s = a + b + c; // No problem, the java compiler will optimize
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
    sb.append(i);  // In a loop, the java compiler cannot be optimized, so use StringBuilder manually
}

Random Access to List s

Everyone knows the difference between an array and a list of chains: random access to arrays is more efficient.When the calling method gets a List, what if you want to access the data randomly and you don't know if the internal implementation of the array is a chain table or an array?You can determine if it implements the RandomAccess interface.

Example:

// Call someone else's service to get a list
List<Integer> list = otherService.getList();
if (list instanceof RandomAccess) {
    // Internal array implementation, random access
    System.out.println(list.get(list.size() - 1));
} else {
    // Internal may be chain table implementation, random access is inefficient
}

Use Set for frequent calls to Collection.contains methods

In a java collection class library, the contains method of a List has a general time complexity of O(n). If the contains method needs to be called frequently in the code to find data, you can first convert the list to a HashSet implementation, reducing the time complexity of O(n) to O(1).

Counterexamples:

ArrayList<Integer> list = otherService.getList();
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
    // Time Complexity O(n)
    list.contains(i);
}

Example:

ArrayList<Integer> list = otherService.getList();
Set<Integer> set = new HashSet(list);
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
    // Time Complexity O(1)
    set.contains(i);
}

Making code more elegant

Add uppercase L after long integer constant

When using a long integer constant value, L needs to be added after it. It must be uppercase L, not lowercase L, which can easily be confused with number 1 and can be misinterpreted.

Counterexamples:

long value = 1l;
long max = Math.max(1L, 5);

Example:

long value = 1L;
long max = Math.max(1L, 5L);

Do not use magic values

Magic values may seem obvious when you write a piece of code, but they don't seem so clear when debugging.This is why magic values need to be defined as readable constants.However, -1, 0, and 1 are not considered magic values.

Counterexamples:

for (int i = 0; i < 100; i++){
    ...
}
if (a == 100) {
    ...
}

Example:

private static final int MAX_COUNT = 100;
for (int i = 0; i < MAX_COUNT; i++){
    ...
}
if (count == MAX_COUNT) {
    ...
}

Do not use collection implementations to assign static member variables

For static member variables of a collection type, do not use a collection implementation to assign values, instead use a static code block to assign values.

Counterexamples:

private static Map<String, Integer> map = new HashMap<String, Integer>() {
    {
        put("a", 1);
        put("b", 2);
    }
};
private static List<String> list = new ArrayList<String>() {
    {
        add("a");
        add("b");
    }
};

Example:

private static Map<String, Integer> map = new HashMap<>();
static {
    map.put("a", 1);
    map.put("b", 2);
};

private static List<String> list = new ArrayList<>();
static {
    list.add("a");
    list.add("b");
};

The try-with-resources statement is recommended

A try-with-resources statement was introduced in Java 7, which guarantees that related resources will be closed, is superior to the original try-catch-final statement, and makes the program code safer and more concise.

Counterexamples:

private void handle(String fileName) {
    BufferedReader reader = null;
    try {
        String line;
        reader = new BufferedReader(new FileReader(fileName));
        while ((line = reader.readLine()) != null) {
            ...
        }
    } catch (Exception e) {
        ...
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                ...
            }
        }
    }
}

Example:

private void handle(String fileName) {
    try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
        String line;
        while ((line = reader.readLine()) != null) {
            ...
        }
    } catch (Exception e) {
        ...
    }
}

Delete unused private methods and fields

Delete unused private methods and fields to make your code simpler and easier to maintain.If you need to reuse it, you can retrieve it from your history submission.

Counterexamples:

public class DoubleDemo1 {
    private int unusedField = 100;
    private void unusedMethod() {
        ...
    }
    public int sum(int a, int b) {
        return a + b;
    }
}

Example:

public class DoubleDemo1 {
    public int sum(int a, int b) {
        return a + b;
    }
}

Delete unused local variables

Delete unused local variables to make your code simpler and easier to maintain.

Counterexamples:

public int sum(int a, int b) {
    int c = 100;
    return a + b;
}

Example:

public int sum(int a, int b) {
    return a + b;
}

Remove unused method parameters

Unused method parameters are misleading, deleting unused method parameters makes the code simpler and easier to maintain.However, since override methods are method definitions based on a parent class or interface, they cannot be deleted even if there are unused method parameters.

Counterexamples:

public int sum(int a, int b, int c) {
    return a + b;
}

Example:

public int sum(int a, int b) {
    return a + b;
}

Remove extra brackets from expressions

Redundant parentheses in corresponding expressions are thought to be helpful in code reading, or unnecessary at all.For someone familiar with Java syntax, the extra parentheses in an expression can make the code more cumbersome.

Counterexamples:

return (x);
return (x + 2);
int x = (y * 3) + 1;
int m = (n * 4 + 2);

Example:

return x;
return x + 2;
int x = y * 3 + 1;
int m = n * 4 + 2;

Tool classes should mask constructors

Tool classes are a collection of static fields and functions that should not be instantiated.However, java adds an implicit public constructor for each class that does not have a well-defined constructor.Therefore, to avoid misuse of java Small White, you should explicitly define a private constructor to block this implicit public constructor.

Counterexamples:

public class MathUtils {
    public static final double PI = 3.1415926D;
    public static int sum(int a, int b) {
        return a + b;
    }
}

Example:

public class MathUtils {
    public static final double PI = 3.1415926D;
    private MathUtils() {}
    public static int sum(int a, int b) {
        return a + b;
    }
}

Remove redundant exception capture and throw

After catching an exception with the catch statement, do nothing and throw the exception again, which is the same as not catching the exception. You can delete this code or add other handling.

Counterexamples:

private static String readFile(String fileName) throws IOException {
    try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
        String line;
        StringBuilder builder = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            builder.append(line);
        }
        return builder.toString();
    } catch (Exception e) {
        throw e;
    }
}

Example:

private static String readFile(String fileName) throws IOException {
    try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
        String line;
        StringBuilder builder = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            builder.append(line);
        }
        return builder.toString();
    }
}

Public static constants should be accessed through classes

Although it is allowed to access public static constants through instances of classes, it is easy to mistake an instance of each class for having a public static constant.Therefore, public static constants should be accessed directly through classes.

Counterexamples:

public class User {
    public static final String CONST_NAME = "name";
    ...
}

User user = new User();
String nameKey = user.CONST_NAME;

Example:

public class User {
    public static final String CONST_NAME = "name";
    ...
}

String nameKey = User.CONST_NAME;

Do not use NullPointerException to judge null

Null pointer exceptions should be handled with code avoidance (for example, detection is not null) rather than by capturing exceptions.

Counterexamples:

public String getUserName(User user) {
    try {
        return user.getName();
    } catch (NullPointerException e) {
        return null;
    }
}

Example:

public String getUserName(User user) {
    if (Objects.isNull(user)) {
        return null;
    }
    return user.getName();
}

Use String.valueOf(value) instead of "" +value"

String.valueOf(value) is more efficient than "" +value"when converting other objects or types to strings.

Counterexamples:

int i = 1;
String s = "" + i;

Example:

int i = 1;
String s = String.valueOf(i);

Outdated Code Add @Deprecated Comment

When a piece of code is obsolete and cannot be deleted directly for compatibility, and you don't want it to be used again in the future, you can tag it with the @Deprecated comment.Add @deprecated to the documentation comments to explain and provide alternatives

Example:

/**
 * Preservation
 *
 * @deprecated This method is inefficient, please replace it with the {@link newSave()} method
 */
@Deprecated
public void save(){
    // do something
}

Keep code away from bug s

Prohibit use of construction method BigDecimal(double)

BigDecimal(double) is at risk of loss of precision and may cause business logic exceptions in scenarios where precise calculations or value comparisons occur.

Counterexamples:

BigDecimal value = new BigDecimal(0.1D); // 0.100000000000000005551115...

Example:

BigDecimal value = BigDecimal.valueOf(0.1D);; // 0.1

Returns an empty array and set instead of null

Returns null, requiring the caller to force null detection, otherwise a null pointer exception is thrown.Returns an empty array or collection, effectively avoiding null pointer exceptions thrown by the caller because null is not detected, or removing the caller's statement to detect null to make the code more concise.

Counterexamples:

public static Result[] getResults() {
    return null;
}

public static List<Result> getResultList() {
    return null;
}

public static Map<String, Result> getResultMap() {
    return null;
}

public static void main(String[] args) {
    Result[] results = getResults();
    if (results != null) {
        for (Result result : results) {
            ...
        }
    }

    List<Result> resultList = getResultList();
    if (resultList != null) {
        for (Result result : resultList) {
            ...
        }
    }

    Map<String, Result> resultMap = getResultMap();
    if (resultMap != null) {
        for (Map.Entry<String, Result> resultEntry : resultMap) {
            ...
        }
    }
}

Example:

public static Result[] getResults() {
    return new Result[0];
}

public static List<Result> getResultList() {
    return Collections.emptyList();
}

public static Map<String, Result> getResultMap() {
    return Collections.emptyMap();
}

public static void main(String[] args) {
    Result[] results = getResults();
    for (Result result : results) {
        ...
    }

    List<Result> resultList = getResultList();
    for (Result result : resultList) {
        ...
    }

    Map<String, Result> resultMap = getResultMap();
    for (Map.Entry<String, Result> resultEntry : resultMap) {
        ...
    }
}

Call the equals method first with a constant or a deterministic value

The object's equals method tends to throw null pointer exceptions, so the equals method should be called using a constant or an object with a value.Of course, using the java.util.Objects.equals() method is a best practice.

Counterexamples:

public void isFinished(OrderStatus status) {
    return status.equals(OrderStatus.FINISHED); // Possible null pointer exception thrown
}

Example:

public void isFinished(OrderStatus status) {
    return OrderStatus.FINISHED.equals(status);
}

public void isFinished(OrderStatus status) {
    return Objects.equals(status, OrderStatus.FINISHED);
}

Enumerated property fields must be private and immutable

Enumerations are often used as constants, and the properties of these enumeration constants can be easily modified if there are common property fields or set field methods in the enumeration.Ideally, an attribute field in an enumeration is private and assigned to a private constructor without a corresponding Setter method, preferably with a final modifier.

Counterexamples:

public enum UserStatus {
    DISABLED(0, "Disable"),
    ENABLED(1, "Enable");

    public int value;
    private String description;

    private UserStatus(int value, String description) {
        this.value = value;
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

Example:

public enum UserStatus {
    DISABLED(0, "Disable"),
    ENABLED(1, "Enable");

    private final int value;
    private final String description;

    private UserStatus(int value, String description) {
        this.value = value;
        this.description = description;
    }

    public int getValue() {
        return value;
    }

    public String getDescription() {
        return description;
    }
}

Be careful with String.split(String regex)

String split method, the incoming delimiter string is a regular expression!Some keywords (such as. []()|, etc.) need to be escaped

Counterexamples:

"a.ab.abc".split("."); // The result is []
"a|ab|abc".split("|"); // The result is ['a','|','a','b','|','a','b','c']

Example:

"a.ab.abc".split("\\."); // The result is ['a','ab','abc']
"a|ab|abc".split("\\|"); // The result is ['a','ab','abc']

summary

This article is a summary of your experience in Java development and can be shared for your reference.Hope to help you avoid treading holes and make your code more efficient and elegant.

More exciting articles, pay attention to [ToBeTopJavaer], and tens of thousands of excellent course resources for free!!!

Topics: Java Attribute