5 Mistakes 90% of Java Developers Make

If this article is helpful to you, please save the child, you can vote a lot , the voting channel  , thank you very much~~

foreword

As a java development programmer, I don't know if you have encountered some incredible bugs. These errors usually take you hours to resolve. When you find them, you may silently call yourself a fool. Yes, these ridiculous bugs are basically caused by you ignoring some basic knowledge. In fact, they are all very low-level mistakes. Today, I summarize some common coding mistakes, and then give solutions. I hope you can avoid such problems in your daily coding.

1. Using Objects.equals to compare objects

This method is believed to be familiar to everyone, and even many people often use it. It is a method provided by JDK7, which can quickly realize the comparison of objects and effectively avoid annoying null pointer checks. But this method is easy to use wrongly, for example:

Long longValue = 123L;
System.out.println(longValue==123); //true
System.out.println(Objects.equals(longValue,123)); //false
复制代码

Why does replacing ==with Objects.equals()result in a different result? This is because using the ==compiler will get the basic data type corresponding to the package type longValue, and then compare with this basic data type, which means that the compiler will automatically convert the constant to the comparison basic data type instead of the package type.

After using this Objects.equals()method, the basic data type of the compiler default constant is int. The following is the source code Objects.equals(), which a.equals(b)uses the Long.equals()object type to be judged, because the compiler has already considered the constant to be a inttype, so the comparison result must be false.

public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}
    
public boolean equals(Object obj) {
    if (obj instanceof Long) {
        return value == ((Long)obj).longValue();
    }
    return false;
}
复制代码

Knowing the reason, the solution is simple. Directly declare the data type of the constant, eg Objects.equals(longValue,123L). In fact, if the logic is strict, the above problems will not arise. What we need to do is to maintain good coding habits.

2. Wrong date format

In our daily development, we often need to format the date, but many people use the wrong format, which leads to unexpected situations. Please see the example below.

Instant instant = Instant.parse("2021-12-31T00:00:00.00Z");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss")
.withZone(ZoneId.systemDefault());
System.out.println(formatter.format(instant));//2022-12-31 08:00:00
复制代码

以上用于YYYY-MM-dd格式化, 年从2021 变成了 2022。为什么?这是因为 javaDateTimeFormatter 模式YYYYyyyy之间存在细微的差异。它们都代表一年,但是yyyy代表日历年,而YYYY代表星期。这是一个细微的差异,仅会导致一年左右的变更问题,因此您的代码本可以一直正常运行,而仅在新的一年中引发问题。12月31日按周计算的年份是2022年,正确的方式应该是使用yyyy-MM-dd格式化日期。

这个bug特别隐蔽。这在平时不会有问题。它只会在新的一年到来时触发。我公司就因为这个bug造成了生产事故。

3. 在 ThreadPool 中使用 ThreadLocal

如果创建一个ThreadLocal 变量,访问该变量的线程将创建一个线程局部变量。合理使用ThreadLocal可以避免线程安全问题。

但是,如果在线程池中使用ThreadLocal ,就要小心了。您的代码可能会产生意想不到的结果。举个很简单的例子,假设我们有一个电商平台,用户购买商品后需要发邮件确认。

private ThreadLocal<User> currentUser = ThreadLocal.withInitial(() -> null);

private ExecutorService executorService = Executors.newFixedThreadPool(4);

public void executor() {
    executorService.submit(()->{
        User user = currentUser.get();
        Integer userId = user.getId();
        sendEmail(userId);
    });
}
复制代码

如果我们使用ThreadLocal来保存用户信息,这里就会有一个隐藏的bug。因为使用了线程池,线程是可以复用的,所以在使用ThreadLocal获取用户信息的时候,很可能会误获取到别人的信息。您可以使用会话来解决这个问题。

4. 使用HashSet去除重复数据

在编码的时候,我们经常会有去重的需求。一想到去重,很多人首先想到的就是用HashSet去重。但是,不小心使用 HashSet 可能会导致去重失败。

User user1 = new User();
user1.setUsername("test");

User user2 = new User();
user2.setUsername("test");

List<User> users = Arrays.asList(user1, user2);
HashSet<User> sets = new HashSet<>(users);
System.out.println(sets.size());// the size is 2
复制代码

Careful readers should have already guessed the reason for the failure. HashSetUse hashcodeto address the hash table, use the equalsmethod to determine whether the objects are equal. If the custom object has no overridden method and equals method, the methods and methods hashcodeof the parent object are used by default . So it will be considered that these are two different objects, so the deduplication fails.hashcodeequalsHashSet

5. The exception in the thread pool is eaten

ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.submit(()->{
    //do something
    double result = 10/0;
});
复制代码

The above code simulates a scenario where a thread pool throws an exception. Our real business code has to deal with various possible situations, so it is very likely to be triggered for some specific reasons RuntimeException.

But if there is no special handling, this exception will be eaten by the thread pool. This will lead to problems that you don't even know about, which is a very serious consequence. try catchTherefore, it is better to catch exceptions in the thread pool .

Summarize

This article summarizes 5 mistakes that are easy to make during the development process. I hope everyone can develop good coding habits.

If this article is helpful to you, please save the child, you can vote a lot , the voting channel  , thank you very much~~

Guess you like

Origin juejin.im/post/7182184496517611576