前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >掉进JDK的坑,有理真的说不清......

掉进JDK的坑,有理真的说不清......

作者头像
一个正经的程序员
发布2022-04-11 09:13:29
3940
发布2022-04-11 09:13:29
举报
文章被收录于专栏:一个正经的程序员

前言

JDK 作为我们每天必备的调用类库,里面大量提供了基础类供我们使用。可以说离开 JDK ,我们的 Java代码寸步难行。

JDK 带给我们的便利可谓是不胜枚举,但同时这些方法在使用起来也存在一些坑,如果不注意就很容易掉入到陷阱里面,导致程序抛出错误。

1、String.valueOf()

代码语言:javascript
复制
public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

注意:这里返回了一个 "null" 的字符串,而不是 null。这两个是有很大区别的。当进行非空判断的时候,返回的是 true。也就是这个 "null" 字符串是符合判空条件的!

正确的姿势是在 String.valueOf 方法前必须判空:

代码语言:javascript
复制
Object obj= null;
// 判空
if(obj != null) {
    String str= String.valueOf(obj);
}

2、Integer.parseInt()

Integer.parseInt() 方法用于将字符串转化为 Integer 类型的方法。此方法的适用性就显得比较窄,因为是 String 类型的参数没有任何限定,当在传入一些比如 20.0、20L、30d、40f 这类数据的情况下会抛出异常。

代码语言:javascript
复制
String input = "20.0";
int out = Integer.parseInt(input);

会抛出异常 NumberFormatException:

代码语言:javascript
复制
Exception in thread "main" java.lang.NumberFormatException: For input string: "20.0"
  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
  at java.lang.Integer.parseInt(Integer.java:580)
  at java.lang.Integer.parseInt(Integer.java:615)

所以对于数字,最好可以用 BigDecimal 进行转换!

3、BigDecimal 的除法 divide()

众所周知,BigDecimal 是处理金额最有效的数据类型。一般进行财务报表计算的时候为了防止金额出现错误,一般情况下都会采用 BigDecimal。而 double、float 都会存在些许的误差。

常见的除法用起来没有任何丝毫的问题,妥妥的没毛病。

你开开心心地用 BigDecimal 进行了计算,而最终的结果返回却有问题。

代码语言:javascript
复制
public static void main(String[] args) throws Exception {
    BigDecimal ten = new BigDecimal(10);
    BigDecimal three= new BigDecimal(3);
    BigDecimal result = ten.divide(three);
    System.out.println(result.toString());
}

执行结果报错:

代码语言:javascript
复制
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
  at java.math.BigDecimal.divide(BigDecimal.java:1693)

这就是 BigDecimal 除法的坑:一旦返回的结果是无限循环小数,就会抛出 ArithmeticException。因此在进行 BigDecimal 除法的时候,需要进行保留小数的处理。

代码语言:javascript
复制
public static void main(String[] args) throws Exception {
    BigDecimal ten = new BigDecimal(10);
    BigDecimal three= new BigDecimal(3);
    BigDecimal result = ten.divide(three, 2, BigDecimal.ROUND_HALF_UP);
    System.out.println(result.toString());
}

执行结果:

代码语言:javascript
复制
3.33

4、Collections.emptyList() 此 List 非彼 List

在接口服务层处理时候,我们可能会对没有数据是返回一个空的List:Collections.emptyList()。

代码语言:javascript
复制
public List<String> get(String param) {
    // 逻辑处理
    // ......
    // 没有数据返回空集合
    return Collections.emptyList();
}

表面上看起来没有问题,但是一旦接受者对结果进行操作,就会出现异常:

代码语言:javascript
复制
List<String> resultList = service.get("param");
resultList.add("test");

运行结果:

代码语言:javascript
复制
Exception in thread "main" java.lang.UnsupportedOperationException
  at java.util.AbstractList.add(AbstractList.java:148)
  at java.util.AbstractList.add(AbstractList.java:108)

主要问题在于 Collections.emptyList() 并非我们平时看到的 List,此List 不支持 add、remove 方法。原因是 Collections.emptyList 返回的并不是我们平时认识的那个 List,它是一个内部常量类,是一种只读的 List ,并不提供数据的写入能力。因此它仅可作为一种空值返回,无法进行删除、添加操作。

代码语言:javascript
复制
public static final List EMPTY_LIST = new EmptyList<>();

5、BigDecimal 的 compareTo() 方法

虽然 BigDecimal 重写了 equals 方法,但是使用会存在问题:

代码语言:javascript
复制

public static void main(String[] args) {
    boolean b = new BigDecimal("1").equals(new BigDecimal("1.0"));
    System.out.println(b);
}

运行结果:

代码语言:javascript
复制
false

1 和 1.0 在比较的时候返回了 false。这是因为在 equals 的源码中进行了数据的 scale(也就是精度)的比较。如果不一致就会返回 false。如果使用 compareTo() 方法就不存在这个问题。

代码语言:javascript
复制
public static void main(String[] args) throws Exception {
    BigDecimal bd1 = new BigDecimal("1");
    BigDecimal bd2 = new BigDecimal("1.0");
    int i = bd1.compareTo(bd2);
    // i = 0 : bd1 == bd2
    // i = -1 : bd1 < bd2
    // i = 1 : bd1 > bd2
  }

6、String 的 split() 方法根据 | 分割

String 的 split 方法在进行 || 分割的时候需要进行转义,否则结果会有问题!

代码语言:javascript
复制
public static void main(String[] args) throws Exception {
    String str = "77|88";
    String[] s1 = str.split("|");
    String[] s2 = str.split("\\|");
    
    System.out.print("错误:");
    for (String s : s1) {
      System.out.print(s + "\t");
    }
    
    System.out.print("\n");
    
    System.out.print("正确:");
    for (String s : s2) {
      System.out.print(s + "\t");
    }
}

运行结果:

代码语言:javascript
复制
错误:7  7  |  8  8  
正确:77  88

结论

JDK 的设计者有两个很大的特点:

  • 大多不会做非 null 判断;
  • 出现错误直接 throw new Exception,容错性很差。

在实际开发中,面对 JDK 一定要谨慎使用。JDK 提供了便利的同时,也有一些我们使用上的盲区。应该养成多看源码,多注意错误性处理,防止在小问题上栽大跟头。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一个正经的程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1、String.valueOf()
  • 2、Integer.parseInt()
  • 3、BigDecimal 的除法 divide()
  • 4、Collections.emptyList() 此 List 非彼 List
  • 5、BigDecimal 的 compareTo() 方法
  • 6、String 的 split() 方法根据 | 分割
  • 结论
相关产品与服务
腾讯云 BI
腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档