如何将 Optional 与不是使用 Optional 创建的级联对象一起使用
how use Optional with cascaded objects not created with Optional
上下文:我已经链接了由 wsdl2java 生成的对象,因此 none 其中包含 java.util.Optional。有一个已经创建的调用 soap 网络服务的方法,接收 xml 并在级联对象中解组它。
愿望:我想使用 Optional 以避免空测试。
我已经发布了完成它的困难 () 但是,经过 3 天的搜索和阅读,我真的被卡住了,我意识到我的知识还存在一些差距,所以我决定迈出一步返回并尝试更简单的解决方案,然后再继续。
我想知道我是否真的在尝试可能做的事情:将 Optional 与级联对象一起使用,这些对象不是在考虑 Optional 模式的情况下创建的。我在互联网上找到的大多数示例要么使用用 "private Optional myObj" 编码的级联对象,要么仅限于对对象使用 Optional.of,而不是像 wsdl2java 生成的对象树。
到目前为止,这是我试图弄清楚是否可行的方法,但我也被卡住了:我遵循了 http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html 并且我尝试应用相同的想法,想象对象最初是用 [=68 编码的=] 7(根本没有 private Optional myObj)。
首先,完全如 Oracle 文章所示(从父到子依赖):
USB
public class USB {
String version;
public USB() {
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
可选声卡
public class OptionalSoundcard {
private Optional<USB> usb;
public OptionalSoundcard() {
// TODO Auto-generated constructor stub
}
public Optional<USB> getUsb() {
return usb;
}
public void setUsb(Optional<USB> usb) {
this.usb = usb;
}
}
可选计算机
public class OptionalComputer {
private Optional<OptionalSoundcard> soundcard;
public OptionalComputer() {
}
public Optional<OptionalSoundcard> getSoundcard() {
return soundcard;
}
public void setSoundcard(Optional<OptionalSoundcard> soundcard) {
this.soundcard = soundcard;
}
}
测试成功
@Test
public void runOptionalClassicOracleExample() throws Exception {
USB usb = new USB();
usb.setVersion("1");
OptionalSoundcard soundcard = new OptionalSoundcard();
soundcard.setUsb(Optional.ofNullable(usb));
OptionalComputer computer = new OptionalComputer();
computer.setSoundcard(Optional.ofNullable(soundcard));
Optional<OptionalComputer> sc = Optional.of(computer);
// Optional<Computer> sc = Optional.ofNullable(computer);
String v1 = sc.flatMap(OptionalComputer::getSoundcard).flatMap(OptionalSoundcard::getUsb).map(USB::getVersion)
.orElse("UNKNOWN");
assertThat(v1, is(equalTo("1")));
}
现在,想象一下用 Java 7 模式创建的同一台计算机和 Soundcar(USB class 与上面相同)
声卡
public class Soundcard {
private USB usb;
public Soundcard() {
// TODO Auto-generated constructor stub
}
public USB getUsb() {
return usb;
}
public void setUsb(USB usb) {
this.usb = usb;
}
}
计算机
public class Computer {
private Soundcard soundcard;
public Computer() {
// TODO Auto-generated constructor stub
}
public Soundcard getSoundcard() {
return soundcard;
}
public void setSoundcard(Soundcard soundcard) {
this.soundcard = soundcard;
}
}
还有连编译都不通过的测试
@Test
public void runClassicOracleExample() throws Exception {
USB usb = new USB();
usb.setVersion("2");
Soundcard soundcard = new Soundcard();
soundcard.setUsb(usb);
Computer computer = new Computer();
computer.setSoundcard(soundcard);
Optional<Computer> sc = Optional.ofNullable(computer);
String v1 = sc.flatMap(Computer::getSoundcard).flatMap(Soundcard::getUsb).map(USB::getVersion)
.orElse("UNKNOWN");
assertThat(v1, is(equalTo("2")));
}
错误是:
可选类型中的方法 flatMap(Function>) 不适用于参数
(计算机::获取声卡)
- Computer 类型的 getSoundcard() 类型是 Soundcard,这与描述符的 return 类型不兼容:Optional
*** 已编辑
在现实世界中我有
NamenOndernemingType 1 X 1 NaamOndernemingLijstCommercieelType 1 X List<> NaamOndernemingType
我知道所有这三个都会产生相同的结果,除了一个细节:null safety
// no Optional at all and no map() at all
NaamOndernemingLijstCommercieelType naamOndernemingLijstCommercieel = onderneming.getNamen()
.getCommercieleNamen();
NaamOndernemingType naamOnderneming1 = naamOndernemingLijstCommercieel.getCommercieleNaam().stream()
.filter(x -> x.getTaalcode().getValue() == "nl").findFirst().get();
// Optional.ofNullable wrapped only the list and flatMap the list
Optional<List<NaamOndernemingType>> optionalList = Optional
.ofNullable(onderneming.getNamen().getCommercieleNamen().getCommercieleNaam());
NaamOndernemingType naamOnderneming2 = optionalList
.flatMap(list -> list.stream().filter(s -> "nl".equals(s.getTaalcode().getValue())).findFirst()).get();
// Optional.ofNUllable on root element and map all other "levels" until get the
// list and strem()
Optional<NamenOndernemingType> optionalNamenOnderneming = Optional.ofNullable(onderneming.getNamen());
NaamOndernemingType naamOnderneminge = optionalNamenOnderneming.map(NamenOndernemingType::getCommercieleNamen)
.map(NaamOndernemingLijstCommercieelType::getCommercieleNaam).get().stream().filter(Objects::nonNull)
.filter(x -> x.getTaalcode().getValue() == "nl").findFirst().get();
*** 未来的读者可能会发现值得一读
我的最终解决方案变成:
Optional.ofNullable(onderneming.getNamen()).map(NamenOndernemingType::getCommercieleNamen)
.map(NaamOndernemingLijstCommercieelType::getCommercieleNaam).get().stream().filter(Objects::nonNull)
.filter(x -> x.getTaalcode().getValue() == "nl").findFirst()
.ifPresent(o -> myMethod("onderneming_commerciele_naam", o.getNaam().getValue()));
为什么不直接使用 .map()
?
因为根据 Optional#flatMap()
的 java 文档:
If a value is present, apply the provided Optional
-bearing mapping function to it, return that result, otherwise return an empty Optional
. This method is similar to #map(Function)
, but the provided mapper is one whose result is already an Optional
, and if invoked, flatMap
does not wrap it with an additional Optional
.
flatMap 中使用的映射器必须 return 和 Optional
。我认为 map
更适合您的需求。因为它将 Computer#getSoundcard()
的结果包装在 Optional.
中
上下文:我已经链接了由 wsdl2java 生成的对象,因此 none 其中包含 java.util.Optional。有一个已经创建的调用 soap 网络服务的方法,接收 xml 并在级联对象中解组它。
愿望:我想使用 Optional 以避免空测试。
我已经发布了完成它的困难 (
我想知道我是否真的在尝试可能做的事情:将 Optional 与级联对象一起使用,这些对象不是在考虑 Optional 模式的情况下创建的。我在互联网上找到的大多数示例要么使用用 "private Optional myObj" 编码的级联对象,要么仅限于对对象使用 Optional.of,而不是像 wsdl2java 生成的对象树。
到目前为止,这是我试图弄清楚是否可行的方法,但我也被卡住了:我遵循了 http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html 并且我尝试应用相同的想法,想象对象最初是用 [=68 编码的=] 7(根本没有 private Optional myObj)。
首先,完全如 Oracle 文章所示(从父到子依赖):
USB
public class USB {
String version;
public USB() {
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
}
可选声卡
public class OptionalSoundcard {
private Optional<USB> usb;
public OptionalSoundcard() {
// TODO Auto-generated constructor stub
}
public Optional<USB> getUsb() {
return usb;
}
public void setUsb(Optional<USB> usb) {
this.usb = usb;
}
}
可选计算机
public class OptionalComputer {
private Optional<OptionalSoundcard> soundcard;
public OptionalComputer() {
}
public Optional<OptionalSoundcard> getSoundcard() {
return soundcard;
}
public void setSoundcard(Optional<OptionalSoundcard> soundcard) {
this.soundcard = soundcard;
}
}
测试成功
@Test
public void runOptionalClassicOracleExample() throws Exception {
USB usb = new USB();
usb.setVersion("1");
OptionalSoundcard soundcard = new OptionalSoundcard();
soundcard.setUsb(Optional.ofNullable(usb));
OptionalComputer computer = new OptionalComputer();
computer.setSoundcard(Optional.ofNullable(soundcard));
Optional<OptionalComputer> sc = Optional.of(computer);
// Optional<Computer> sc = Optional.ofNullable(computer);
String v1 = sc.flatMap(OptionalComputer::getSoundcard).flatMap(OptionalSoundcard::getUsb).map(USB::getVersion)
.orElse("UNKNOWN");
assertThat(v1, is(equalTo("1")));
}
现在,想象一下用 Java 7 模式创建的同一台计算机和 Soundcar(USB class 与上面相同)
声卡
public class Soundcard {
private USB usb;
public Soundcard() {
// TODO Auto-generated constructor stub
}
public USB getUsb() {
return usb;
}
public void setUsb(USB usb) {
this.usb = usb;
}
}
计算机
public class Computer {
private Soundcard soundcard;
public Computer() {
// TODO Auto-generated constructor stub
}
public Soundcard getSoundcard() {
return soundcard;
}
public void setSoundcard(Soundcard soundcard) {
this.soundcard = soundcard;
}
}
还有连编译都不通过的测试
@Test
public void runClassicOracleExample() throws Exception {
USB usb = new USB();
usb.setVersion("2");
Soundcard soundcard = new Soundcard();
soundcard.setUsb(usb);
Computer computer = new Computer();
computer.setSoundcard(soundcard);
Optional<Computer> sc = Optional.ofNullable(computer);
String v1 = sc.flatMap(Computer::getSoundcard).flatMap(Soundcard::getUsb).map(USB::getVersion)
.orElse("UNKNOWN");
assertThat(v1, is(equalTo("2")));
}
错误是:
可选类型中的方法 flatMap(Function>) 不适用于参数 (计算机::获取声卡) - Computer 类型的 getSoundcard() 类型是 Soundcard,这与描述符的 return 类型不兼容:Optional
*** 已编辑
在现实世界中我有
NamenOndernemingType 1 X 1 NaamOndernemingLijstCommercieelType 1 X List<> NaamOndernemingType
我知道所有这三个都会产生相同的结果,除了一个细节:null safety
// no Optional at all and no map() at all
NaamOndernemingLijstCommercieelType naamOndernemingLijstCommercieel = onderneming.getNamen()
.getCommercieleNamen();
NaamOndernemingType naamOnderneming1 = naamOndernemingLijstCommercieel.getCommercieleNaam().stream()
.filter(x -> x.getTaalcode().getValue() == "nl").findFirst().get();
// Optional.ofNullable wrapped only the list and flatMap the list
Optional<List<NaamOndernemingType>> optionalList = Optional
.ofNullable(onderneming.getNamen().getCommercieleNamen().getCommercieleNaam());
NaamOndernemingType naamOnderneming2 = optionalList
.flatMap(list -> list.stream().filter(s -> "nl".equals(s.getTaalcode().getValue())).findFirst()).get();
// Optional.ofNUllable on root element and map all other "levels" until get the
// list and strem()
Optional<NamenOndernemingType> optionalNamenOnderneming = Optional.ofNullable(onderneming.getNamen());
NaamOndernemingType naamOnderneminge = optionalNamenOnderneming.map(NamenOndernemingType::getCommercieleNamen)
.map(NaamOndernemingLijstCommercieelType::getCommercieleNaam).get().stream().filter(Objects::nonNull)
.filter(x -> x.getTaalcode().getValue() == "nl").findFirst().get();
*** 未来的读者可能会发现值得一读
我的最终解决方案变成:
Optional.ofNullable(onderneming.getNamen()).map(NamenOndernemingType::getCommercieleNamen)
.map(NaamOndernemingLijstCommercieelType::getCommercieleNaam).get().stream().filter(Objects::nonNull)
.filter(x -> x.getTaalcode().getValue() == "nl").findFirst()
.ifPresent(o -> myMethod("onderneming_commerciele_naam", o.getNaam().getValue()));
为什么不直接使用 .map()
?
因为根据 Optional#flatMap()
的 java 文档:
If a value is present, apply the provided
Optional
-bearing mapping function to it, return that result, otherwise return an emptyOptional
. This method is similar to#map(Function)
, but the provided mapper is one whose result is already anOptional
, and if invoked,flatMap
does not wrap it with an additionalOptional
.
flatMap 中使用的映射器必须 return 和 Optional
。我认为 map
更适合您的需求。因为它将 Computer#getSoundcard()
的结果包装在 Optional.