In Instructions for Practical Living and Other Neo-Confucian Writings, the greater Chinese statesman and philosopher Wang Yangming wrote the following words:
Lust grows day by day, like the dust on the floor. If you do not sweep the dust every day, it will accumulate. If you work hard, you will find that there is no end to the journey of life. The more you explore, the more there will be left to know. What is necessary is precision, clarity, and completeness.
Wang Yangming's wise words are still very much relevant to our daily lives today. Bad code, just like lust and dust, increases every day. If you do not constantly work to clean it, it will accumulate. But, if you work hard to clean bad code, you can improve your programming ability and make your code precise and clear, with no room for doubt. This article introduces three ways to improve your Java code based on the actual coding work of an Alibaba Cloud engineer, with bad code samples provided.
entrySet()
When the Primary Key and Value of Map Are UsedYou should iterate entrySet()
when the primary key and value are used. This is more efficient than iterating keySet()
and then getting the value.
Bad code:
Map<String, String> map = ...;
for (String key : map.keySet()) {
String value = map.get(key);
...
}
Good code:
Map<String, String> map = ...;
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
...
}
Collection.isEmpty()
to Detect Null ValuesCompared with Collection.size()
, Collection.isEmpty()
is much more readable and provides better performance when it comes to detecting null values. The time complexity of Collection.isEmpty()
is always O(1)
, but that of Collection.size()
may be O(n)
.
Bad code:
if (collection.size() == 0) {
...
}
Good code:
if (collection.isEmpty()) {
...
}
To detect null values, you can use CollectionUtils.isEmpty(collection)
and CollectionUtils.isNotEmpty(collection)
.
Passing a collection as a parameter to the collection itself is an error or meaningless code.
For methods that require unchanged parameters during execution, an error may occur when you pass a collection to itself.
Bad code:
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
if (list.containsAll(list)) { // 无意义,总是返回true
...
}
list.removeAll(list); // 性能差, 直接使用clear()
The collection class of Java is easy to use, but the collection size is limited in source code. The time complexity of each scaling operation may be O(n)
. You can specify the predictable collection size whenever possible to reduce the occurrences of collection scaling.
Bad code:
int[] arr = new int[]{1, 2, 3};
List<Integer> list = new ArrayList<>();
for (int i : arr) {
list.add(i);
}
Good code:
int[] arr = new int[]{1, 2, 3};
List<Integer> list = new ArrayList<>(arr.length);
for (int i : arr) {
list.add(i);
}
StringBuilder
In Java, concatenated strings are tuned during compilation. However, strings that are concatenated in a cycle are not concatenated during compilation. In this case, concatenate strings by using StringBuilder
.
Bad code:
String s = "";
for (int i = 0; i < 10; i++) {
s += i;
}
Good code:
String a = "a";
String b = "b";
String c = "c";
String s = a + b + c; // 没问题,java编译器会进行优化
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append(i); // 循环中,java编译器无法进行优化,所以要手动使用StringBuilder
}
Random access to arrays is more efficient than that to linked lists. When a called method needs to randomly access data in the acquired List
, without knowing whether an array or a linked list is internally implemented, you can check whether the RandomAccess
operation is used.
Good code:
// 调用别人的服务获取到list
List<Integer> list = otherService.getList();
if (list instanceof RandomAccess) {
// 内部数组实现,可以随机访问
System.out.println(list.get(list.size() - 1));
} else {
// 内部可能是链表实现,随机访问效率低
}
Collection.contains
MethodIn the collection class library of Java, the time complexity of the contains method for List
is O(n)
. If you need to frequently call the contains method in the code to search for data, you can convert List
into HashSet
to reduce the time complexity to O(1)
.
Bad code:
ArrayList<Integer> list = otherService.getList();
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
// 时间复杂度O(n)
list.contains(i);
}
Good code:
ArrayList<Integer> list = otherService.getList();
Set<Integer> set = new HashSet(list);
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
// 时间复杂度O(1)
set.contains(i);
}
L
" to Long Integer ConstantsAppend the uppercase letter L
to long integer constants. Do not use the lowercase l
, because it can easily be confused with the digit 1
.
Bad code:
long value = 1l;
long max = Math.max(1L, 5);
Good code:
long value = 1L;
long max = Math.max(1L, 5L);
Magic numbers may make your code very clear, but it will be difficult to debug. Therefore, magic numbers must be defined as readable constants. However, -1
, 0,
and 1
are not considered magic numbers.
Bad code:
for (int i = 0; i < 100; i++){
...
}
if (a == 100) {
...
}
Good code:
private static final int MAX_COUNT = 100;
for (int i = 0; i < MAX_COUNT; i++){
...
}
if (count == MAX_COUNT) {
...
}
Assign values to static member variables of the collection type by using static code blocks rather than collection implementations.
Bad code:
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");
}
};
Good code:
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");
};
try-with-resources
StatementJava 7 introduced the try-with-resources
statement, which is used to close related resources and makes program code simpler and more secure. It is better than the original try-catch-finally
statement.
Bad code:
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) {
...
}
}
}
}
Good code:
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 to make the code simpler and easier to maintain. You can recover deleted methods and fields from historical commits.
Bad code:
public class DoubleDemo1 {
private int unusedField = 100;
private void unusedMethod() {
...
}
public int sum(int a, int b) {
return a + b;
}
}
Good code:
public class DoubleDemo1 {
public int sum(int a, int b) {
return a + b;
}
}
Delete unused local variables to make the code simpler and easier to maintain.
Bad code:
public int sum(int a, int b) {
int c = 100;
return a + b;
}
Good code:
public int sum(int a, int b) {
return a + b;
}
Unused method parameters are misleading. Delete them to make the code simpler and easier to maintain. However, do not delete unused parameters for override methods that are defined based on the methods of parent classes or interface methods.
Bad code:
public int sum(int a, int b, int c) {
return a + b;
}
Good code:
public int sum(int a, int b) {
return a + b;
}
The redundant brackets of expressions are considered unnecessary by some coders but helpful for code reading by other coders. For Java experts, these redundant brackets only make the code look complex.
Bad code:
return (x);
return (x + 2);
int x = (y * 3) + 1;
int m = (n * 4 + 2);
Good code:
return x;
return x + 2;
int x = y * 3 + 1;
int m = n * 4 + 2;
The tool class is a collection of static fields and functions and must not be instantiated. In Java, an implicit public constructor is added to each class without constructor definition. If you are a Java novice, we recommend that you define an explicit private constructor to mask the implicit public constructor.
Bad code:
public class MathUtils {
public static final double PI = 3.1415926D;
public static int sum(int a, int b) {
return a + b;
}
}
Good code:
public class MathUtils {
public static final double PI = 3.1415926D;
private MathUtils() {}
public static int sum(int a, int b) {
return a + b;
}
}
If exceptions caught by using the catch statement are thrown without processing, the result is the same as not catching the exceptions. To solve this problem, you can delete the related code block or add another processing method.
Bad code:
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;
}
}
Good code:
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();
}
}
Though public static constants can be accessed through class instances, this may lead to the misunderstanding that the instances of each class have a public static constant. We recommend that you access public static constants through classes.
Bad code:
public class User {
public static final String CONST_NAME = "name";
...
}
User user = new User();
String nameKey = user.CONST_NAME;
Good code:
public class User {
public static final String CONST_NAME = "name";
...
}
String nameKey = User.CONST_NAME;
Prevent null pointer exceptions through coding (for example, no null values are detected) rather than through catching exceptions
Bad code:
public String getUserName(User user) {
try {
return user.getName();
} catch (NullPointerException e) {
return null;
}
}
Good code:
public String getUserName(User user) {
if (Objects.isNull(user)) {
return null;
}
return user.getName();
}
""+value
with String.valueOf(value)
Use String.valueOf(value)
rather than ""+value
to convert other objects or types into strings more efficiently.
Bad code:
int i = 1;
String s = "" + i;
Good code:
int i = 1;
String s = String.valueOf(i);
@Deprecated
Annotation to Outdated CodeIf a segment of code is outdated but cannot be deleted for compatibility reasons, you can add the @Deprecated
annotation to the code so that it will no longer be used. Add @deprecated
to document comments to give an explanation and provide an alternative solution.
Good code:
/**
* 保存
*
* @deprecated 此方法效率较低,请使用{@link newSave()}方法替换它
*/
@Deprecated
public void save(){
// do something
}
BigDecimal(double)
BigDecimal(double)
can cause accuracy losses and abnormal business logic during precise computation or value comparison.
Bad code:
BigDecimal value = new BigDecimal(0.1D); // 0.100000000000000005551115...
Good code:
BigDecimal value = BigDecimal.valueOf(0.1D);; // 0.1
To return null values, require the caller to detect null values. Otherwise, a null pointer exception may be thrown. Returning null arrays or collections can prevent null pointer exceptions from being thrown when the caller does not detect null values. To simplify the code, you can delete the statement that instructs the caller to detect null values.
Bad code:
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) {
...
}
}
}
Good code:
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) {
...
}
}
equals
Method by Using Constants or Determined ValuesThe equals
method for objects often throws null pointer exceptions. To solve this problem, call the equals method by using constants or objects with determined values. The best solution is to use the java.util.Objects.equals()
method.
Bad code:
public void isFinished(OrderStatus status) {
return status.equals(OrderStatus.FINISHED); // 可能抛空指针异常
}
Good code:
public void isFinished(OrderStatus status) {
return OrderStatus.FINISHED.equals(status);
}
public void isFinished(OrderStatus status) {
return Objects.equals(status, OrderStatus.FINISHED);
}
Enumeration is often used in the same way as constants. If enumeration contains public property fields or field setting methods, the properties of these enumerated constants are prone to modification. Ideally, enumerated property fields are private and assigned values in private constructors. We recommend that you add the final modifier due to the lack of the Setter
method.
Bad code:
public enum UserStatus {
DISABLED(0, "禁用"),
ENABLED(1, "启用");
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;
}
}
Good code:
public enum UserStatus {
DISABLED(0, "禁用"),
ENABLED(1, "启用");
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;
}
}
String.split(String regex)
The string-specific split method passes a separator string which is a regular expression. Some keywords, such as .[]() \|
, must be escaped.
Bad code:
"a.ab.abc".split("."); // 结果为[]
"a|ab|abc".split("|"); // 结果为["a", "|", "a", "b", "|", "a", "b", "c"]
Good code:
"a.ab.abc".split("\\."); // 结果为["a", "ab", "abc"]
"a|ab|abc".split("\\|"); // 结果为["a", "ab", "abc"]
And that's it. I hope that you also learned a thing or two from Wang Yangming's wise words. If nothing else, I hope that our Java coding guide helps you write more effective and elegant code.
Are you eager to know the latest tech trends in Alibaba Cloud? Hear it from our top experts in our newly launched series, Tech Show!
The Refactoring Principle and Why It Matters to Anyone Coding
208 posts | 12 followers
FollowAlibaba Clouder - March 11, 2021
Changyi - September 2, 2021
Alibaba Cloud Community - February 14, 2022
Changyi - February 16, 2020
Alibaba Clouder - May 24, 2019
Alibaba Clouder - August 20, 2020
208 posts | 12 followers
FollowAn on-demand database hosting service for MySQL with automated monitoring, backup and disaster recovery capabilities
Learn MoreAn on-demand database hosting service for PostgreSQL with automated monitoring, backup and disaster recovery capabilities
Learn MoreApsaraDB RDS for MariaDB supports multiple storage engines, including MySQL InnoDB to meet different user requirements.
Learn MoreAn on-demand database hosting service for SQL Server with automated monitoring, backup and disaster recovery capabilities
Learn MoreMore Posts by Alibaba Cloud Native