【JAVA】【BUG】Java 开发中常见问题的具体示例,结合代码片段说明问题场景及原因

一、基础语法与类型问题

1. 空指针异常(NPE)

java 复制代码
String str = null;
System.out.println(str.length()); // 触发NPE:调用null对象的方法
java 复制代码
List<String> list = null;
list.add("a"); // 触发NPE:对null集合执行操作

2. 自动装箱 / 拆箱陷阱

java 复制代码
Integer a = 128;
Integer b = 128;
System.out.println(a == b); // false(128超出Integer缓存范围[-128,127])
System.out.println(a.equals(b)); // true(正确比较值)
java 复制代码
// 循环中频繁装箱导致性能损耗
int sum = 0;
for (int i = 0; i < 10000; i++) {
    sum += new Integer(i); // 每次创建Integer对象,应直接用int
}

3. 字符串操作误区

java 复制代码
// 频繁拼接字符串产生大量临时对象
String str = "";
for (int i = 0; i < 1000; i++) {
    str += i; // 每次拼接创建新String,效率低
}
// 正确方式:用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);
}
java 复制代码
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2); // false(s1在常量池,s2在堆内存,地址不同)
System.out.println(s1.equals(s2)); // true(比较内容)

二、集合框架问题

1. ConcurrentModificationException

java 复制代码
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");

// for-each循环中修改集合,触发异常
for (String s : list) {
    if (s.equals("a")) {
        list.remove(s); // 报错:ConcurrentModificationException
    }
}

// 正确方式:用迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("a")) {
        it.remove(); // 迭代器自身的remove方法
    }
}

2. HashMap 线程安全与键问题

java 复制代码
// JDK 1.7及之前:多线程put可能导致死循环(JDK 1.8后优化但仍不线程安全)
HashMap<String, Integer> map = new HashMap<>();
new Thread(() -> { for (int i = 0; i < 1000; i++) map.put("key" + i, i); }).start();
new Thread(() -> { for (int i = 0; i < 1000; i++) map.put("key" + i, i); }).start();

// 正确:用ConcurrentHashMap
ConcurrentHashMap<String, Integer> safeMap = new ConcurrentHashMap<>();
java 复制代码
// 键未重写hashCode和equals,导致HashMap无法正确查找
class User {
    String name;
    User(String name) { this.name = name; }
    // 未重写hashCode()和equals()
}
HashMap<User, Integer> map = new HashMap<>();
map.put(new User("张三"), 1);
System.out.println(map.get(new User("张三"))); // null(两个User对象地址不同)

三、多线程与并发问题

1. 线程安全:共享变量可见性问题

java 复制代码
class Counter {
    private int count = 0; // 未用volatile,线程1修改后线程2可能看不到
    public void increment() { count++; }
    public int getCount() { return count; }
}

Counter counter = new Counter();
// 线程1累加
new Thread(() -> { for (int i = 0; i < 1000; i++) counter.increment(); }).start();
// 线程2读取,可能结果小于1000(因count未被volatile修饰,不可见)
new Thread(() -> { System.out.println(counter.getCount()); }).start();

2. 线程池资源泄漏

java 复制代码
// 未关闭线程池,导致核心线程一直存活
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
    executor.submit(() -> System.out.println("任务"));
}
// 缺少 executor.shutdown(); 线程池不会自动关闭,资源泄漏

3. 死锁示例

java 复制代码
Object lockA = new Object();
Object lockB = new Object();

// 线程1:持有lockA,等待lockB
new Thread(() -> {
    synchronized (lockA) {
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        synchronized (lockB) { System.out.println("线程1获取双锁"); }
    }
}).start();

// 线程2:持有lockB,等待lockA
new Thread(() -> {
    synchronized (lockB) {
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        synchronized (lockA) { System.out.println("线程2获取双锁"); }
    }
}).start();
// 结果:两个线程互相等待,死锁

四、IO 与资源管理问题

1. 资源未关闭导致泄漏

