java常见bugs

欢迎你来读这篇博客,这篇博客主要是关于java常见bug及避免方法的介绍
其中包括了关于我的见解和收集的知识分享。

序言

正文

NPE 场景

  1. 调用了空对象的实例方法
  2. 访问空对象的属性
  3. 数组为空的时候,取长度
  4. 不能抛出空异常对象
  5. 方法的返回值是null,调用方法直接使用
  6. 自动拆箱导致NPE
    • 空包装对象赋值给基本数据类型时
    • 方法传参时
    • 空对象进行比较大小

避免方法

  • 使用之前初始化
  • 避免返回null
  • 外部传值,一定要及时判断
  • 基本数据类型优于包装类型,优先使用基本数据类型
  • 不确定的包装类型,先校验后使用
  • 对于Null值的包装类型,赋值为0

字符串、数组、集合场景

  • null字符串调用equals方法
  • 对象数组new出来,但元素没有初始化
  • list的addAll方法,传递null

Optional

  • 不能作为类字段使用,没有实现序列化接口
  • 容器类,代表存在和不存在
  • orElse(new Object()) 存在返回,空提供默认值
  • orElseGet() 存在返回,空由函数去产生 // 配合单例
  • orElseThrow 存在返回,空抛出异常
  • ifPresent 存在处理
  • map 执行操作后返回一个optional对象

正确处理异常

  • 使用异常,而不是返回码(或类似),因为异常会更加的详细
  • 主动捕获检查性异常,并对异常信息进行反馈(日志或标记)
  • 保持代码整洁,一个方法中不要有多个 try catch 或者嵌套的 try catch
  • 捕获更加具体的异常,而不是通用的 Exception
  • 合理的设计自定义的异常类

常见异常

  • 并发修改:可迭代对象在遍历的同时做修改,则会报并发修改异常
  • 类型转换:类型转换不符合 Java 的继承关系,则会报类型转换异常
  • 枚举查找:枚举在查找时,如果枚举值不存在,不会返回空,而是直接抛出异常

资源管理

try-with-resources

java计算、接口、集合

BigDecimal精度问题

  • 初始化设置精度需要匹配
    • bigDecimal.setScale(2) 可大不能小
    • bigDecimal.setScale(2,BigDecimal.ROUND_HALF_UP)
  • 除法结果需要精度
  • 数值比较需要精度匹配

日期

SimpleDataFormat

  • 可以解析大于或等于它定义的时间精度,但不能解析小于它定义的精度
  • 线程不安全,多线程会抛出异常
    • 原因:内部有一个calendar
    • 解决方法:定义为局部变量、使用ThreadLoacl、Synchronize

迭代问题

  • for-each优于for

集合判等问题

  • equals和hashcode与其可能带来的潜在问题
  • 类实现了 compareTo 方法,就需要实现 equals 方法
  • compareTo 与 equals 的实现过程需要同步

Lombok

  • @EqualsAndHashCode(callSuper=true)
  • 命名问题

抽象类和接口

抽象类、接口的含义和特性

  • 抽象类是子类的通用特性,包含了属性和行为;接口是定义行为,并不关心谁去实现
  • 抽象类是对类本质的抽象,表达的是 is a 的关系;接口是对行为的抽象,表达的是like a 的关系

抽象类、接口的相同点

  • 接口中的方法(java8 改变了这一语法)和抽象类中的抽象方法都不能有方法体,并且必须在子类中实现
  • 都可以被继承,但是不能被实例化

抽象类、接口的不同点

  • 使用时语法不同,抽象类使用 extends,接口则使用implements
  • 接口中只能定义常量,所以,不能表达对象状态,而抽象类可以
  • 接口中的方法必须是 public类型的,而抽象类则没有限制
  • 类可以同时实现多个接口(间接解决了 Java 不支持多继承的we难题),但是只能继承一个抽象类

默认方法与静态方法

lambda与函数式接口

Stream和lambda真的高效吗

迭代过多可能会导致计算低效

序列化

  • 父类不可序列化,子类实现了序列化接口也不行
    • 需要提供父类的默认无参构造器
  • 类中存在引用对象
    • 所有属性都是可序列化的才可以序列化
  • 同一个对象多次序列化,直接有更新
    • 不会重复序列化,会影响结果

泛型

玩转泛型的前提是理解泛型擦除。

泛型的特性

  • 先检查再编译
  • 泛型不支持继承
  • 泛型的类型变量不能是基本类型
  • 泛型的类型参数只能是类类型,不能是简单类型

使用原始类型,可能会带来灾难性后果 不声明泛型类型。主要是为了兼容旧代码。

参考资料

启示录

富贵岂由人,时会高志须酬。

能成功于千载者,必以近察远。


java常见bugs
https://allendericdalexander.github.io/2025/03/31/java_bugs/
作者
AtLuoFu
发布于
2025年3月31日
许可协议