发布于2026-07-05 阅读(0)
扫一扫,手机访问
在日常的Ja va开发工作中,解析CSV文件本身并不算高难度任务,但如果不小心踩中“空指针”这类基础错误,整个过程就会瞬间卡壳。尤其是处理信用卡交易数据时,这类问题会格外棘手——你不仅要确保程序能跑通,还得保证它能把交易条理清晰地统计出来。那么,实际要怎么做呢?今天就深入拆解一下整个过程,从修复`NullPointerException`,到实现交易总数、借记/贷记分类和金额汇总,一条路走到底。
假设你在代码里声明了一个 `private Scanner s;`,然后直接就去调 `s.nextLine()`——这基本就是空指针的“待触发按钮”。因为 Scanner 对象还没有被实例化成可用状态。说白了,你没有在构造阶段或者正式读取数据之前,完成 `s = new Scanner(...)` 这步操作。更典型的错误逻辑是:程序刚进入`scanner()`方法就急着跑`while (moreLines)`循环,循环里直接尝试读取 `s.nextLine()`,而此刻 `s` 仍然等于 `null`。等循环结束了才想起来创建 Scanner 实例,整个顺序显然不对。
这个问题听起来有点低级,但在实际代码中却极其常见,经常让开发者排查很久才发现是初始化顺序的问题。
正确的做法其实很简单:在真正开始对文件进行逐行扫描之前,提前把 Scanner 实例化好,并且确保文件存在、可读。在这个基础上,再去做数据统计的活儿就顺手多了。
以下是重构后的关键代码逻辑,它已经将交易分析的统计需求封装在内:
import ja va.io.File;
import ja va.io.FileNotFoundException;
import ja va.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;
public CsvReader() {
// 构造器只负责对象状态初始化,不提前执行 IO 操作
}
public void analyzeTransactions() {
try {
s = new Scanner(new File("visadata.txt"));
// 跳过可能的第一行表头(比如 "卡号,日期,类型,金额,描述")
if (s.hasNextLine()) s.nextLine();
while (s.hasNextLine()) {
String line = s.nextLine().trim();
if (line.isEmpty()) continue;
String[] fields = getTokens(line);
if (fields.length < 5) continue; // 字段数不够就跳过
String transactionType = fields[2].trim().toLowerCase(); // 假设第3列为交易类型
String amountStr = fields[3].trim(); // 假设第4列为金额
totalTransactions++;
try {
double amount = Double.parseDouble(amountStr);
if ("debit".equals(transactionType)) {
debitCount++;
totalDebitAmount += amount;
} else if ("credit".equals(transactionType)) {
creditCount++;
}
} catch (NumberFormatException e) {
System.err.println("警告:无效金额格式跳过行 — " + line);
}
}
printSummary();
} catch (FileNotFoundException e) {
System.err.println("❌ 错误:未找到文件 'visadata.txt',请检查路径和文件权限。");
} finally {
if (s != null) s.close(); // 无论如何都要关闭资源
}
}
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);
}
}
代码重构完成后,有几个地方值得额外留意,它们直接决定了这个解析器在实际业务场景中的可用性和健壮性。
经过上面这些调整,你不仅摆脱了那个让人头疼的 `NullPointerException`,而且手里已经有了一套结构清晰、具备基础金融统计能力的 CSV 解析器。更进一步,这套框架完全可以继续扩展——比如增加多卡类型识别、时间范围过滤、导出分析报告等高级功能,只是时间问题。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8