java 复制代码
// 错误:未关闭文件流,可能导致文件句柄耗尽
FileInputStream fis = null;
try {
    fis = new FileInputStream("file.txt");
    // 读取操作
} catch (IOException e) {
    e.printStackTrace();
}
// 缺少 finally { if (fis != null) fis.close(); }

// 正确:try-with-resources(自动关闭)
try (FileInputStream fis = new FileInputStream("file.txt")) {
    // 读取操作
} catch (IOException e) {
    e.printStackTrace();
}

2. 大文件读取 OOM

java 复制代码
// 错误:一次性加载大文件到内存
byte[] data = Files.readAllBytes(Paths.get("largeFile.txt")); // 大文件时OOM

// 正确:逐行读取
try (BufferedReader br = new BufferedReader(new FileReader("largeFile.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        // 处理单行
    }
} catch (IOException e) {
    e.printStackTrace();
}

五、异常处理问题

1. 异常被吞(掩盖错误)

java 复制代码
try {
    int result = 1 / 0; // 触发ArithmeticException
} catch (Exception e) {
    // 未处理也未抛出,异常被吞,无法排查错误
}

2. finally 块覆盖异常

java 复制代码
try {
    int result = 1 / 0; // 异常A
} catch (ArithmeticException e) {
    throw e; // 计划抛出异常A
} finally {
    throw new RuntimeException("finally异常"); // 异常B覆盖异常A
}
// 最终抛出的是"finally异常",原异常丢失

六、JVM 与内存问题

1. 内存泄漏(静态集合未清理)

java 复制代码
class Cache {
    // 静态集合持有对象引用,不会被GC回收
    private static List<Object> cache = new ArrayList<>();
    
    public static void add(Object obj) {
        cache.add(obj); // 只添加不删除,持续占用内存
    }
}
// 频繁调用Cache.add(),最终导致OOM

七、框架问题(以 Spring 为例)

1. 事务失效(自调用问题)

java 复制代码
@Service
public class OrderService {
    @Transactional
    public void createOrder() {
        // 事务逻辑
    }
    
    public void process() {
        createOrder(); // 自调用,未通过Spring代理,事务失效
    }
}

2. 依赖冲突(NoSuchMethodError)

xml 复制代码
<!-- Maven依赖冲突:引入不同版本的Jackson -->
<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.0</version> <!-- 旧版本无某方法 -->
    </dependency>
    <dependency>
        <groupId>other.lib</groupId>
        <artifactId>some-lib</artifactId>
        <version>1.0</version>
        <dependency> <!-- 传递依赖高版本 -->
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.0</version>
        </dependency>
    </dependency>
</dependencies>
<!-- 运行时可能因版本不一致抛出NoSuchMethodError -->

这些示例覆盖了 Java 开发中最典型的问题场景,实际开发中需通过规范编码、工具检测(如 IDE 提示、静态检查工具)和充分测试来规避。

文章小尾巴

文章小尾巴(点击展开)

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

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

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

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

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

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

相关推荐
没有bug.的程序员3 小时前
MySQL 配置调优参数:从基础到生产级优化指南
java·数据库·mysql·优化·mysql配置调优
寻月隐君3 小时前
Rust 泛型编程基石:AsRef 和 AsMut 的核心作用与实战应用
后端·github
画船听雨眠aa3 小时前
Java8新特性——Stream API常见操作
java
Java水解3 小时前
100道互联网大厂面试题+答案
java·后端·面试
用户8356290780513 小时前
使用Python自动化移除Excel公式,保留纯净数值
后端·python
nlog3n4 小时前
分布式计数器系统完整解决方案
java·分布式
Java水解4 小时前
SpringBoot 线程池 配置使用详解
spring boot·后端
ytadpole4 小时前
Java并发编程:从源码分析ThreadPoolExecutor 的三大核心机制
java·面试
Aevget4 小时前
「Java EE开发指南」用MyEclipse开发的EJB开发工具(一)
java·ide·java-ee·myeclipse