举个例子,我将假设下面有一个项目,其代码库已经开发了几年。例如,该项目的开发人员首次体验了 Guava,并且该库中的一些选项已经集成到类中。此外,我们的示例项目基于一个服务层,该服务层在其接口中提供并期望可选选项。到目前为止,一切都很好。然而,您很快就会意识到有一个类不仅包含 Guava,还包含 Java 可选值。这个类虽然大大简化了,但可能如下所示:
import com.google.common.base.Optional;
...
public class MixedStyleClass {
private Optional<Device> device;
private java.util.Optional<Configuration> configuration;
public Optional<Device> getDevice() { … }
public void setConfiguration(java.util.Optional<Configuration> config) { … }
}
冗余使用第二个可选类
当谈到使用这两类选项时,有些人可能会感到脖子后面的汗毛都竖起来了。难道你不能通过可选来减少代码吗?然而,由于多种原因,说起来容易做起来难:
更改方法签名和替换接口中的类可能会导致该接口的使用者进行重大自定义。
并非所有导入都可以轻松地从 Guava 更改为 Java,因为这两个类具有不同的方法,并且必须相应地调整代码。
服务层的接口由于依赖于其他项目,不能轻易更改。
通常开发人员根本没有时间来实现它。
在我的项目示例中,我假设服务层中的方法无 手机数据库 法更改,并且更改最初应尽可能小且有限。作为一名开发人员,在决定是否只想在可用时间内替换该类的选项,或者是否要在转换中包含该类的其他使用者时,您可以从自己的经验中受益。但是,当您调用服务层时,您必须相应地映射这两个选项。为了不必一次又一次地重写此映射,您需要适当的方法来双向转换选项。您可以在以下帮助程序类中看到一个示例:
public class Optionals {
public static Optional fromGuavaToJava(com.google.common.base.Optional optional) {
return optional.transform(Optional::of)
.or(Optional.empty());
}
public static com.google.common.base.Optional fromJavaToGuava(Optional optional) {
return optional.map(com.google.common.base.Optional::of)
.orElse(com.google.common.base.Optional.absent());
}
}
用于转换不同可选类的辅助函数
在服务层中调用的返回 Guava 可选的方法将Optionals.fromGuavaToJava(…)使用进行转换。因此,GuavaOption 满足了Optionals.fromJavaToGuava(…)消费者的期望。使用此工具,您现在可以在界面上转换选项。
带有选项的反模式
既然已经阐明了如何在接口处处理可选值,那么代码中仍然需要进行更正,因为并非两个可选值类都提供相同的方法。虽然 Guava 提供了“可选转换”,但在 Java 中该方法称为“map”。例如,这里是fromNullabletoofNullabl或absentto empty。一个优点是只有少数方法具有相同的名称 - 例如get和isPresent。
在此步骤中,您有机会纠正选项的某些反模式 - 不幸的是,它们通常被用作更好的空检查。然而,这并不一定会使代码更具可读性。
public Optional<Integer> getOrderNumber(Optional<Order> previousOrder) {
if (previousOrder.isPresent()) {
return Optional.fromNullable(previousOrder.get().getOrderNumber());
}
return Optional.absent();
}
不必要地使用 isPresent() 和 get()
这是一个很好的例子,向您展示可选选项如何不必要地使代码膨胀。的使用isPresent不必要是口头的。无需经历使用它fromNullable的麻烦absent,而是在转换后使用map:
public Optional<Integer> getOrderNumber(Optional<Order> previousOrder) {
return previousOrder.map(Order::getOrderNumber);
}
map() 的应用
使用map传递的方法对可选值执行 - 如果存在。如果没有,将empty退回一张。您将所需的 getter 作为函数参数传递给类。这样,值就会以可选形式返回。这也使得它变得不必要,四行代码减少为一行,并且代码变得更具可读性:return Optional.absent()
if (previousOrder.isPresent()) {
final Order order = previousOrder.get();
initAddressesFromPreviousOrder(model, order);
}
繁琐地使用不必要的方法
isPresent这里也不需要调用,ifPresent您可以选择直接调用方法。如果previousOrder empty是,则不会执行任何代码。所以你得到:
previousOrder.ifPresent(order → initAddressesFromPreviousOrder(model, order));
ifPresent() 的应用
Java 9中Optional的创新——or方法
Java 9 中的创新为您提供了可选类的附加方法。如果您使用可选值,则之前可以orElse选择orElseGet返回标准值(如果该值是可选值)empty。但是,您丢失了可选选项的上下文,并且如果需要另一个可选选项,则必须使用 再次封装结果Optional.of。对于or(Supplier<? Extends Optional<? Extends T>> supplier)返回 a 的方法来说,这Optional<T>已经成为过去。如果您想进一步深入研究这个主题,我推荐Java Magazine中的文章,其中也有更ifPresentOrElse详细的介绍stream。
正如您所看到的,考虑到 Java 9 带来的创新,JavaOptional 类提供的方法值得一看。
拉蒙·库普弗图片
作者 拉蒙·库普弗
Ramon Küpfer 是 adesso Switzerland 的 Java 软件工程师。他对 Java 9 的变化带来的新鲜空气感到兴奋,试图从过去的错误中吸取教训,让遗留代码比他发现的更好。