Is there an elegant way to get the first non null value of multiple method returns in Java?

前端 未结 3 756
南方客
南方客 2021-02-08 10:06

You have already seen this many times yourself, of that I\'m sure:

public SomeObject findSomeObject(Arguments args) {
    SomeObject so = queryFirstSource(args);         


        
3条回答
  •  我在风中等你
    2021-02-08 10:53

    It depends on some factors you are not defining. Do you have a fixed, rather small set of query…Source actions as shown in your question or are you rather heading to having a more flexible, extensible list of actions?

    In the first case you might consider changing the query…Source methods to return an Optional rather than SomeObject or null. If you change your methods to be like

    Optional queryFirstSource(Arguments args) {
        …
    }
    

    You can chain them this way:

    public SomeObject findSomeObject(Arguments args) {
        return queryFirstSource(args).orElseGet(
          ()->querySecondSource(args).orElseGet(
          ()->queryThirdSource(args).orElse(null)));
    }
    

    If you can’t change them or prefer them to return null you can still use the Optional class:

    public SomeObject findSomeObject(Arguments args) {
        return Optional.ofNullable(queryFirstSource(args)).orElseGet(
           ()->Optional.ofNullable(querySecondSource(args)).orElseGet(
           ()->queryThirdSource(args)));
    }
    

    If you are looking for a more flexible way for a bigger number of possible queries, it is unavoidable to convert them to some kind of list or stream of Functions. One possible solution is:

    public SomeObject findSomeObject(Arguments args) {
        return Stream.>of(
          this::queryFirstSource, this::querySecondSource, this::queryThirdSource
        ).map(f->f.apply(args)).filter(Objects::nonNull).findFirst().orElse(null);
    }
    

    This performs the desired operation, however, it will compose the necessary action every time you invoke the method. If you want to invoke this method more often, you may consider composing an operation which you can re-use:

    Function find = Stream.>of(
        this::queryFirstSource, this::querySecondSource, this::queryThirdSource
    ).reduce(a->null,(f,g)->a->Optional.ofNullable(f.apply(a)).orElseGet(()->g.apply(a)));
    
    public SomeObject findSomeObject(Arguments args) {
        return find.apply(args);
    }
    

    So you see, there are more than one way. And it depends on the actual task what direction to go. Sometimes, even the simple if sequence might be appropriate.

提交回复
热议问题