如何用Java 8函数式风格改写仅变量类型不同的两段代码?
用函数式风格统一不同类型Optional的分支逻辑
这问题我之前也碰到过,核心就是利用Optional的方法链特性,绕开Long和UUID没有共同接口的限制,同时把嵌套的if-else改写成简洁的函数式代码。
解决方案(Java 9+)
直接用flatMap、or和orElseThrow串联逻辑,一行代码搞定:
String id = entity.legacyIndicator() .flatMap(__ -> entity.legacyId().map(Object::toString)) .or(() -> entity.newId().map(Object::toString)) .orElseThrow(() -> new IOException("No ID found."));
代码拆解说明
处理legacy分支:
entity.legacyIndicator().flatMap(__ -> entity.legacyId().map(Object::toString))- 如果
legacyIndicator存在,就尝试获取legacyId(Optional<Long>),通过Object::toString把Long转成String,得到Optional<String>。 - 用
flatMap而不是map,是为了避免出现Optional<Optional<String>>的嵌套结构,直接把结果扁平化。 - 如果
legacyIndicator不存在,这部分会返回空的Optional。
- 如果
切换到new分支:
.or(() -> entity.newId().map(Object::toString))- 当前面的
Optional为空(也就是legacyIndicator不存在),就执行这个分支:获取newId(Optional<UUID>),同样用Object::toString转成String,得到Optional<String>。 - Java 9新增的
or方法接收一个Supplier<Optional<T>>,完美适配分支切换的场景。
- 当前面的
统一异常处理:
.orElseThrow(() -> new IOException("No ID found."))- 如果两个分支的ID都不存在(最终
Optional为空),就抛出指定异常;否则返回转换后的ID字符串。 - 这一步把原来两个分支里重复的throw逻辑统一起来,符合DRY原则。
- 如果两个分支的ID都不存在(最终
Java 8兼容版本
如果还在使用Java 8(没有or方法),可以用orElseGet替代:
String id = entity.legacyIndicator() .flatMap(__ -> entity.legacyId().map(Object::toString)) .orElseGet(() -> entity.newId().map(Object::toString)) .orElseThrow(() -> new IOException("No ID found."));
这里orElseGet会在前面的Optional为空时,返回newId转换后的Optional<String>,后续逻辑和Java 9版本一致。
为什么能解决类型差异问题?
虽然Long和UUID没有实现共同接口,但它们都继承自Object,而Object本身就有toString()方法。我们用Object::toString这个方法引用,就能统一处理两种类型的转换,完全不需要额外定义接口或者包装类。
内容的提问来源于stack exchange,提问作者Andrew Cheong
相关产品推荐
相关产品推荐

