如何使用Optional与未使用Optional创建的级联对象 [英] how use Optional with cascaded objects not created with Optional

查看:209
本文介绍了如何使用Optional与未使用Optional创建的级联对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文:我链接了由wsdl2java生成的对象,因此它们都不包含java.util.Optional。有一个已经创建的方法调用soap web服务,接收xml并在级联对象中解组它。



欲望:我想使用Optional以避免null测试。



我已经发布了我的dificults来完成它(如何使用可选和过滤从wsdl2java生成的链式/级联对象中检索对象)但是,之后3天的搜索和阅读我真的卡住了,我意识到我的知识中有一些差距所以我决定退后一步,尝试一个更简单的解决方案,然后继续前进。



<我想知道我是否真的尝试了一些可能做的事情:使用Optional与未使用Optional模式创建的级联对象。我在互联网上找到的大多数例子都使用用private Optional myObj编码的级联对象,或者它们仅限于将Optional.of用于对象,而不是像wsdl2java生成的对象树。



这是我到目前为止试图弄清楚它是否可能而且我也陷入困境:我跟着 http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html 我尝试应用同样的想象这些对象最初是用Java 7编写的(根本没有私有的可选myObj)。



首先,正如Oracle文章所示(从父对子依赖):



USB

  public class USB {

字符串版本;
public USB(){

}
public String getVersion(){
return version;
}
public void setVersion(String version){
this.version = version;
}
}

OptionalSoundcard

 公共类OptionalSoundcard {

private可选< USB> USB;

public OptionalSoundcard(){
// TODO自动生成的构造函数存根
}

public可选< USB> getUsb(){
返回usb;
}

public void setUsb(可选< USB> usb){
this.usb = usb;
}

}

OptionalComputer

  public class OptionalComputer {

private可选< OptionalSoundcard>声卡;

public OptionalComputer(){
}

public可选< OptionalSoundcard> getSoundcard(){
返回声卡;
}

public void setSoundcard(可选< OptionalSoundcard>声卡){
this.soundcard = soundcard;
}

}

以及成功的测试

  @Test 
