Java中如何为无共同接口两类提取switch重复通用函数
泛型化实现通用非空校验逻辑
问题根源
IntelliJ 自动提取代码段的默认逻辑是基于当前上下文的具体类型做硬编码,提取时只会识别当前选中代码的Form类型,把签名写死为Function<Form, Form>,没有自动推导抽象为泛型,自然无法兼容Note类型。
而你这段重复逻辑本身的能力边界非常清晰:
- 接收任意类型的入参
- 判断入参是否为null,是则抛出指定异常
- 校验通过则原样返回入参,全程不需要访问入参的任何方法、字段
这种逻辑根本不依赖两个类的共同接口,只需要把签名改成支持任意泛型T,就能做到类型安全的通用兼容。
重构实现
第一步:定义泛型通用校验函数
直接利用Java泛型的类型推断能力,把硬编码的Form替换为任意泛型T:
/** * 通用非空校验:对象为null则抛出指定异常,否则原样返回 * @param exceptionSupplier 空值时抛出的异常的获取方法 * @param <T> 任意入参、出参类型,类型保持一致 */ private static <T> Function<T, T> requireNonNullOrThrow(Supplier<RuntimeException> exceptionSupplier) { return obj -> { if (obj == null) { throw exceptionSupplier.get(); } return obj; }; }
第二步:替换原有重复逻辑
替换后switch分支的代码会大幅简化,且完全保留原有业务逻辑:
case "form" -> handleProvider.withHandle(handle -> handle.attach(FormDao.class).findFormById(id)) // 编译器会自动推断T为Form类型 .thenApply(requireNonNullOrThrow(() -> exceptionIfNotFound)) .thenApply(obj -> obj.exportedDocument); case "note" -> handleProvider.withHandle(handle -> handle.attach(NoteDao.class).findNoteById(id)) // 编译器会自动推断T为Note类型 .thenApply(requireNonNullOrThrow(() -> exceptionIfNotFound));
方案优势
- 不需要Form、Note类实现任何共同接口,因为校验逻辑全程不感知T的具体类型
- Java编译器会在
thenApply的调用点,根据上游CompletableFuture的返回类型自动推导T的具体值,不需要手动写泛型参数 - 没有类型擦除带来的unchecked警告,全程类型安全
- 后续新增其他业务对象的分支时,直接复用这个校验函数即可,不需要重复写判空逻辑
注:如果你的
exceptionIfNotFound是提前定义好的异常Supplier,不需要每次传参,也可以把函数定义为类级别的静态常量,但注意这种写法会因为类型擦除带来少量编译警告,优先用上面的泛型方法写法最稳妥。
内容的提问来源于stack exchange,提问作者oligofren
相关产品推荐
相关产品推荐

