Java程序员易踩的坑及解析

开发 前端
我们小伙伴会说了,Java不是中为了节省内存和提高性能,会对一定范围内的Integer对象进行缓存。范围默认是在 -128 到 127 之间,怎么没有生效?

作为Java程序员,在日常开发中经常会遇到一些低级错误或者难以理解的情况。以下2个常见的问题,涉及到Java的基础知识,这2个基础知识小坑90%以上的程序员都踩过

1. ==号比较的坑

在比较Integer类型的对象时,一些程序员小伙伴可能会使用==来判断它们是否相等。然而,这种用法并不总是正确的。例如,对于Integer对象,==比较的是对象的引用而非值,因此结果可能出乎意料。我们应该养成使用equals()方法来判断两个Integer对象是否相等的良好习惯

Integer status1 = new Integer(1);
Integer status2 = new Integer(1);
System.out.println(status1 == status2);

思考:返回结果是什么?

答案:false

我们小伙伴会说了,Java不是中为了节省内存和提高性能,会对一定范围内的Integer对象进行缓存。范围默认是在 -128 到 127 之间,怎么没有生效?

我们来看一下Integer构造方法

public Integer(int value) {
    this.value = value;
}

发现在Integer构造方法中并没有使用缓存

思考:Integer缓存在哪里使用?

在Integer类的valueOf方法中

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

如果将代码修改为如下:

Integer status1 = 1;
  Integer status2 = 1;

  System.out.println(status1 == status2);

思考:返回结果是什么?

答案:true

特别说明: Integer status1 = 1 会默认转换为Integer status1 = Integer.valueOf(1)

编码要养成良好习惯,尽量少用==判断两个Integer类型数据是否相等,而应该改成使用equals方法判断:

Integer status1 = new Integer(1);
Integer status2 = new Integer(1);
System.out.println(status1.equals(status2));

输出结果true

2. BigDecimal的坑

在一些业务场景(比如:仓库数量,金额)需要设置成小数,此时字段类型应该定义成BigDecimal,而不是Double,避免丢失精度问题

Double amount1 = 0.02;
  Double amount2 = 0.03;
  System.out.println(amount2 - amount1);

思考:输出结果会是0.1?

答案:不是输出结果如下:

0.009999999999999998

原因如下:Double类型的两个参数相减会转换成二进制,Double有效位数为16位这就会出现存储小数位数不够的情况,这种情况下就会出现误差

将上面代码进行优化

BigDecimal amount1 = new BigDecimal(0.02);
BigDecimal amount2 = new BigDecimal(0.03);
System.out.println(amount2.subtract(amount1));

思考:结果会是0.1?不是的,输出结果如下:

0.0099999999999999984734433411404097569175064563751220703125

思考:BigDecimal为啥还是丢失精度?

查看BigDecimal构造方法,注释说明如下

/**
 * 将 a double 转换为 a BigDecimal ,它是 的二进制浮点值的精确十进制表示 double形式。返回 BigDecimal 的小数位数是最小值,因此 (10scale × val) 是整数。
 * 笔记:
 * 此构造函数的结果可能有些不可预测。人们可能会假设用 Java 编写 new BigDecimal(0.1) 会创建一个 BigDecimal 完全等于 0.1(未缩放值为 1,小数位数为 1),但实际上它等于 0.1000000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能完全表示为 a double (或者,就此而言,不能表示为任何有限长度的二进制分数)。因此,传递 给 构造函数的值并不完全等于 0.1,尽管外观如此。
 * String另一方面,构造函数是完全可预测的:正如人们所期望的那样,写入new BigDecimal("0.1")会创建一个BigDecimal完全等于 0.1 的构造函数。因此,通常建议优先使用 String 构造函数而不是此构造函数。
 * 当 必须将 a double 用作 的源BigDecimal时,请注意,此构造函数提供精确的转换;它不会给出与使用Double.toString(double)方法然后使用BigDecimal(String)构造函数将 转换为 double a String 相同的结果。若要获得该结果,请使用该staticvalueOf(double)方法。
 * 参数:
 * val – double 要转换为 BigDecimal的值。
 * 抛出:
 * NumberFormatException – 如果 val 是无限或 NaN。
         */
public BigDecimal(double val) {
    this(val,MathContext.UNLIMITED);
}

通过构造函数说明发现,使用BigDecimal构造函数初始化对象,也会丢失精度

思考:BigDecimal如何才能不丢失精度呢?

BigDecimal amount3 = new BigDecimal(String.valueOf(0.02));
  BigDecimal amount4 = new BigDecimal(String.valueOf(0.03));
  System.out.println(amount4.subtract(amount3));

使用BigDecimal.valueOf方法初始化BigDecimal类型参数,也能保证精度不丢失。在新版的阿里巴巴开发手册中,也推荐使用这种方式创建BigDecimal参数。

BigDecimal amount1 =  BigDecimal.valueOf(0.02);
  BigDecimal amount2 =   BigDecimal.valueOf(0.03);
  System.out.println(amount2.subtract(amount1));
责任编辑:武晓燕 来源: springboot葵花宝典
相关推荐

2022-07-15 08:20:54

Java基础知识

2018-02-06 08:36:02

简历程序员面试

2020-05-06 11:33:49

程序员技能求职

2015-09-16 09:57:41

swoolePHP程序员

2017-11-28 14:15:38

开发者故事

2014-08-13 11:11:58

程序员

2018-05-31 15:22:53

程序员女程序男性程序员

2015-08-18 15:22:59

程序员成长阶段

2012-11-08 09:49:30

C++Java程序员

2020-08-11 07:31:39

JavaVolatile模型

2020-01-12 19:10:30

Java程序员数据

2022-09-25 21:58:27

程序员

2013-08-20 09:33:59

程序员

2014-07-29 10:30:16

JavaJava程序员

2012-11-02 13:47:31

Java程序员编程

2021-07-28 14:37:57

WKWebviewh5网络

2021-10-18 21:41:10

Go程序员 Defer

2011-07-07 14:47:15

PHP

2011-05-13 14:34:02

程序员

2021-09-29 09:07:22

Docker 日志容器
点赞
收藏

51CTO技术栈公众号