头图

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();
}

初念初恋
175 声望17 粉丝