当前位置: 首页 > news >正文

Java问题排查汇总(附示例与解法)

一、高频问题:编译与运行时异常(60%+)

1. 空指针异常(NullPointerException)

// 错误示例1 public class Main { public static void main(String[] args) { String str = null; System.out.println(str.length()); // 触发NullPointerException } } // 错误示例2 public class User { private String name; public void printName() { System.out.println(name.toUpperCase()); // name为null } }

解决方法

// 方法1:提前判空 String str = null; if (str != null) { System.out.println(str.length()); } else { System.out.println("字符串为空"); } // 方法2:使用三元运算符 String result = (str != null) ? str : "默认值"; System.out.println(result.length()); // 方法3:Java 8+ Optional类 import java.util.Optional; String str = null; Optional.ofNullable(str) .ifPresent(s -> System.out.println(s.length())); // 方法4:防御性编程 public class User { private String name = ""; // 初始化默认值 public void printName() { if (name != null) { System.out.println(name.toUpperCase()); } } public void setName(String name) { this.name = (name == null) ? "" : name; // 入参校验 } }

2. 数组越界(ArrayIndexOutOfBoundsException)

// 错误示例 public class Main { public static void main(String[] args) { int[] arr = {1, 2, 3}; System.out.println(arr[5]); // 数组长度3,访问索引5 } }

解决方法

// 方法1:边界检查 int[] arr = {1, 2, 3}; int index = 5; if (index >= 0 && index < arr.length) { System.out.println(arr[index]); } else { System.out.println("索引越界: " + index); } // 方法2:使用增强for循环 for (int num : arr) { System.out.println(num); // 避免手动索引 } // 方法3:安全访问工具方法 public class ArrayUtils { public static <T> T safeGet(T[] array, int index) { if (array == null || index < 0 || index >= array.length) { return null; } return array[index]; } }

3. 类型转换异常(ClassCastException)

// 错误示例 public class Main { public static void main(String[] args) { Object obj = "Hello"; Integer num = (Integer) obj; // String无法转为Integer } }

解决方法

// 方法1:使用instanceof检查 Object obj = "Hello"; if (obj instanceof Integer) { Integer num = (Integer) obj; System.out.println(num); } else if (obj instanceof String) { String str = (String) obj; System.out.println(str); } // 方法2:安全转换工具 public class CastUtils { public static <T> T safeCast(Object obj, Class<T> clazz) { if (obj != null && clazz.isInstance(obj)) { return clazz.cast(obj); } return null; } public static Integer toInteger(Object obj) { if (obj == null) return null; if (obj instanceof Integer) { return (Integer) obj; } if (obj instanceof Number) { return ((Number) obj).intValue(); } if (obj instanceof String) { try { return Integer.parseInt((String) obj); } catch (NumberFormatException e) { return null; } } return null; } }

4. 数字格式异常(NumberFormatException)

// 错误示例 public class Main { public static void main(String[] args) { String str = "abc123"; int num = Integer.parseInt(str); // 包含非数字字符 } }

解决方法

// 方法1:捕获异常 String str = "abc123"; try { int num = Integer.parseInt(str); } catch (NumberFormatException e) { System.out.println("无效的数字格式: " + str); int num = 0; // 设置默认值 } // 方法2:正则表达式验证 public class NumberUtils { public static boolean isNumeric(String str) { if (str == null || str.trim().isEmpty()) { return false; } return str.matches("-?\\d+(\\.\\d+)?"); } public static Integer parseIntegerSafe(String str) { if (str == null) return null; try { return Integer.parseInt(str.trim()); } catch (NumberFormatException e) { return null; } } } // 使用示例 String str = "123"; if (NumberUtils.isNumeric(str)) { int num = Integer.parseInt(str); }

二、中频问题:IO、资源与逻辑错误(30%+)

1. 文件未找到(FileNotFoundException)

// 错误示例 import java.io.FileReader; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { FileReader reader = new FileReader("不存在的文件.txt"); // 使用reader reader.close(); } }

解决方法

