从包装在Java可选文件中的对象提取多个字段

从包装在Java可选文件中的对象提取多个字段,java,optional,Java,Optional,这个问题类似于Java而不是Scala 假设我有一个返回可选值的方法。 我需要从包装的地址中提取多个字段,例如getCity(),getCountry(),和getZIP()。如果地址不存在,则应使用一些默认值。然后,逻辑应继续处理结果值 问题是这样做的最佳和最惯用的方式是什么。我可以想到以下三点: 1)如果有其他情况 城市; 国家; 拉链; 可选的optAddr=getAddress(); if(optAddr.isPresent()){ 地址addr=optAddr.get(); city=

这个问题类似于Java而不是Scala

假设我有一个返回
可选值的方法。
我需要从包装的地址中提取多个字段,例如
getCity()
getCountry()
,和
getZIP()
。如果地址不存在,则应使用一些默认值。然后,逻辑应继续处理结果值

问题是这样做的最佳和最惯用的方式是什么。我可以想到以下三点:

1)如果有其他情况

城市;
国家;
拉链;
可选的optAddr=getAddress();
if(optAddr.isPresent()){
地址addr=optAddr.get();
city=addr.getCity();
country=addr.getCountry();
zip=addr.getZIP();
}
否则{
城市=空;
country=country.getUSA();
zip=zip.DEFAULT;
}
// ... 使用城市、国家和邮政编码
优点:

  • 没有创建额外的对象-最有效的变体
  • 默认情况分组在一起
缺点:

  • 冗长的
2)多条链

可选optAddr=getAddress();
City-City=optAddr.map(地址::getCity()
.orElse(空);
Country Country=optAddr.map(地址::getCountry)
.orElseGet(国家:getUSA);
ZIP=optAddr.map(地址::getZIP)
.orElse(ZIP.DEFAULT);
//…使用城市、国家和邮政编码
请注意,这里的逻辑略有不同,因为默认值不仅在缺少地址时适用,而且在相应的地址字段为
null
时也适用

但这不是我的问题

优点:

  • 简洁
  • 变量立即初始化为一个值
  • 更接近于如何使用单个字段完成
缺点:

  • 默认值是分散的
  • map
    的链式调用可能会创建中间对象(但以惯用的方式)
  • 可能在单个
    可选
    上使用多条链
3a)将默认值包装到对象中

专用地址createDefaultAddress(){
地址addr=新地址();
地址设置城市(空);
地址setCountry(Country.getUSA());
addr.setZIP(ZIP.DEFAULT);
返回地址;
}
地址addr=getAddress().orelsGet(this::createDefaultAddress);
City-City=addr.getCity();
Country Country=addr.getCountry();
ZIP=addr.getZIP();
// ... 使用城市、国家和邮政编码
优点:

  • 清晰
缺点:

  • 字段被打包到一个
    地址中
    ,仅用于随后立即提取它们
3b)将默认值包装为常量

正如@HariMenon和@flakes所建议的那样,具有默认值的an
地址可以存储在常量中,并在每次调用中重复使用,以减少开销

还可以延迟初始化该“常量”:

私有地址默认地址;
私有地址getDefaultAddress(){
if(defaultAddress==null){
defaultAddress=新地址();
defaultAddress.setCity(空);
defaultAddress.setCountry(Country.getUSA());
defaultAddress.setZIP(ZIP.DEFAULT);
}
返回默认地址;
}
地址addr=getAddress().orelsGet(this::getDefaultAddress);
// ... 与3.1相同
奖金问题:

假设我完全控制
getAddress()
方法,并且我知道所有用法都与本例类似,但默认值不同。
我是否应该将其更改为返回
null
而不是
可选
,以更好地适应
if else
解决方案?

这有点主观,因此不会有正确的答案。但这是我的2美分,以及我为什么这么认为。选项1绝对不是Java8的惯用方法

在2和3之间,您将选择什么取决于您是希望使用默认地址,还是希望使用单独的默认城市、国家和邮政编码。如果地址不为空,但城市为空,是否仍要使用默认城市?选择3会让事情变得丑陋。否则,我倾向于选择3。即使您将其包装到一个对象中,该对象也可以是一个名为DEFAULT_ADDRESS的常量,然后它会变得非常清楚它到底是什么,因此更具可读性

选项2使它看起来就像您有一个单独的默认国家、城市和邮政编码,而事实似乎并非如此。但是就像我说的,如果是这样的话,你应该用它

编辑3b和奖金: 若您正在考虑包装器对性能的影响,那个么您就想得太多了。在Java中创建这样的包装器非常便宜,而现代JIT编译器在大多数情况下都能很好地优化这一点。可读性优于性能,除非通过测量证明代码是性能瓶颈。对于可选vs null,只需选择一种编码样式并在项目中使用它

如果您正在返回Optionals,那么请确保该方法从不返回null(可以同时返回Optional和null的方法是令人讨厌的)。许多人认为您应该始终使用
Optional
s。就我个人而言,我有点不同意。如果它是一个新的代码库,并且我们在任何地方都使用Optionals,那么它就很棒了。坚持使用它,不要在任何地方使用null和null检查。如果它是一个已经在多个位置使用null的旧代码库,那么只需使用null并记录该方法在某些情况下可以返回null。将可选项和空项组合在一起会造成可怕的混乱,我认为可选项的好处不足以超过成本。Optionals在从一开始就支持它们的语言中非常好。但他们
private static final Address DEFAULT_ADDRESS = new Address() {{
    setCity(null);
    setCountry(Country.getUSA());
    setZIP(ZIP.DEFAULT);
}};
...
Address addr = getAddress().orElse(DEFAULT_ADDRESS);