一、基础语法与类型问题
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 提示、静态检查工具)和充分测试来规避。
文章小尾巴
文章小尾巴(点击展开)
文章写作、模板、文章小尾巴可参考:《写作"小心思"》
感谢你看到最后,最后再说两点~
①如果你持有不同的看法,欢迎你在文章下方进行留言、评论。
②如果对你有帮助,或者你认可的话,欢迎给个小点赞,支持一下~
(文章内容仅供学习参考,如有侵权,非常抱歉,请立即联系作者删除。)