Writing high-quality code: 151 suggestions for improving Java programs (Chapter 1: common methods and guidelines for JAVA Development ___ recommendation 1 ~ 5), java151
The reasonable man adapts himself to the world; The unreasonable one persists in trying to adapt the world himself.
People who understand the truth adapt themselves to the world; people who do not know the truth want to adapt the world to themselves.
------- Bernard Shaw
This series of articles is used to record the Reading Notes of the book "Writing 151 suggestions for improving java programs with high quality code. For your convenience and convenience, I would like to thank Qin Xiaobo, author of the original book, for his unique insights on java and helping java enthusiasts grow. Due to the length of the article, I recorded and shared my reading notes in batches. There are 12 chapters in the book, and a total of 151 suggestions, 1 ~ Chapter 3 provides 51 suggestions for java syntax ~ Chapter 9 puts forward 80 suggestions for using JDK APIs ~ Chapter 12 provides 20 suggestions on program performance, open-source tools and frameworks, coding style and programming ideas. According to the directory structure of this book, I read this book step by step, which is recorded here.
I read this book for the first time a year and a half ago. I did not read it carefully, but I only learned some questions. At that time, I thought this book was okay. Now I will turn it out one year later, when you start reading the book again, you may find that understanding is different from the charm of your first reading. Therefore, we recommend that you read the book carefully and understand it carefully, the number of books I read is not used to go out and brag about. What books have I read? It took a short period of time ..... books are read to themselves and used to improve themselves. Therefore, you must be considerate, think-oriented, and learn to use them. Technical books are similar and the principle remains the same, so read a technical book carefully and read other books about such technology later. Your understanding will be more profound, I read a number of books about one aspect of technology quickly, but I still don't know why.
The world of JAVA is rich and colorful, but it is also full of Economic traps. If you accidentally fall into the dark abyss, only after learning about the rules can you fly in the ocean of technology. The journey of a thousand miles begins with a complete step. This chapter mainly describes the issues related to the JAVA language basics and the precautions for recommended solutions and variables, how to securely serialize and How to Use assertions;
Recommendation 1: do not contain confusing letters in constants and variables
The package names are all in lower Case, the first letter of the class name is all in upper Case, the constants are all separated by underscores, and the variables are named by Camel Case. These are the most basic Java coding specifications, it is a well-known rule for every Java er, but do not introduce confusing letters in the declaration of variables. Try to read the following code and think about the I of the printed result:
1 public class Demo {2 public static void main (String [] args) {3 test01 (); 4} 5 6 public static void test01 () {7 long I = 1l; 8 System. out. println ("twice of I:" + (I + I); 9} 10}
Some may say: Can Errors still occur in such a simple example? The running result must be 22! Practice is the only criterion for testing truth. Let's take a look at it. Maybe you may be surprised that the result is 2, not 22. Is there a problem with the compiler, but a "2" missing "?
Because the value assigned to the variable I is the number "1", but it is followed by the long integer variable's identifier letter "l. Let alone I dig a hole to let you jump. If a similar program appears in a project and you try to understand the author's thoughts by reading the code, this may happen. Therefore, to make your program easier to understand, do not mix the letter "l" (including uppercase letters "O") with numbers as much as possible, so as to avoid readers understanding and program intention deviation. If both letters and numbers are used, the letter "l" must be in uppercase, and the letter "O" is added with comments.
Note: the letter "l" must be capitalized when used as a long integer sign..
Recommendation 2: Do not convert constants into Variables
Changing a constant to a variable? How can I change the final and static constants? It is impossible to assign a value for this. Is it really impossible? Take a look at the following code:
1 import java. util. random; 2 3 public class Demo01 {4 public static void main (String [] args) {5 test02 (); 6} 7 8 public static void test02 () {9 System. out. println ("Constant changes:" + Constant. RAND_CONST); 10} 11} 12 13 interface Constant {14 public static final int RAND_CONST = new Random (). nextInt (); 15}
Is RAND_CONST a constant? Does the value change? Definitely changes! The definition of this constant is absolutely not desirable. A constant is a constant, and its value must be determined during the compilation period. It should not be changed during the runtime; otherwise, the program will be quite readable, even the author cannot determine what magic happened at runtime.
The handler is thinking about using the constant change function to implement serial number algorithm and Random Seed generation. Unless this is really the only solution in the project, it will be abandoned. constants are still used as constants.
Note: Make sure that the constant value remains unchanged during runtime.
Suggestion 3: the types of the ternary operators must be consistent.
The ternary operator is a simplified way of writing if-else. There are many places to use it in the project, and it is also very easy to use. However, the easy-to-use and simple things do not mean that they can be used at will. See the following code:
1 public static void test03 () {2 int I = 80; 3 String str = String. valueOf (I <100? 90: 100); 4 String str1 = String. valueOf (I <100? 90: 100.0); 5 System. out. println ("are the two equal:" + str. equals (str1); 6}
After analyzing this program, I is 80, less than 100, and the return values of the two must be 90, and then converted to the String type. The values are absolutely equal and beyond all doubt. Well, the analysis is a bit reasonable, but the second operand of the ternary operator in the variable str is 100, and the second operand in str1 is 100.0. Does it affect wood? It cannot be affected. The conditions of the ternary operators are true. Only the first value is returned. The second value has a wool relationship, which seems to make sense.
After running, the result is: "are the two equal: false", not equal, why?
The problem lies in the numbers 100 and 100.0. In the str variable, the first operand 90 and the second operand 100 of the ternary operator are of the int type, with the same type, the returned result is also 90 of the int type, while the first operand (90) of the variable str1 is int, and the second operand 100.0 is floating point, that is, the types of the two operands are inconsistent, the Trielement operator must return a data, and the data type must be determined. If the impossible condition is true, int type is returned. If the condition is false, float type is returned. This is not allowed by the compiler, so it will convert the int type to the floating point 90.0, that is, the return value of the ternary operator is the floating point 90.0, so of course it is not equal to the 90 of the integer. Why is the integer converted to the floating point type instead of the floating point type converted to the integer type? This involves the conversion rules of ternary operators:
If you know the reason, the corresponding solution is as follows: ensure that the two operands in the three element operator have the same type to avoid this error.
Recommendation 4: Avoid method overloading with Variable Length Parameters
In project and system development, to improve the flexibility and reusability of methods, we often need to pass uncertain numbers of parameters to methods, before Java 5, a common design technique is to define a form parameter as a Collection type, subclass type, or array type. The disadvantage of this method is that null parameters need to be determined and filtered, for example, a Collection or array with a real parameter of null and a length of 0. The variable length parameter (varags) introduced in Java 5 is used to better reuse the method, so that the method caller can "Freely" pass the number of real parameters, of course, variable-length parameters must follow certain rules. For example, variable-length parameters must be the last parameter in the method. A method cannot define multiple variable-length parameters. These basic rules must be kept in mind, however, even if you remember these rules, errors may still occur. See the following code:
1 public class Client {2 public static void main (String [] args) {3 Client client = new Client (); 4 // 499 off for goods of RMB 5 client. calPrice (499, 75); 6} 7 8 // calculate 9 public void calPrice (int price, int discount) {10 float knockdownPrice = price * discount/100366f; 11 System. out. println ("the price after simple discount is:" + formatCurrency (knockdownPrice); 12} 13 14 // 15 public void calPrice (int price, int... discounts) {16 float knockdownPrice = price; 17 for (int discount: discounts) {18 knockdownPrice = knockdownPrice * discount/100; 19} 20 System. out. println ("the price after the complex discount is:" + formatCurrency (knockdownPrice); 21} 22 23 public String formatCurrency (float price) {24 return NumberFormat. getCurrencyInstance (). format (price); 25} 26}
This is a simulation class for calculating commodity discounts, with two parameters of the calPrice method (the business logic of this method is: provide the original price and discount rate of the commodity, you can get the discount price of the commodity) is a simple Discount calculation method, which is often used in actual projects. This is a single discount method. The calPrice method with variable-length parameters is called a complicated Discount calculation method. Multiple discount overlay operations (the simulation class is relatively simple) are also often seen in reality, for example, if VIP members are given a discount again during the sales promotion period, or if the day is your birthday, you will receive a discount, that is, the discount in the conventional saying.
The business logic is clear. Let's take a closer look at these two methods. Are they heavy loads? Of course, the definition of the overload is: "The method name is the same, the parameter type or quantity is different", it is obvious that the two methods are overloaded. However, this overload is a bit special. The parameter category of calPrice (int price, int... discounts) covers the parameter category of calPrice (int price, int discount. The problem arises: Which method should be called to handle calPrice (499,75?
We know that the java compiler is very intelligent. during compilation, it determines the method to be called based on the method signature, for example, calPrice (499,75, 95, obviously 75 and 95 will be converted into an array containing two elements and passed to calPrice (int price, int... discounts), because only this method meets the real parameter type, this is easy to understand. But now we are facing the calPrice () call. This 75 can be compiled into either the int Type 75 or the int Array {75 }, that is, an array containing only one element. Which method should be called? The running result is: "The price after a simple discount is 374.25 ". It seems that the first method is called. Why does it call the first method instead of the second variable-length method? During compilation, java will first process the data according to the number and type of real parameters (the two real parameters here are all int type, note that they are not converted to an int array, that is, find the calPrice (int price, int discount) method and check whether it meets the method signature conditions. The question now is, why does the compiler first find a method based on two real arguments of the int type instead of one of the int type and one of the real arguments of the int array type?
Because int is a native data type, and array is an object, the compiler wants to "get lazy", so it starts from the simplest "conjecture ", this problem occurs as long as the compilation conditions are met.
The problem is clearly explained. In order to make our programs understandable to humansCareful consideration of Variable Length Parameter Method OverloadingOtherwise, you may be stuck in these traps one day.
Recommendation 5: do not threaten the variable length method with null or null values.
We recommend that you reload variable length parameters. We recommend that you continue with the reload of variable length parameters. The previous example shows that the range of variable length parameters covers the range of non-variable length parameters, the two methods in this discussion are variable-length parameters. The Code is as follows:
1 public class Client5 { 2 3 public void methodA(String str, Integer... is) { 4 5 } 6 7 public void methodA(String str, String... strs) { 8 9 }10 11 public static void main(String[] args) {12 Client5 client5 = new Client5();13 client5.methodA("china", 0);14 client5.methodA("china", "people");15 client5.methodA("china");16 client5.methodA("china", null);17 }18 }
Both methods are overloaded. The current problem is: client5.methodA ("china"); client5.methodA ("china", null); The compilation fails, and the prompt is the same: the method is ambiguous, the compiler does not know which method to call, but the responses of the two codes are different.
For the methodA ("china") method, according to the real parameter "china" (String type), both methods comply with the form parameter format. The Compiler does not know which method to call, so an error is returned. Let's take a look at this problem: Client5 is a complex business logic and provides two overload methods for calling from other modules (local calls within the system or remote calls outside the system) the caller can call a variable-length parameter according to the variable-length parameter specification. The number of parameters passed in can be N (N> = 0). Of course, you can write the client5.methodA ("china") method! It is in full compliance with the specifications, but this makes the compiler and callers depressed, and the program does not run in compliance with the rules. Who is responsible for this problem? He is a Client5 class designer and violates the KISS Principle (Keep it Smile, Stupid, that is, the lazy principle). According to this design method, he should be able to call it, however, the compilation fails while following the rules. This should be prohibited for designers and developers.
For Client5.methodA ("China", null), a direct amount of null is of no type. Although both methods meet the call requirements, but do not know which method to call, an error is returned. After careful analysis, in addition to not complying with the preceding lazy principle, there is also a very bad coding habit, that is, the caller hides the real parameter type, which is very dangerous, not only does the caller need to "Guess which method to call", but the caller may also cause internal logic confusion. In this example, modify the settings as follows:
1 public static void main(String[] args) {2 Client5 client5 = new Client5();3 String strs[] = null;4 client5.methodA("china", strs);5 }
That is to say, let the compiler know that the null value is of the String type, and the compilation can be successful, which reduces the occurrence of errors.