本文目录导读:

- 核心思路与常用库
- 案例一:使用 Stream API 清洗内存中的数据(去空、去重、过滤)
- 案例二:使用正则表达式清洗文本格式(手机号、身份证、邮箱)
- 案例三:清洗 CSV 文件(读取 → 清洗 → 写出)
- 案例四:复杂清洗 — 填充缺失值与异常值
- 案例五:使用 Apache Commons Lang 处理字符串清洗
- 总结与最佳实践
Java中实现数据清洗通常涉及对原始数据进行过滤、转换、去重、填充缺失值、格式标准化等操作,数据清洗是数据预处理的关键步骤,通常在大数据分析、ETL(数据抽取、转换、加载)或数据迁移项目中使用。
下面我将通过几个典型的 Java 案例,展示如何实现常见的数据清洗任务。
核心思路与常用库
在 Java 中实现数据清洗,主要依赖以下几种方式:
- 纯 Java + 集合框架:适合中小规模数据,使用
List、Map、Stream API进行过滤和映射。 - 正则表达式:用于清洗文本格式(如电话号码、邮箱、身份证)。
- Apache Commons Lang / BeanUtils:处理字符串、Bean属性。
- OpenCSV / Apache POI:读取 CSV、Excel 文件进行清洗。
- Java 8+ Stream API:链式操作,简洁高效。
使用 Stream API 清洗内存中的数据(去空、去重、过滤)
假设我们从用户注册日志中获取了一个用户列表,需要清洗掉无效数据。
import java.util.*;
import java.util.stream.*;
public class StreamCleanExample {
public static void main(String[] args) {
// 模拟脏数据:包含 null、空字符串、重复、非法年龄
List<User> rawUsers = Arrays.asList(
new User("Alice", 25, "alice@example.com"),
new User("Bob", -5, "bob@test"), // 年龄非法
new User("", 30, ""), // 姓名为空
new User("Charlie", null, null), // 年龄为null,邮箱为null
new User("Alice", 25, "alice@example.com"), // 重复
new User("David", 150, "david@example.com") // 年龄过大
);
// 清洗逻辑:年龄在0-120之间,姓名非空,邮箱非空且格式简单校验
List<User> cleanedUsers = rawUsers.stream()
.filter(Objects::nonNull) // 过滤null
.filter(u -> u.getName() != null && !u.getName().trim().isEmpty()) // 姓名非空
.filter(u -> u.getAge() != null && u.getAge() >= 0 && u.getAge() <= 120) // 年龄合法
.filter(u -> u.getEmail() != null && u.getEmail().contains("@")) // 邮箱包含@
.distinct() // 去重(需重写equals/hashCode)
.collect(Collectors.toList());
System.out.println("清洗前数量: " + rawUsers.size());
System.out.println("清洗后数量: " + cleanedUsers.size());
cleanedUsers.forEach(System.out::println);
}
}
class User {
private String name;
private Integer age;
private String email;
public User(String name, Integer age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
// getter / setter / equals / hashCode / toString 省略
}
关键点:
distinct()依赖equals()/hashCode(),如果User未重写则无法正确去重(默认比较对象引用)。- 使用
filter()链式过滤规则。
使用正则表达式清洗文本格式(手机号、身份证、邮箱)
通常用于从非结构化文本或CSV字段中提取/验证数据。
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.List;
public class RegexCleanExample {
// 预编译正则
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
public static void main(String[] args) {
List<String> rawData = new ArrayList<>();
rawData.add("13800138000"); // 正确
rawData.add("123456"); // 太短
rawData.add("abc@def"); // 无域名后缀
rawData.add("test@example.com"); // 正确
rawData.add(" 13800138001 "); // 含空格
rawData.add(null); // null
List<String> cleaned = new ArrayList<>();
for (String data : rawData) {
if (data == null) continue;
String trimmed = data.trim();
// 判断是手机号还是邮箱
if (PHONE_PATTERN.matcher(trimmed).matches() || EMAIL_PATTERN.matcher(trimmed).matches()) {
cleaned.add(trimmed);
}
}
System.out.println("清洗后有效数据: " + cleaned);
}
}
常见清洗模式:
- 空格清理:
str.trim()或str.replaceAll("[\\s]+", "") - 特殊符号:
str.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5]", "")(保留中文) - 统一大小写:
str.toLowerCase()
清洗 CSV 文件(读取 → 清洗 → 写出)
使用 OpenCSV 进行文件级清洗是非常常见的场景。
Maven 依赖:
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.8</version>
</dependency>
代码示例:
import com.opencsv.*;
import java.io.*;
import java.util.*;
public class CsvCleanExample {
public static void main(String[] args) throws Exception {
String inputFile = "data.csv";
String outputFile = "cleaned_data.csv";
try (
Reader reader = new FileReader(inputFile);
Writer writer = new FileWriter(outputFile);
CSVReader csvReader = new CSVReaderBuilder(reader).withSkipLines(1).build(); // 跳过标题头
CSVWriter csvWriter = new CSVWriterBuilder(writer).build()
) {
String[] line;
// 写标题头
csvWriter.writeNext(new String[]{"姓名", "年龄", "邮箱", "手机号"});
while ((line = csvReader.readNext()) != null) {
if (line.length < 4) continue; // 字段不足
String name = line[0].trim();
String ageStr = line[1].trim();
String email = line[2].trim();
String phone = line[3].trim();
// 规则清洗
if (name.isEmpty()) continue;
int age;
try {
age = Integer.parseInt(ageStr);
if (age < 0 || age > 120) continue;
} catch (NumberFormatException e) {
continue; // 年龄非数字
}
if (!email.contains("@")) continue;
if (!phone.matches("^1[3-9]\\d{9}$")) continue;
csvWriter.writeNext(new String[]{name, String.valueOf(age), email, phone});
}
}
System.out.println("清洗完成,输出至: " + outputFile);
}
}
复杂清洗 — 填充缺失值与异常值
通常用于数值型数据(如传感器数据、销售数据)。
import java.util.*;
import java.util.stream.*;
public class FillMissingExample {
public static void main(String[] args) {
List<Double> readings = Arrays.asList(23.5, null, 25.0, null, -999.0, 24.0, null);
// 统计有效值的均值(忽略异常值 -999)
double sum = 0;
long count = 0;
for (Double v : readings) {
if (v != null && v != -999.0) {
sum += v;
count++;
}
}
double mean = count > 0 ? sum / count : 0;
// 清洗:null 或 -999 替换为均值
List<Double> cleaned = readings.stream()
.map(v -> {
if (v == null || v == -999.0) {
return mean;
}
return v;
})
.collect(Collectors.toList());
System.out.println("原始: " + readings);
System.out.println("清洗后: " + cleaned);
System.out.println("填充均值: " + mean);
}
}
使用 Apache Commons Lang 处理字符串清洗
import org.apache.commons.lang3.StringUtils;
public class StringCleanExample {
public static void main(String[] args) {
String raw = " Hello, World!! ";
// 常用清洗
String cleaned = raw
.trim()
.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5 ]", "") // 只保留中文、英文、数字、空格
.replaceAll("\\s+", " "); // 多个空格合并为一个
System.out.println("'" + cleaned + "'");
// 判断空
if (StringUtils.isBlank(cleaned)) {
System.out.println("数据为空");
}
}
}
总结与最佳实践
| 场景 | 推荐技术 |
|---|---|
| 内存中小批量数据 | Java 8+ Stream API + 正则 |
| 文件(CSV/Excel) | OpenCSV / Apache POI + 流式处理 |
| 大数据量(千万+) | Apache Spark / Flink(Java API),并行清洗 |
| 实时数据流 | Apache Flink / Kafka Streams |
| 数据质量规则引擎 | 使用策略模式 + Drools 规则引擎 |
Java 数据清洗的通用步骤:
- 解析:读取原始数据(文件、数据库、消息队列)。
- 过滤:剔除 null、空值、非法记录。
- 转换:统一格式(日期、大小写、编码)、去除空格、替换异常值。
- 验证:正则校验(手机号、邮箱)、范围校验(年龄0-120)。
- 去重:基于业务主键或 equals/hashCode。
- 写出:输出到清洗后的目标存储。
如果你有具体的场景(如清洗特定的日志格式、金融交易数据),可以提供更多细节,我可以帮你定制更精确的实现方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播