关于node.js:90的Java开发人员都会犯的5个错误

40次阅读

共计 2829 个字符,预计需要花费 8 分钟才能阅读完成。

前言
作为一名 java 开发程序员,不晓得大家有没有遇到过一些匪夷所思的 bug。这些谬误通常须要您几个小时能力解决。当你找到它们的时候,你可能会默默地骂本人是个傻瓜。是的,这些可笑的 bug 基本上都是你疏忽了一些基础知识造成的。其实都是很低级的谬误。明天,我总结一些常见的编码谬误,而后给出解决方案。心愿大家在日常编码中可能防止这样的问题。

  1. 应用 Objects.equals 比拟对象
    这种办法置信大家并不生疏,甚至很多人都常常应用。是 JDK7 提供的一种办法,能够疾速实现对象的比拟,无效防止烦人的空指针查看。然而这种办法很容易用错,例如:
    Long longValue = 123L;
    System.out.println(longValue==123); //true
    System.out.println(Objects.equals(longValue,123)); //false
    复制代码
    为什么替换 == 为 Objects.equals()会导致不同的后果?这是因为应用 == 编译器会失去封装类型对应的根本数据类型 longValue,而后与这个根本数据类型进行比拟,相当于编译器会主动将常量转换为比拟根本数据类型, 而不是包装类型。
    应用该 Objects.equals()办法后,编译器默认常量的根本数据类型为 int。上面是源码 Objects.equals(),其中 a.equals(b)应用的是 Long.equals()会判断对象类型,因为编译器曾经认为常量是 int 类型,所以比拟后果肯定是 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;

}
复制代码
晓得了起因,解决办法就很简略了。间接申明常量的数据类型,如 Objects.equals(longValue,123L)。其实如果逻辑紧密,就不会呈现下面的问题。咱们须要做的是保持良好的编码习惯。

  1. 日期格局谬误
    在咱们日常的开发中,常常须要对日期进行格式化,然而很多人应用的格局不对,导致呈现意想不到的状况。请看上面的例子。
    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。为什么?这是因为 java 的 DateTimeFormatter 模式 YYYY 和 yyyy 之间存在轻微的差别。它们都代表一年,然而 yyyy 代表日历年,而 YYYY 代表星期。这是一个轻微的差别,仅会导致一年左右的变更问题,因而您的代码本能够始终失常运行,而仅在新的一年中引发问题。12 月 31 日按周计算的年份是 2022 年,正确的形式应该是应用 yyyy-MM-dd 格式化日期。
    这个 bug 特地荫蔽。这在平时不会有问题。它只会在新的一年到来时触发。我公司就因为这个 bug 造成了生产事变。
  2. 在 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 获取用户信息的时候,很可能会误获取到他人的信息。您能够应用会话来解决这个问题。

  1. 应用 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
复制代码
仔细的读者应该曾经猜到失败的起因了。HashSet 应用 hashcode 对哈希表进行寻址,应用 equals 办法判断对象是否相等。如果自定义对象没有重写 hashcode 办法和 equals 办法,则默认应用父对象的 hashcode 办法和 equals 办法。所以 HashSet 会认为这是两个不同的对象,所以导致去重失败。

  1. 线程池中的异样被吃掉
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    executorService.submit(()->{
    //do something
    double result = 10/0;
    });
    复制代码
    下面的代码模仿了一个线程池抛出异样的场景。咱们真正的业务代码要解决各种可能呈现的状况,所以很有可能因为某些特定的起因而触发 RuntimeException。
    然而如果没有非凡解决,这个异样就会被线程池吃掉。这样就会导出呈现问题你都不晓得,这是很重大的结果。因而,最好在线程池中 try catch 捕捉异样。
    总结
    本文总结了在开发过程中很容易犯的 5 个谬误,心愿大家养成良好的编码习惯。

正文完
 0