自定义异常是脏数据的结构化信封,需封装原始数据快照、字段名与值、错误类型枚举、来源标识,并在清洗各环节主动抛出、批量收集、分级响应、关联原始记录。

在数据清洗过程中,用自定义异常来记录脏数据,核心不是“抛出就完事”,而是让异常成为一种结构化、可追溯、可分类的脏数据载体。它要能说清三点:哪条数据错了、为什么错、错在哪个环节。Java 本身不强制要求异常必须被处理,但清洗场景下,你得主动捕获、解析、落库或写日志,否则异常一抛就飞了,脏数据反而丢了。
设计带业务语义的自定义异常类
别继承 RuntimeException 就完事。要封装关键上下文:
-
原始数据快照:比如一行 CSV 字符串、一个 JSON 字符串、或一个 Map
记录,避免异常抛出后找不到原始输入 - 字段名与值:指出是 “phone” 字段值为 “11111111111”,而不是笼统说“手机号非法”
-
错误类型枚举:定义如
DirtType.MISSING、DirtType.FORMAT_INVALID、DirtType.OUT_OF_RANGE、DirtType.SEMANTIC_PLACEHOLDER(对应“9999999999”这类语义标记),方便后续按类型统计或分流 - 来源标识:加上文件名、行号、批次 ID 或 traceId,便于定位问题源头
在清洗逻辑中主动抛出并捕获
不要等 NPE 或 NumberFormatException 再兜底。要在校验点主动判断、主动抛出:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 读取 Excel 行时,检查手机号列是否为空或为 “11111111”,符合即 new DirtyDataException("phone", value, DirtType.SEMANTIC_PLACEHOLDER, "user_import.xlsx", rowNo)
- 解析时间字段失败时,不直接 try-catch 吞掉,而是 catch ParseException 后包装成 DirtyDataException,并带上原始字符串和字段名
- 在 Stream API 清洗链中,用
flatMap包装解析逻辑:合法则返回单元素流,非法则Stream.of(new DirtyDataException(...)),再统一收集到 errorList
集中处理异常,落地为可观测的脏数据
抛出只是开始,关键在怎么收口:
-
批量收集:用 List
缓存本轮清洗中所有异常,清洗结束后统一输出为 CSV 或插入 dirty_data_log表(含字段、原始值、错误类型、时间、操作人) -
分级响应:对
DirtType.SEMANTIC_PLACEHOLDER类异常,可记日志但不中断流程;对DirtType.MALFORMED_JSON,则终止当前批次并告警 - 关联原始记录:确保每条异常记录都能反查到 raw_logs.id 或 file_offset,避免“知道错了,但找不到是哪条”
本质上,自定义异常在这里不是错误信号灯,而是脏数据的标准化信封——它把杂乱的“问题描述”变成结构化的“数据事实”,后续做质量报告、修复回溯、规则优化才有据可依。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










