解析复杂用户输入构建对象树时,使用Exceptions是否合理?
问题
当查阅何时及为何使用Exceptions的相关信息时,不少人(含本平台用户)认为验证用户输入时不应使用异常,因为无效输入属于常见情况。
我当前需解析一段复杂的用户输入字符串,并将其映射为对象树(Object-Tree),工作模式类似解析器。
伪代码示例如下:
input: ---- hello[5] + foo["ok"] ---- results in something like that: class Hello { int id = 5 } class Add {} class foo { string name = 'ok' }
若要验证该输入,我必须执行解析操作;但同时编写验证用解析代码与对象创建代码会显得冗余。
目前我在解析单个token时使用Exceptions来收集所有错误,代码示例如下:
// one token is basically a single try { foreach (token in tokens) { factory = getFactory(token) // throws ParseException addObject(factory.create(token)) // throws ParseException } } catch (ParseException e) { // e.g. "Foo Token expects value to be string" addError(e) }
请问这种用法是否属于不当使用异常?替代方案为在每个工厂中注入验证类或调整返回类型,但这两种方案都不够简洁。
回答
你的这种用法不属于异常的不当使用,理由如下:
解析场景的特殊性:你不是在做普通的表单输入校验,而是执行语法解析——这个过程必须依赖完整的语法分析逻辑,单独编写一套验证代码必然造成冗余。用异常捕获解析过程中的语法、语义错误,契合异常的设计初衷:处理程序执行中意外但可预见的错误场景。
代码简洁性优势:当前方案避免了重复逻辑,不需要给每个工厂注入验证类,也不用修改返回类型来承载错误信息。异常能在解析流程的各个节点自然抛出错误,再统一捕获收集,逻辑连贯清晰。
澄清“无效输入是常见情况”的误区:这个观点适用于普通表单输入,但解析器场景下,合法输入是符合语法规则的,无效输入本质是语法错误,属于程序执行的异常分支,用异常处理完全合理。
如果要优化现有方案,可考虑两点:
- 不要捕获第一个错误就终止解析,继续处理后续token,收集所有错误后返回给用户,提升体验
- 自定义
ParseException时携带token位置、错误类型等上下文信息,方便快速定位问题
内容的提问来源于stack exchange,提问作者gries
相关产品推荐
相关产品推荐

