
本文介绍如何使用 java 读取空格分隔的五列商品数据(描述、数量、重量、价格、税则号),按税则号聚合统计数量、重量和价格总和,并将结果格式化输出到新文件。全程采用面向对象设计与 stream api,兼顾可读性与工程实践性。
本文介绍如何使用 java 读取空格分隔的五列商品数据(描述、数量、重量、价格、税则号),按税则号聚合统计数量、重量和价格总和,并将结果格式化输出到新文件。全程采用面向对象设计与 stream api,兼顾可读性与工程实践性。
在实际业务处理中(如海关报关、库存汇总等场景),常需对结构化文本数据进行分组聚合。本教程以一个典型需求为例:从 .txt 文件中读取商品记录(每行 5 列,空格分隔),按第 5 列“税则号(tariff code)”归类,合并同税则号下所有商品的数量、重量、价格,最终输出精简汇总结果。
为提升代码可维护性与扩展性,我们采用面向对象方式建模核心业务实体 WritingKit:
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Locale;
public class WritingKit {
private String description;
private int quantity;
private double weight;
private double price;
private String tariffCode;
// 使用德语 Locale 支持逗号作为小数点(适配输入中的 "0,3" 格式)
private static final NumberFormat nf = NumberFormat.getNumberInstance(Locale.GERMAN);
public WritingKit(String description, int quantity, double weight, double price, String tariffCode) {
this.description = description;
this.quantity = quantity;
this.weight = weight;
this.price = price;
this.tariffCode = tariffCode;
}
// 静态工厂方法:从字符串数组解析一行数据
public static WritingKit valueOf(String[] parts) {
if (parts.length <p>主程序使用 Java NIO.2 和 Stream API 实现高效、声明式的处理流程:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6235" title="Java Maven Code Review"><img
src="https://img.php.cn/upload/skill/000/000/081/179084711841712.jpg" alt="Java Maven Code Review" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill6235" title="Java Maven Code Review" class="overflowclass">Java Maven Code Review</a>
<p class="overflowclass">审查Java Maven项目(ZIP压缩包或GitLab仓库URL),检查代码规范、命名、模块边界、可维护性问题以及重复代码。</p>
</div>
<a rel="nofollow" href="/xiazai/skill6235" title="Java Maven Code Review" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><pre class="brush:php;toolbar:false;">import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
public class TariffAggregator {
public static void main(String[] args) {
// ✅ 输入路径:支持命令行传参,也可硬编码(如 Paths.get("input.txt"))
Path inputPath = args.length > 0 ? Paths.get(args[0]) : Paths.get("Test for java input.txt");
Path outputPath = Paths.get("Test for java output.txt");
try {
// 1️⃣ 读取全部行 → 解析为 WritingKit 对象列表
List<writingkit> items = Files.lines(inputPath)
.filter(line -> !line.trim().isEmpty()) // 跳过空行
.map(line -> line.split("\s+")) // 按任意空白字符(空格/制表符)分割
.map(WritingKit::valueOf)
.collect(Collectors.toList());
System.out.println("✅ 原始数据共 " + items.size() + " 条记录:");
items.forEach(item -> System.out.println(" " + item.toCsv(" ")));
// 2️⃣ 按 tariffCode 分组,并对每组内对象执行 combine 聚合
Map<string writingkit> aggregatedByTariff = items.stream()
.collect(Collectors.groupingBy(
WritingKit::getTariffCode,
Collectors.collectingAndThen(
Collectors.reducing(
null,
item -> item,
WritingKit::combine
),
Optional::get
)
));
// 3️⃣ 输出结果到文件(覆盖写入)
List<string> resultLines = new ArrayList();
for (WritingKit item : aggregatedByTariff.values()) {
resultLines.add(item.toCsv(" "));
}
Files.write(outputPath, resultLines);
System.out.println("✅ 汇总完成!共 " + aggregatedByTariff.size() + " 个税则号,结果已保存至:" + outputPath);
} catch (IOException e) {
System.err.println("❌ 文件读写异常:" + e.getMessage());
e.printStackTrace();
} catch (NumberFormatException | NullPointerException e) {
System.err.println("❌ 数据解析错误(检查输入格式或小数点符号):" + e.getMessage());
}
}
// Getter 方法(供 WritingKit 类内部调用,此处省略;实际使用时请补全)
public String getTariffCode() { return this.tariffCode; }
public String getDescription() { return this.description; }
public int getQuantity() { return this.quantity; }
public double getWeight() { return this.weight; }
public double getPrice() { return this.price; }
}</string></string></writingkit>? 关键注意事项:
- 路径格式:Windows 下路径应使用正斜杠 / 或双反斜杠 \,例如 "C:/Test for java input.txt";避免原始字符串中混用引号导致编译错误。
- 小数解析:输入中使用英文逗号 , 作小数点(如 0,3),故必须配置 Locale.GERMAN 的 NumberFormat;若输入为英文句点(0.3),可直接用 Double.parseDouble()。
- 分隔符鲁棒性:使用正则 \s+ 替代固定空格,兼容多空格、制表符等空白分隔。
- 错误处理:生产环境建议增加更细粒度的异常捕获(如单行解析失败时跳过并记录警告)。
- 内存优化:对于超大文件(GB 级),应改用 Files.lines() 流式处理,避免一次性加载全部内容——本方案已默认采用该方式。
? 总结:相比原始二维字符数组硬编码方案,本实现以清晰的职责分离(数据建模 → 解析 → 聚合 → 输出)大幅提升可读性与可测试性。通过 Collectors.groupingBy 与 reducing 组合,一行代码即可完成分组求和,充分体现了 Java 8+ Stream API 的表达力与工程价值。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










