持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第14天,点击查看活动详情
BigDecimal常见bug
1. 精度问题
后端计算BigDecimal后,未指定精度导致前端显示问题,所以后端在计算BigDecimal的时候如果是带小数的计算,一定要加上精度,设置Scale
2. 精度舍入问题
精度设置后如果不指定舍入方式,会直接报异常.生产上见过一个计算的案子由于没有指定舍入方式,导致线上执行到这段代码的时候异常了,导致业务中断.而且由于此计算满足的if条件情况很少,所以一直没有发现这个bug 直到用户报事的时候才发现是因为精度舍入导致的.
正确的使用方式
3. 构造BigDecimal对象时NPE异常
由于在构造BigDecimal对象的时候,没有对构造函数的参数进行非空校验导致NPE异常. 生产上有根据某个参数计算税费的逻辑,但是由于没有取到税率参数从而出现NPE导致业务中断
4. 比较方式不对
选择了错误的比较方式,导致逻辑判断有误. BigDecimal缓存导致的有些时候==是true,有些时候是false,此问题中Integer的原理一样
所以BigDecimal的比较大小用compareTo
== 与 equals区别
== 的意思是比较的两个字符串指向的是JVM中的同一个字符串,即内存地址相同。
equals是比较的两个字符串的内容是否一样,在JVM中可能是不同的字符串。
题外话
说到异常,提一下异常的打印为什么生产上不让使用e.printStackTrace()
-
占用内存 e.printStackTrace()输出的信息是个字符串,会占用字符串常量池的内存空间.关于字符串常量池的也是一个比较难以理解的常考点,有兴趣的可以在网上找下子牙老师关于字符串常量池的介绍.
-
性能问题 e.printStackTrace()跟System.out.print()一样都是会有加锁的逻辑的
private void printStackTrace(PrintStreamOrWriter s) {
// Guard against malicious overrides of Throwable.equals by
// using a Set with identity equality semantics.
Set<Throwable> dejaVu =
Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
dejaVu.add(this);
synchronized (s.lock()) {
// Print our stack trace
s.println(this);
StackTraceElement[] trace = getOurStackTrace();
for (StackTraceElement traceElement : trace)
s.println("\tat " + traceElement);
// Print suppressed exceptions, if any
for (Throwable se : getSuppressed())
se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
// Print cause, if any
Throwable ourCause = getCause();
if (ourCause != null)
ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
}
}
- 日志格式导致的易观性
使用logback、log4j可以根据实际业务情况选择性的输入日志级别,便于日志的管理及展示