
本教程详细介绍了如何使用java高效地处理文本文件中的重复行。针对以特定字段(如每行的第一个逗号分隔值)作为重复判断依据的场景,我们将探讨两种基于java stream api和`collectors.tomap()`的解决方案:一种直接操作字符串,另一种通过引入领域对象提升代码可读性和可维护性。文章将提供详细的代码示例和实现步骤,帮助开发者准确筛选和存储唯一数据。
在数据处理中,我们经常会遇到需要从文本文件中清除重复记录的场景。与简单的行重复不同,有时重复的定义是基于行内某个特定字段的值。例如,在一个包含公司信息的文本文件中,如果多行记录的第一个字段(如公司ID)相同,即使其他字段不同,我们也可能希望将其视为重复并只保留其中一条。本教程将详细介绍如何使用Java实现这一功能,并将处理后的唯一记录存储到ArrayList中。
考虑以下文本文件内容:
123456,greenwitch street,near dominos store,Opp sandwitch company,Neyork,US,876890 123480,Postwitch street,near KFC store,Opp masala company,Newyork,US,876891 123456,Newyork street,near 100th avenue,King master company,Texas,US,10005
在这个例子中,第一行和第三行的起始值(123456)是相同的。我们的目标是删除第三行,因为它的第一个字段与第一行重复。Java Stream API的distinct()方法通常用于删除完全相同的对象或字符串,但对于这种基于部分字段的重复判断则无能为力。
Collectors.toMap()是解决这类问题的强大工具。它允许我们定义如何从流中的每个元素生成一个键(Key),一个值(Value),以及当出现重复键时如何处理(mergeFunction)。
立即学习“Java免费学习笔记(深入)”;
假设我们已经将文本文件的所有行读取到一个List<String>中:
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class DeduplicateTextFile {
public static void main(String[] args) {
List<String> sourceList = List.of(
"123456,greenwitch street,near dominos store,Opp sandwitch company,Neyork,US,876890",
"123480,Postwitch street,near KFC store,Opp masala company,Newyork,US,876891",
"123456,Newyork street,near 100th avenue,King master company,Texas,US,10005"
);
List<String> uniqueList = sourceList.stream()
.collect(Collectors.toMap(
str -> str.substring(0, str.indexOf(',')), // keyMapper: 提取第一个逗号前的子字符串作为键
Function.identity(), // valueMapper: 将整个字符串作为值
(existing, replacement) -> existing // mergeFunction: 如果键重复,保留已存在的(即第一次遇到的)值
))
.values() // 获取Map中所有的值(即唯一的行字符串)
.stream()
.toList(); // 将结果收集到List中
System.out.println("去重后的列表 (字符串):");
uniqueList.forEach(System.out::println);
}
}代码解释:
直接操作字符串在简单场景下是可行的,但当数据结构变得复杂或需要对字段进行更多操作时,引入领域对象(Domain Object)会显著提高代码的可读性、可维护性和健壮性。
我们可以创建一个Company类来封装每行数据。为了简化代码,这里使用Lombok的@Getter和@Builder注解。
import lombok.Builder;
import lombok.Getter;
@Builder
@Getter
public class Company {
private long id;
private String street;
private String locationDescription;
private String companyName;
private String state;
private String country;
private String zipCode;
/**
* 将一行字符串解析为Company对象
* @param line 待解析的字符串
* @return 解析后的Company对象
*/
public static Company parse(String line) {
String[] arr = line.split(",");
if (arr.length < 7) {
throw new IllegalArgumentException("Invalid line format: " + line);
}
return Company.builder()
.id(Long.parseLong(arr[0]))
.street(arr[1]) // 补充street字段
.locationDescription(arr[2])
.companyName(arr[3])
.state(arr[4])
.country(arr[5])
.zipCode(arr[6])
.build();
}
@Override
public String toString() {
return id + "," + street + "," + locationDescription + "," + companyName + "," + state + "," + country + "," + zipCode;
}
}注意:
有了Company类,去重逻辑将更加清晰:
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
// 假设Company类已定义如上
public class DeduplicateWithDomainObject {
public static void main(String[] args) {
List<String> sourceList = List.of(
"123456,greenwitch street,near dominos store,Opp sandwitch company,Neyork,US,876890",
"123480,Postwitch street,near KFC store,Opp masala company,Newyork,US,876891",
"123456,Newyork street,near 100th avenue,King master company,Texas,US,10005"
);
List<Company> uniqueCompanies = sourceList.stream()
.map(Company::parse) // 将每行字符串解析为Company对象
.collect(Collectors.toMap(
Company::getId, // keyMapper: 使用Company对象的id作为键
Function.identity(), // valueMapper: 将Company对象本身作为值
(existing, replacement) -> existing // mergeFunction: 如果id重复,保留已存在的Company对象
))
.values()
.stream()
.toList();
System.out.println("\n去重后的列表 (Company对象):");
uniqueCompanies.forEach(System.out::println);
}
}代码解释:
在实际应用中,sourceList通常是通过读取文件获得的。以下是一个简单的文件读取示例:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
public class FileReaderExample {
public static List<String> readLinesFromFile(String filePath) throws IOException {
return Files.lines(Paths.get(filePath))
.collect(Collectors.toList());
}
public static void main(String[] args) {
String filePath = "data.txt"; // 替换为你的文件路径
// 假设data.txt文件内容如示例所示
try {
List<String> allLines = readLinesFromFile(filePath);
// 接下来可以将allLines传递给上述的去重方法
System.out.println("从文件读取的行数: " + allLines.size());
// ... 进行去重操作
} catch (IOException e) {
System.err.println("读取文件时发生错误: " + e.getMessage());
}
}
}在Company.parse()方法中,Long.parseLong()和line.split(",")都可能抛出异常(如NumberFormatException或ArrayIndexOutOfBoundsException),因此在实际生产代码中,应加入更完善的异常处理机制,例如使用try-catch块捕获并记录错误,或者返回Optional<Company>。
本文介绍了两种在Java中根据特定字段删除文本文件重复行的有效方法。
无论选择哪种方法,Java Stream API都提供了强大且简洁的工具来处理这类数据去重任务。在实际应用中,请根据具体需求和项目复杂性选择最合适的方案,并务必考虑文件I/O和潜在的解析错误处理。
以上就是Java处理文本文件:根据首个字段删除重复行并存储的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号