import java.io.File; import java.io.FileReader; import java.io.IOException; public class Main { public static void main(String[] args) { // 方法1:先检查文件是否存在 File file = new File("data.txt"); if (file.exists() && file.isFile()) { try (FileReader reader = new FileReader(file)) { // 使用reader } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("文件不存在: " + file.getAbsolutePath()); } // 方法2:使用try-with-resources自动关闭资源 try (FileReader reader = new FileReader("data.txt")) { // 使用reader } catch (IOException e) { System.out.println("读取文件失败: " + e.getMessage()); // 创建默认文件或使用默认值 } } }

2. 资源未关闭导致内存泄漏

// 错误示例 public class ResourceLeak { public void readFile() throws IOException { FileInputStream fis = new FileInputStream("largefile.bin"); // 处理文件 // 忘记调用 fis.close(); } }

解决方法

// 方法1:try-with-resources(Java 7+) public void readFile() { try (FileInputStream fis = new FileInputStream("largefile.bin"); BufferedInputStream bis = new BufferedInputStream(fis)) { // 自动关闭资源 } catch (IOException e) { e.printStackTrace(); } } // 方法2:finally块确保关闭 public void readFile() { FileInputStream fis = null; try { fis = new FileInputStream("largefile.bin"); // 处理文件 } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }

3. 并发修改异常(ConcurrentModificationException)

// 错误示例 import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); for (String item : list) { // 增强for循环使用迭代器 if ("B".equals(item)) { list.remove(item); // 在遍历时修改列表 } } } }

解决方法

import java.util.*; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); // 方法1:使用迭代器的remove方法 Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if ("B".equals(item)) { iterator.remove(); // 使用迭代器删除 } } // 方法2:Java 8+ removeIf list.removeIf(item -> "B".equals(item)); // 方法3:记录要删除的元素,遍历后删除 List<String> toRemove = new ArrayList<>(); for (String item : list) { if ("B".equals(item)) { toRemove.add(item); } } list.removeAll(toRemove); // 方法4:使用CopyOnWriteArrayList(线程安全,适合读多写少) List<String> safeList = new CopyOnWriteArrayList<>(list); for (String item : safeList) { if ("B".equals(item)) { safeList.remove(item); } } } }

三、低频但棘手问题(<10%)

1. 内存溢出(OutOfMemoryError)

// 错误示例 import java.util.ArrayList; import java.util.List; public class MemoryLeak { private static List<byte[]> cache = new ArrayList<>(); public void processData() { while (true) { cache.add(new byte[1024 * 1024]); // 每次添加1MB } } }

解决方法

// 方法1:使用JVM参数调优 /* 启动参数示例: -Xms512m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -Xms512m: 初始堆大小512MB -Xmx1024m: 最大堆大小1024MB -XX:+HeapDumpOnOutOfMemoryError: 内存溢出时生成堆转储文件 */ // 方法2:使用弱引用或软引用 import java.lang.ref.WeakReference; import java.util.Map; import java.util.WeakHashMap; public class CacheManager { // 使用WeakHashMap,当键不再被强引用时,自动回收 private Map<Object, Object> cache = new WeakHashMap<>(); // 使用SoftReference,内存不足时才回收 private SoftReference<byte[]> dataCache; } // 方法3:监控内存使用 public class MemoryMonitor { public static void printMemoryInfo() { Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); long usedMemory = totalMemory - freeMemory; System.out.printf("最大内存: %.2f MB\n", maxMemory / 1024.0 / 1024.0); System.out.printf("已用内存: %.2f MB\n", usedMemory / 1024.0 / 1024.0); System.out.printf("可用内存: %.2f MB\n", freeMemory / 1024.0 / 1024.0); } }

2. 死锁(Deadlock)

// 错误示例 public class DeadlockExample { private final Object lock1 = new Object(); private final Object lock2 = new Object(); public void method1() { synchronized (lock1) { System.out.println("线程1获得lock1"); try { Thread.sleep(100); } catch (InterruptedException e) {} synchronized (lock2) { System.out.println("线程1获得lock2"); } } } public void method2() { synchronized (lock2) { System.out.println("线程2获得lock2"); try { Thread.sleep(100); } catch (InterruptedException e) {} synchronized (lock1) { System.out.println("线程2获得lock1"); } } } }

解决方法

// 方法1:按相同顺序获取锁 public class DeadlockSolution { private final Object lock1 = new Object(); private final Object lock2 = new Object(); public void method1() { synchronized (lock1) { System.out.println("线程1获得lock1"); try { Thread.sleep(100); } catch (InterruptedException e) {} synchronized (lock2) { System.out.println("线程1获得lock2"); } } } public void method2() { synchronized (lock1) { // 改为先获取lock1 System.out.println("线程2获得lock1"); try { Thread.sleep(100); } catch (InterruptedException e) {} synchronized (lock2) { System.out.println("线程2获得lock2"); } } } } // 方法2:使用tryLock避免死锁 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TryLockSolution { private final Lock lock1 = new ReentrantLock(); private final Lock lock2 = new ReentrantLock(); public void method1() { while (true) { if (lock1.tryLock()) { try { System.out.println("线程1获得lock1"); if (lock2.tryLock()) { try { System.out.println("线程1获得lock2"); break; // 成功获取两个锁 } finally { lock2.unlock(); } } } finally { lock1.unlock(); } } // 未获取到锁,短暂休眠后重试 try { Thread.sleep(10); } catch (InterruptedException e) {} } } }

3. 线程安全问题

// 错误示例 public class Counter { private int count = 0; public void increment() { count++; // 非原子操作 } public int getCount() { return count; } }

解决方法

// 方法1:使用synchronized public class SynchronizedCounter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } } // 方法2:使用AtomicInteger import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } } // 方法3:使用ReentrantLock import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockCounter { private int count = 0; private final Lock lock = new ReentrantLock(); public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } public int getCount() { lock.lock(); try { return count; } finally { lock.unlock(); } } }

四、Java问题排查工具箱

1. 命令行工具

# 查看Java进程 jps -l # 查看堆内存使用 jmap -heap <pid> # 生成堆转储文件 jmap -dump:format=b,file=heapdump.hprof <pid> # 线程转储 jstack <pid> > threaddump.txt # 查看GC情况 jstat -gc <pid> 1000 10 # 每秒一次,共10次

2. 使用JVM参数进行调试

# 开启调试信息 java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log -jar app.jar # 内存溢出时生成堆转储 java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./oom.hprof -jar app.jar # 设置堆大小 java -Xms512m -Xmx2g -Xmn256m -jar app.jar

3. 使用JMX监控

// 在启动参数中添加 // -Dcom.sun.management.jmxremote // -Dcom.sun.management.jmxremote.port=9010 // -Dcom.sun.management.jmxremote.authenticate=false // -Dcom.sun.management.jmxremote.ssl=false

4. 使用日志记录

import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Service { private static final Logger logger = LoggerFactory.getLogger(Service.class); public void process() { logger.debug("开始处理"); try { // 业务逻辑 logger.info("处理成功"); } catch (Exception e) { logger.error("处理失败", e); // 记录完整异常栈 } } }

5. 断点调试技巧

// 条件断点 public void process(List<User> users) { for (User user : users) { // 在下一行设置条件断点:user.getName().equals("张三") System.out.println(user.getName()); } } // 异常断点 // 在IDE中设置捕获特定异常时自动暂停

快速排查流程图

问题发生 ↓ 查看控制台输出 ↓ 阅读异常堆栈(关键信息:异常类型、位置、原因) ↓ 复现问题(构造最小可复现代码) ↓ 断点调试(单步执行,观察变量变化) ↓ 日志分析(查看相关日志) ↓ 工具分析(jstack、jmap、jvisualvm) ↓ 代码审查(检查逻辑错误、并发问题) ↓ 测试验证(确保修复后不再出现问题)

黄金法则

  1. 优先阅读异常信息,Java的异常信息通常很详细

  2. 使用try-with-resources管理资源

  3. 对可能为null的对象进行判空

  4. 多线程环境下使用线程安全的集合

  5. 定期检查代码中的内存泄漏点

http://www.jsqmd.com/news/654587/

相关文章:

  • DeerFlow监控体系:关键指标采集与告警设置
  • rt thread中的can通信 学习记录
  • 终极魔兽争霸3优化指南:如何让经典游戏在Win11上流畅运行
  • 2026年靠谱的耐腐方矩管生产厂家推荐,全流程管控有保障 - mypinpai
  • 汽车改色膜服务联系方式大汇总,看看哪个口碑好值得选 - myqiye
  • Zotero-GPT:将人工智能注入文献管理的革命性插件
  • 百度网盘提取码智能获取工具:告别繁琐搜索,3秒直达资源
  • 别再死记硬背LangChain API了!用这5个真实项目案例,带你从零到一上手AI应用开发
  • 2026年激光打标机实力公司口碑推荐:国内顶尖定制厂家深度解析 - 品牌策略师
  • 从原理到实践:手把手实现Code128条形码的生成与校验
  • 2026年口碑好的能承接大型项目方矩管供应企业,推荐哪家 - 工业设备
  • MinerU在出版行业的应用:教材扫描件自动分栏+习题识别+答案定位
  • Node.js环境配置与Ostrakon-VL调用:全栈JavaScript视觉应用开发
  • 团团收靠谱吗?京东e卡回收平台评测与对比! - 团团收购物卡回收
  • Nintendo Switch文件管理终极指南:NSC_BUILDER轻松处理NSP和XCI游戏文件
  • 5分钟快速解锁VMware macOS支持:终极免费工具完整指南
  • 2026年浴室柜加盟产品展示,品牌推荐及市场推广实用指南 - 工业品网
  • 低空经济数据服务全解析:核心技术、应用场景与未来布局
  • UnrealPakViewer:从黑盒到透明化,深度解析UE4 Pak文件管理技术突破
  • 终极指南:如何在Mac上完整备份和查看微信聊天记录
  • [ecapture]Connect Events获取
  • 电子小白学完基本元器件之后,电子新手该怎么走?
  • 如何突破城通网盘下载限制?ctfileGet直连解析工具全解析
  • 快速上手SiameseAOE:从用户评论中自动提取“属性-观点”对
  • QMCDecode终极指南:轻松解密QQ音乐加密音频文件
  • 5步掌握NSC_BUILDER:Switch游戏文件管理的完整路径
  • 程序员Token消耗排行榜:原来最烧钱的不是写代码!
  • 如何创建语句级触发器_表级操作监控与日志记录实现
  • 2026信息安全就业方向+前景(超详细)|小白入门到精通,收藏永不会踩坑
  • Python学习超简单第二弹:函数