I recently read the "151 suggestions for writing high-quality code to improve Jaav programs" by Qin Xiaobo. If it is 151 suggestions, it is more appropriate to avoid some unpopular pits of Java. The following 20 are more interesting. The suggestion to learn again.
The types of ternary operators must be consistent
Ternary operator operation is also called ternary operation. Its expression is like: "conditional expression? Expression 1: Expression 2". There are such ternary operators in most languages, and their purpose is to Simplify if-else, execute expression 1 when the conditional expression is true, otherwise execute expression 2. Let's analyze the following code:
public static void main(String[] args){
int i = 80;
String s = String.valueOf(i < 100 ? 80 : 100);
String s1 = String.valueOf(i < 100 ? 80 : 100.0);
boolean equals = s.equals(s1);
// 两者是否相等:false, 字符串s的值:80, 字符串s1的值:80.0
System.out.println("两者是否相等:" + equals);
System.out.println("字符串s的值:" + s);
System.out.println("字符串s1的值:" + s1);
}
Description : If the types of ternary operators are inconsistent, the returned results are also inconsistent.
Avoid overloading methods with variable length parameters
public class Client {
private static final Logger log = LoggerFactory.getLogger(Client.class);
public static void main(String[] args) {
Client client = new Client();
client.calPrice(5000, 80);
}
/**
* calPrice 简单折扣计算
*
* @param price 价格
* @param discount 折扣
* @description
* @author luokangyuan
* @date 2019-4-2 14:58
* @version 1.0.0
*/
private void calPrice(int price, int discount) {
float knockdownPrice = price * discount / 100.0F;
log.info("简单的折扣后的价格:{}", knockdownPrice);
}
/**
* calPrice
*
* @param price 价格
* @param discounts 折扣
* @description 复杂折扣计算
* @author luokangyuan
* @date 2019-4-2 15:08
* @version 1.0.0
*/
private void calPrice(int price, int... discounts) {
float knockdownPrice = price;
for (int discount : discounts) {
knockdownPrice = knockdownPrice * discount / 100;
}
log.info("复杂折扣后的价格:{}", knockdownPrice);
}
}
Description : Method overloading means that the method name is the same, and the parameter types or number of parameters are different. In the above example, the Java
editor will find a suitable method based on the method signature. The above test calls are simple discount calculations, not complicated Discount calculation.
Don't just replace one class
public class Constant{
public final static int MAX_AGE = 150;
}
public class Client{
public static void main(String[] args){
System.out.println("人类寿命极限是:" + Constant.MAX_AGE);
}
}
For the final modified basic type and String type, the compiler will consider it to be stable (Immutable Status), so the value is directly compiled into the bytecode at compile time, avoiding reference at runtime (Run-time Reference ) To improve the efficiency of code execution. For our example, the Client class is written with "150" in the bytecode at compile time, this constant, not an address reference, so no matter how you modify the constant class later, as long as you don't recompile the Client class, the output Still business as usual.
For a final modified class (that is, a non-basic type), the compiler will think it is not a stable state (Mutable Status), and a reference relationship is established at compile time (this type is also called Soft Final). If the constant introduced by the Client class is a class or instance, the latest value will be output without recompiling in time.
Use even judgment, not odd judgment
String s = n % 2 == 1 ? "奇数" : "偶数";
String s1 = n % 2 == 0 ? "偶数" : "奇数";
Description : Usually use the second type of even number judgment, and use the first type. -1
will also be judged as an even number.
Handling currency with integer types
// 0.40000000000000036
System.out.println(10.00 - 9.60);
explains : Floating-point numbers in Java are not accurate, and there will be problems with using floating-point numbers in currency processing. Therefore, use BigDecimal
, the class to perform calculations, or use integers to magnify the number to be calculated by 100 times, after the calculation Shrinking.
1. Use BigDecimal
BigDecimal
is a class designed to make up for the inaccurate calculation of floating-point numbers, and it also provides common mathematical algorithms for addition, subtraction, multiplication, and division. Especially when mapping with the database Decimal type field, BigDecimal is the best solution.
2. Use integer
Expand the value involved in the calculation by 100 times, convert it to an integer, and then reduce it by 100 times when it is displayed. The advantage of this processing is that the calculation is simple and accurate, and it is generally used in non-financial industries (such as the retail industry). This method is also used in some retail POS machines, their input and output are all integers, so the calculation is simpler.
Use String to assign directly
public static void main(String[] args) {
String str1 = "China";
String str2 = "China";
String str3 = new String("China");
String str4 = str3.intern();
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // false
System.out.println(str1 == str4); // true
}
description : It is recommended to use String str1 = "China";
to assign values to strings instead of new String("China");
. In Java, the defined constants will be stored in a constant pool. If the pool exists, it will not be redefined, so str1 == str2
returns true
. new
out an object, not to check whether the string constant pool exist, so str1 == str3
different references, return false
. After intern()
processed by 061723049e5699, it returns true
because intern()
will go to the object constant pool to check whether there are literally the same referenced objects.
The list generated by asList cannot be modified
private static void arraysTest() {
String[] week = {"Mon", "Tue", "Wed", "Thu"};
List<String> strings = Arrays.asList(week);
strings.add("Fri");
}
Description : Run an error, the list generated by asList cannot be modified.
Don't let null and empty values threaten the variable length method
public void countSum(String type, Integer... is){}
public void countSum(String type, String... strs){}
public static void main(String[] args) {
ClientReload clientReload = new ClientReload();
clientReload.countSum("China", 0);
clientReload.countSum("China", "People");
// 编译报错
clientReload.countSum("China");
// 编译报错
clientReload.countSum("China", null);
}
Description : It is also an overloaded method with variable length parameters. If you use NULL
or a null value for external calls, you will encounter a compilation failure error. This should be NULL
and the null value. In the above overloaded method, the parameters are all satisfied. Condition, so the compiler doesn’t know what method to KISS
principle is violated in the design of overloaded method. At the same time, when calling externally, the external calling hides the type of the actual parameter. If the calling code is modified as follows, it won’t There is a compilation error.
String strs = null;
clientReload.countSum("China", strs);
Watch out for the trap of self-increasing
public static void main(String[] args) {
int count = 0;
for (int i = 0; i < 100; i++) {
int i1 = count++;
count = i1;
System.out.println("每次count++的值:" + i1);
}
System.out.println(count);
}
shows that : The result is 0
instead of our 100
, which is count++
is an expression, and what is returned is the value of count
break not to be forgotten
public static void main(String[] args) {
String s = toChineseNumber(2);
log.info("转换结果:{}", s);
}
private static String toChineseNumber(int n) {
String chineseNumber = "";
switch (n) {
case 0 : chineseNumber = "零";
case 1 : chineseNumber = "壹";
case 2 : chineseNumber = "贰";
case 3 : chineseNumber = "叁";
case 4 : chineseNumber = "肆";
case 5 : chineseNumber = "伍";
case 6 : chineseNumber = "陆";
case 7 : chineseNumber = "柒";
case 8 : chineseNumber = "捌";
case 9 : chineseNumber = "玖";
case 10 : chineseNumber = "拾";
}
return chineseNumber;
}
Description : In switch
in break
must not be less.
Don't let the type switch silently
/** 光速*/
private static final int LIGHT_SPEED = 30 * 10000 * 1000;
public static void main(String[] args) {
long dis = LIGHT_SPEED * 60 * 8;
// -2028888064
System.out.println(dis);
}
description: LIGHT_SPEED * 60 * 8
calculated as int
type, there may be an out-of-bounds problem, although we have written the conversion to Long
in the code, but in Java, the type conversion is performed after the calculation LIGHT_SPEED * 60 * 8
int
type, beyond the length, starting from the beginning, so it is a negative value, modify it to the displayed definition type. as follows:
/** 光速*/
private static final long LIGHT_SPEED = 30L * 10000 * 1000;
public static void main(String[] args) {
long dis = LIGHT_SPEED * 60 * 8;
System.out.println(dis);
}
Avoid overloading methods with variable length parameters
public class MainTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(PriceTool.calPrice(12, 1)); // 1
}
}
class PriceTool {
public static int calPrice(int price, int discount) {
return 1;
}
public static int calPrice(int price, int... discount) {
return 2;
}
}
Description : The compiler will start guessing from the simplest, as long as it meets the compilation conditions, it will be used.
Use less static imports
import static java.lang.Math.PI;
public double calCircleArea(double r) {
return Math.PI * r * r;
}
public double calBallArea (double r) {
return 4 * PI * r * r;
}
Description : Static import can reduce the amount of code, but it is not easy to read and poor readability.
Beware of the null value of the packaging type
public static int f(List<Integer> list){
int count = 0;
for (Integer i : list){
count += (i != null) ? i : 0;
}
return count;
}
Description : Packaging objects and unboxing objects can be freely converted, which is not false, but null values must be removed, and null values cannot be converted to basic types. Regarding this question, we should keep in mind one thing: When the packaging type participates in the operation, it needs to check the null value.
Be careful about the size comparison of packaging types
for example. i==j false
. Integer is a reference type.
public static void main(String[] args){
Integer i = new Integer(100);
Integer j = new Integer(100);
System.out.println(i == j);
}
Avoid unexpected results of instanceof
Instanceof is a simple binary operator. It is used to determine whether an object is a class instance. The operators on both sides need to have inheritance or implementation relationships.
public static void main(String[] args) {
// String对象是否是Object的实例 - true,"String"是要给字符串,字符串继承了Object,当然是Object的实例。
boolean b1 = "String" instanceof Object;
// String对象是否是String类的实例 - true,一个类的对象当然是一个类的实例。
boolean b2 = new String() instanceof String;
// Object对象是否是String的实例,编译报错,Object是父类。
boolean b3 = new Object() instanceof String;
// 拆箱类型是否是装箱类型的实例,编译报错,“A”是一个Char型,是一个基本类型,instanceof只能用于对象判断。
boolean b4 = "A" instanceof Character;
// 空对象是否是String的实例 - false,instanceof的规则,左边为null,无论右边什么类型,都返回false。
boolean b5 = null instanceof String;
// 类型转换后的空对象是否是String的实例 - false,null可以说是没有类型,类型转换后还是null。
boolean b6 = (String) null instanceof String;
// Date对象是否是String的实例,编译报错,Date类和String类没有继承关系
boolean b7 = new Date() instanceof String;
}
Don't randomly set random number seeds
In Java, the generation of random numbers depends on the seed. The relationship between the random number and the seed follows the following two principles: If the seed is different, different random numbers are generated; if the seed is the same, the same random number will be generated even if the instance is different.
public static void main(String[] args)
{
Random r = new Random();
for (int i = 1; i < 4; i++)
{
System.out.println("第" + i + "次:" + r.nextInt());
}
}
运行结果:
第1次:846339168
第2次:756051503
第3次:1696875906
After the program is started, the random number generated will be different. But every time the program is started, three random numbers are generated. The relationship between random number generation and seed is as follows:
1) Different seeds produce different random numbers.
2) If the seed is the same, the same random number will be generated even if the instance is different.
The default seed of Random (non-parameter construction) is System.nanoTime()
(jdk1.5 used to be System.currentTimeMillis()). This value is the number of nanoseconds from a fixed point in time. Different operating systems and hardware have different At a fixed point in time, the random number is naturally different.
Avoid initializing other classes in the constructor
public class Client35 {
public static void main(String[] args) {
Son son = new Son();
son.doSomething();
}
}
// 父类
class Father {
public Father() {
new Other();
}
}
// 相关类
class Other {
public Other() {
new Son();
}
}
// 子类
class Son extends Father {
public void doSomething() {
System.out.println("Hi, show me Something!");
}
}
Description : cause the construction method to be called cyclically.
Integer pool is preferred
Integer caches Integer objects of -128-127. So the object obtained by boxing (Integer.valueOf()) can be reused.
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Performance considerations, the preferred array
private static int getSumForArray(int[] array) {
int sum = 0;
for (int i = 0; i < array.length; i++) {
sum += array[i];
}
return sum;
}
private static int getSumForList(List<Integer> list) {
return list.stream().mapToInt(Integer::intValue).sum();
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。