public void runOptionalClassicOracleExample()抛出异常{

USB usb =新USB ();
usb.setVersion(1);

OptionalSoundcard soundcard = new OptionalSoundcard();
soundcard.setUsb(Optional.ofNullable(usb));

OptionalComputer computer = new OptionalComputer();
computer.setSoundcard(Optional.ofNullable(soundcard));

可选< OptionalComputer> sc = Optional.of(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类与上面相同)



声卡

 公共类声卡{

私人USB usb;

public Soundcard(){
// TODO自动生成的构造函数stub
}

public USB getUsb(){
return usb ;
}

public void setUsb(USB usb){
this.usb = usb;
}

}

计算机

 公共类计算机{

私人声卡声卡;

public Computer(){
// TODO自动生成的构造函数stub
}

public Soundcard getSoundcard(){
return soundcard ;
}

public void setSoundcard(声卡声卡){
this.soundcard = soundcard;
}

}

即使没有' t compile

  @Test 
public void runClassicOracleExample()throws Exception {

USB usb =新USB();
usb.setVersion(2);

Soundcard soundcard = new Soundcard();
soundcard.setUsb(usb);

电脑电脑=新电脑();
computer.setSoundcard(soundcard);

可选<计算机> 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)
- 类型为计算机的getSoundcard()类型为Soundcard,这是与描述符的返回类型不兼容:可选



***已编辑



在现实世界中我有

  NamenOndernemingType 1 X 1 NaamOndernemingLijstCommercieelType 1 X List<> NaamOndernemingType 

我知道所有这三个都会产生相同的结果,除了一个细节:null safety

  //否可选并且所有
都没有map()NaamOndernemingLijstCommercieelType naamOndernemingLijstCommercieel = onderneming.getNamen()
.getCommercieleNamen();
NaamOndernemingType naamOnderneming1 = naamOndernemingLijstCommercieel.getCommercieleNaam()。stream()
.filter(x - > x.getTaalcode()。getValue()==nl)。findFirst()。get() ;

// Optional.ofNullable仅包装列表而flatMap列表
可选< List< NaamOndernemingType>> optionalList =可选
.ofNullable(onderneming.getNamen()。getCommercieleNamen()。getCommercieleNaam());
NaamOndernemingType naamOnderneming2 = optionalList
.flatMap(list - > list.stream()。filter(s - >nl.equals(s.getTaalcode()。getValue()))。findFirst ())。得到();

// Optional.ofNullable on root element并映射所有其他级别,直到获得
//列表和strem()
可选< 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();

***未来读者可能会发现值得阅读
如何使用可选和过滤器从wsdl2java生成的链式/级联对象中检索对象



我的最终解决方案变为:

  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()



因为根据java文件可选#flatMap()


如果存在值,请应用提供的可选 - 承载映射函数到它,返回该结果,否则返回一个空可选。此方法类似 #map(函数)但提供的映射器的结果已经是可选 ,如果被调用, flatMap 不包含额外的可选


flatMap中使用的映射器必须返回 Optional 。我认为 map 会更好地满足您的需求。因为它将结果从 Computer#getSoundcard()包装在一个Optional中。


Context: I have chained objects generated by wsdl2java so none of them contains java.util.Optional. There is an already created method that call the soap web services, receives the xml and unmarshalling it in cascaded objects.

Desire: I want to use Optional in order to avoid null tests.

I have already posted my dificults to accomplish it (how to use optional and filter along to retrieve an object from chained/cascaded objects generated by wsdl2java) but, after 3 days searching and reading I really got stuck and I realised that I have some gap in my knowlodge so I decided take a step back and try a more simple solution before moving forward.

I am wondering if I am really trying something that is possible to do: use Optional with a cascaded objects that weren't created with Optional pattern in mind. Most of the example I found in internet either use cascaded objects coded with "private Optional myObj" or they are limited to use Optional.of to an object, not to a tree of objects like generated by wsdl2java.

Here is what I tried so far to figure out if it is possible and I got stuck as well: I followed http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html and I tryed to apply same idea imagining the objects were coded originally with Java 7 (no private Optional myObj at all).

Firstly, exactly as showed by Oracle article (from parent to child dependency):

USB

public class USB {

    String version;
    public USB() {

    }
    public String getVersion() {
        return version;
    }
    public void setVersion(String version) {
        this.version = version;
    }
}

OptionalSoundcard

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;
    }

}

OptionalComputer

public class OptionalComputer {

    private Optional<OptionalSoundcard> soundcard;  

    public OptionalComputer() {
    }

    public Optional<OptionalSoundcard> getSoundcard() {
        return soundcard;
    }

    public void setSoundcard(Optional<OptionalSoundcard> soundcard) {
        this.soundcard = soundcard;
    }

}

And the well-successed test

@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")));

}

Now, imagine same Computer and Soundcar created with Java 7 pattern in mind (USB class is the same as above)

Soundcard

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;
    }

}

Computer

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;
    }

}

And the test that even doesn't compile

@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")));
}

The error is:

The method flatMap(Function>) in the type Optional is not applicable for the arguments (Computer::getSoundcard) - The type of getSoundcard() from the type Computer is Soundcard, this is incompatible with the descriptor's return type: Optional

*** edited

in real world I have

NamenOndernemingType 1 X 1 NaamOndernemingLijstCommercieelType 1 X List<> NaamOndernemingType

I understand that all these three will produce the same results, except for one detail: 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();

*** Future readers may find worth to read how to use optional and filter along to retrieve an object from chained/cascaded objects generated by wsdl2java

My final solution become:

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()));

解决方案

Why not just use .map()?

Because according to java doc of Optional#flatMap():

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.

The mapper used in flatMap must return an Optional. I think map will suit your needs better. because it wraps the result from Computer#getSoundcard() in an Optional.

这篇关于如何使用Optional与未使用Optional创建的级联对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