【JAVA】【BUG】经常出现的典型 bug 及解决办法

前言

偶然想到,作为每个入门后端 java 程序员,都会经历各种各样的 bug 问题,那么收集了一下比较经常出现的典型 bug 及其解决方法,供给想入门的新友作为参考与学习,老友呢,加深印象更加熟悉!~ 我们开始吧!

目录序号

  1. 空指针异常(NullPointerException)
  2. 数据库连接未关闭
  3. 线程安全问题
  4. 内存泄漏
  5. 字符串拼接性能问题
  6. 未处理异常
  7. 不当使用集合
  8. 无限递归
  9. 日期格式化线程安全问题
  10. 序列化问题
  11. [SQL 注入](#SQL 注入)
  12. 锁粒度问题

1. 空指针异常(NullPointerException)

这是最为常见的错误。当对值为null的对象调用方法、访问属性或者进行其他操作时,就会触发该异常。

java 复制代码
String str = null;
int length = str.length(); // 此处会抛出NPE

解决方法

  • 运用Objects.requireNonNull()方法。
  • 借助Optional类来处理可能为null的情况。
  • 进行null值检查。

2. 数据库连接未关闭

要是数据库连接使用完毕后没有及时关闭,会造成连接资源的浪费,严重时可能引发连接池耗尽的问题。

java 复制代码
Connection conn = DriverManager.getConnection(url, username, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
// 缺少关闭资源的代码

解决方法

  • 采用try-with-resources语句,它能够自动关闭实现了AutoCloseable接口的资源。
  • finally块中关闭资源。

3. 线程安全问题

在多线程环境下,对共享变量进行非原子性操作,或者使用了非线程安全的类,都容易引发数据不一致的情况。

java 复制代码
public class Counter {
    private int count = 0;
    public void increment() {
        count++; // 非原子操作,存在竞态条件
    }
}

解决方法

  • 运用synchronized关键字、ReentrantLock或者原子类(如AtomicInteger)。
  • 优先使用线程安全的集合,像ConcurrentHashMap

4. 内存泄漏

长生命周期的对象持有短生命周期对象的引用,会使短生命周期对象无法被垃圾回收,从而造成内存泄漏。

java 复制代码
public class Cache {
    private static final Map<String, Object> cache = new HashMap<>();
    public static void add(String key, Object value) {
        cache.put(key, value);
        // 缺少移除机制
    }
}

解决方法

  • 为缓存设置合理的过期策略,例如使用LinkedHashMap实现 LRU 缓存。
  • 及时释放无用的资源,如监听器、连接等。

5. 字符串拼接性能问题

在循环中使用+进行字符串拼接,会产生大量的临时对象,降低性能。

java 复制代码
String result = "";
for (int i = 0; i < 1000; i++) {
    result += i; // 性能较差
}

解决方法

  • 使用StringBuilder(非线程安全场景)或者StringBuffer(线程安全场景)。

6. 未处理异常

捕获异常后不进行任何处理,或者直接吞掉异常,会掩盖潜在的问题。

java 复制代码
try {
    // 可能抛出异常的代码
} catch (IOException e) {
    // 空实现,未记录日志或处理异常
}

解决方法

  • 记录异常日志。
  • 向上抛出合适的异常。
  • 提供默认处理逻辑。

7. 不当使用集合

在需要唯一元素的场景中使用ArrayList,导致重复元素出现;或者在需要有序集合时使用HashMap

java 复制代码
List<String> list = new ArrayList<>();
list.add("a");
list.add("a"); // 允许重复元素

解决方法

  • 根据具体需求选择合适的集合类型,如SetTreeMap等。

8. 无限递归

递归方法缺少终止条件,或者终止条件不满足要求,会导致栈溢出错误(StackOverflowError)。

java 复制代码
public void recursiveMethod() {
    recursiveMethod(); // 缺少终止条件
}

解决方法

  • 确保递归方法有明确的终止条件。
  • 考虑使用迭代替代递归。

9. 日期格式化线程安全问题

SimpleDateFormat不是线程安全的类,在多线程环境下共享使用会导致日期解析错误。

java 复制代码
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public static Date parse(String dateStr) {
    return sdf.parse(dateStr); // 多线程下不安全
}

解决方法

  • 在每个线程中创建独立的SimpleDateFormat实例。
  • 使用线程安全的DateTimeFormatter(Java 8 及以后版本)。

10. 序列化问题

实现Serializable接口的类没有声明serialVersionUID,可能会导致反序列化失败。

java 复制代码
public class User implements Serializable {
    private String name;
    // 缺少serialVersionUID
}

解决方法

  • 显式声明serialVersionUID
  • 保持序列化前后类的结构兼容。

11. SQL 注入

直接将用户输入拼接 SQL 语句,会导致 SQL 注入攻击。

java 复制代码
String sql = "SELECT * FROM users WHERE username = '" + username + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql); // 存在SQL注入风险

解决方法

  • 使用预编译语句(PreparedStatement)。
  • 对用户输入进行严格的参数校验。

12. 锁粒度问题

同步块范围过大,会影响系统性能;而锁的粒度太小,又可能无法保证线程安全。

java 复制代码
public synchronized void process() {
    // 包含大量非关键操作,锁粒度太粗
}

解决方法

  • 缩小同步块的范围。
  • 采用细粒度的锁,如ReentrantLock

总结

要减少 Java 后端开发中的错误,关键在于养成良好的编程习惯,比如:

  • 进行严格的输入校验
  • 合理处理异常
  • 做好资源管理
  • 重视代码审查
  • 编写全面的单元测试

文章小尾巴

文章写作、模板、文章小尾巴可参考:《写作"小心思"》

感谢你看到最后,最后再说两点~

①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。

②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~

我是南方者,一个热爱计算机更热爱祖国的南方人。

(文章内容仅供学习参考,如有侵权,非常抱歉,请立即联系作者删除。)

相关推荐
初圣魔门首席弟子3 小时前
c++嵌套类和局部类详细介绍
java·开发语言·c++
nice_lcj5204 小时前
Java 集合框架之 List 全面解析(从概念到实践)
java·windows·list
Albert Edison4 小时前
【MySQL】表的操作
数据库·mysql·oracle
高山上有一只小老虎4 小时前
输出单向链表中倒数第k个结点
java·数据结构·链表
失散135 小时前
分布式专题——22 Kafka集群工作机制详解
java·分布式·云原生·架构·kafka
咖啡Beans6 小时前
SseEmitter + WebClient + Flux实现SSE事件流推送
java·spring boot·flux
你三大爷6 小时前
Safepoint的秘密探寻
java·后端
努力也学不会java6 小时前
【Java并发】揭秘Lock体系 -- condition等待通知机制
java·开发语言·人工智能·机器学习·juc·condition
我需要打球7 小时前
SpringMVC的执行流程
java·servlet