本文详解如何修复因 scanner 未初始化导致的 nullpointerexception,并实现一个健壮的 csv 解析器,用于统计信用卡交易总数、借记/贷记笔数及借记总金额。
本文详解如何修复因 scanner 未初始化导致的 nullpointerexception,并实现一个健壮的 csv 解析器,用于统计信用卡交易总数、借记/贷记笔数及借记总金额。
在开发 CSV 读取器分析信用卡数据时,NullPointerException 是初学者最常见的陷阱之一——其根源往往在于对象使用早于初始化。你的代码中,private Scanner s; 仅声明而未初始化,却在 scanner() 方法开头就调用 s.nextLine(),此时 s 为 null,必然触发异常。
应将 Scanner 初始化移至构造函数或 scanner() 方法起始处,确保在任何读取操作前完成实例化。同时,需明确区分“文件打开失败”与“文件已读完”两类异常:FileNotFoundException 表示文件不存在;NoSuchElementException 表示无更多行可读——二者不可混淆处理。
以下是重构后的核心逻辑(含完整功能扩展):
import java.io.File;import java.io.FileNotFoundException;import java.util.Scanner;public class CsvReader { private Scanner s; private int totalTransactions = 0; private int debitCount = 0; private int creditCount = 0; private double totalDebitAmount = 0.0; // 构造函数:立即初始化 Scanner(若文件存在) public CsvReader(String fileName) { try { s = new Scanner(new File(fileName)); } catch (FileNotFoundException e) { System.err.println("❌ 错误:文件 '" + fileName + "' 未找到。请检查路径和文件名。"); s = null; // 显式设为 null,避免后续误用 } } // 主解析方法 public void analyze() { if (s == null) return; // 文件加载失败,直接退出 while (s.hasNextLine()) { String line = s.nextLine().trim(); if (line.isEmpty()) continue; // 跳过空行 String[] fields = getTokens(line); if (fields.length < 5) { System.err.println("⚠️ 警告:跳过格式异常行(字段不足5个): " + line); continue; } // 假设第3列为交易类型("Debit" / "Credit"),第5列为金额(如 "$123.45") String type = fields[2].trim(); String amountStr = fields[4].trim().replace("$", "").replace(",", ""); try { double amount = Double.parseDouble(amountStr); totalTransactions++; if ("Debit".equalsIgnoreCase(type)) { debitCount++; totalDebitAmount += amount; } else if ("Credit".equalsIgnoreCase(type)) { creditCount++; } } catch (NumberFormatException e) { System.err.println("⚠️ 警告:金额解析失败,跳过该行: " + line); } } s.close(); // ✅ 关闭资源,防止内存泄漏 printSummary(); } // 你原有的 CSV 解析逻辑(已优化:避免空指针 & 提升鲁棒性) private String[] getTokens(String input) { String[] tokens = new String[5]; for (int i = 0; i < tokens.length; i++) tokens[i] = ""; int index = 0, pointer = 0; boolean inQuotes = false; while (pointer < input.length()) { char c = input.charAt(pointer); if (c == '"') { inQuotes = !inQuotes; } else if (c == ',' && !inQuotes) { index++; if (index >= tokens.length) break; // 防越界 } else { tokens[index] += c; } pointer++; } return tokens; } private void printSummary() { System.out.println("? 交易统计报告"); System.out.println("├─ 总交易数: " + totalTransactions); System.out.println("├─ 借记交易数: " + debitCount); System.out.println("├─ 贷记交易数: " + creditCount); System.out.printf("└─ 借记总金额: $%.2f%n", totalDebitAmount); } // 使用示例 public static void main(String[] args) { CsvReader reader = new CsvReader("visadata.txt"); reader.analyze(); }}
通过以上重构,你不仅能彻底规避 NullPointerException,还能获得一个可扩展、易维护、生产就绪的信用卡 CSV 分析工具。