Java输入校验需用hasNextInt()预判+nextLine()清缓存;自定义RuntimeException细化业务异常;用Optional替代null避免NPE;Spring中@Valid须配BindingResult捕获错误。

Java中用Scanner校验用户输入是否为有效整数
用户输入非数字时,Scanner.nextInt() 会抛出 InputMismatchException,而不是返回默认值或静默失败。直接调用它不做处理,程序会中断——这不是校验,是崩溃。
正确做法是配合 hasNextInt() 预判 + nextLine() 清缓冲区:
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个整数:");
while (!scanner.hasNextInt()) {
System.out.print("输入无效,请输入整数:");
scanner.nextLine(); // 必须清掉非法输入,否则死循环
}
int value = scanner.nextInt();
scanner.close();
-
hasNextInt()只检查,不消费输入;nextInt()才真正读取并移除该token - 漏掉
scanner.nextLine()会导致后续输入被残留字符干扰(比如输了个"a"后,下一次hasNextInt()仍看到"a") - 不要在循环里反复 new Scanner(System.in),标准输入流只需一个实例
自定义异常类封装业务校验逻辑
内置异常如 IllegalArgumentException 虽可用,但无法体现“用户名长度不足”“邮箱格式错误”等具体语义。抛出泛型异常会让上层难以区分处理逻辑。
建议为每类校验定义独立异常,例如:
立即学习“Java免费学习笔记(深入)”;
public class UsernameTooShortException extends RuntimeException {
public UsernameTooShortException(String username) {
super("用户名 '" + username + "' 长度不能少于3位");
}
}
- 继承
RuntimeException可避免强制 try-catch,适合参数校验这类编程期错误 - 构造函数中拼接上下文信息(如原始输入值),比只抛 "用户名太短" 更利于排查
- 不要把校验逻辑和异常定义混在一个方法里;校验失败时明确
throw new UsernameTooShortException(input)
用Optional替代null返回做输入合法性表达
很多初学者习惯让校验方法返回 null 表示失败,比如 parseEmail(String s) 成功返回 Email 对象、失败返回 null。这迫使调用方写一堆 if (email != null),且容易引发 NullPointerException。
改用 Optional 更安全、语义更清晰:
public OptionalparseEmail(String input) { if (input == null || !input.matches("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) { return Optional.empty(); } return Optional.of(new Email(input)); }
- 调用方必须显式处理空值:
parseEmail(s).ifPresentOrElse(this::sendMail, () -> log.warn("邮箱无效")) - 禁止对 Optional 做
.get()直接取值——那和写if (x != null) x.method()没本质区别 - 若校验失败需附带错误原因,用
Optional.empty()不够,此时应抛异常或返回Result(需自行定义)
Spring Boot中@Valid与BindingResult配合处理HTTP表单校验
Web场景下,前端传来的JSON或表单数据,不应在Controller里手写一堆 if (s == null || s.length() 。Spring的声明式校验能自动拦截并返回400响应。
关键点在于:必须紧邻 @Valid 参数后声明 BindingResult,否则校验失败直接抛 MethodArgumentNotValidException(返回500而非400):
@PostMapping("/users")
public ResponseEntity> createUser(@Valid @RequestBody User user, BindingResult result) {
if (result.hasErrors()) {
List errors = result.getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.toList());
return ResponseEntity.badRequest().body(errors);
}
// 正常处理...
}
-
@Valid本身不会阻止方法执行;只有配对BindingResult才能捕获错误 - 实体类字段需加注解,如
@NotBlank(message = "用户名不能为空")、@Min(value = 18, message = "年龄不能小于18") - 若用
@Validated分组校验,BindingResult仍需紧跟其后,顺序不能错










