Java 当可选为空时如何返回?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38062664/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:58:44  来源:igfitidea点击:

How to return when an optional is empty?

javanullableoptional

提问by Lii

I love that optionalsare in the Java standard library now. But there is one basic problem I keep running into which I haven't figured out how to solve in the best (easiest to read and understand, prettiest, shortest) way:

我喜欢现在 Java 标准库中的可选项。但是有一个我一直遇到的基本问题,我还没有想出如何以最好的(最容易阅读和理解的,最漂亮的,最短的)方式来解决:

How to return from a method when an optional is empty?

当可选项为空时如何从方法返回?

I am looking for a general solution which works for different combinations of numbers of optionals and sizes of code blocks.

我正在寻找一种通用解决方案,它适用于可选数量和代码块大小的不同组合。

In the following examples I'll try to show what I mean:

在以下示例中,我将尝试说明我的意思:

void m1() {
    // When I get an optional:
    Optional<String> o = getOptional();

    // And want to return if it's empty
    if (!o.isPresent()) return;

    // In the whole rest of the method I have to call Optional.get 
    // every time I want the value:
    System.out.println(o.get());

    // Which is pretty ugly and verbose!
}


void m2() {
    // If I instead return null if a value is absent:
    String s = getNullabe();
    if (s == null) return;

    // Then I can use the value directly:
    System.out.println(s);
}

This question is about how to get the good aspect of both the examples above: The type safely of the optional and the brevity of nullable types.

这个问题是关于如何获得上述两个例子的优点:可选类型的安全性和可空类型的简洁性。

The rest of the examples illustrates this more.

其余示例更详细地说明了这一点。

void m3() {
    // If I on the other hand want to throw on empty that's pretty and compact:
    String s = getOptional()
        .orElseThrow(IllegalStateException::new);

    System.out.println(s);
}

void m4() {
    Optional<String> o = getOptional();
    if (!o.isPresent()) return;

    // I can of course declare a new variable for the un-optionalised string:
    String s = o.get();

    System.out.println(s);

    // But the old variable still remains in scope for the whole method 
    // which is ugly and annoying.
    System.out.println(o.get());
}


void m5() {
    // This is compact and maybe pretty in some ways:
    getOptional().ifPresent(s -> {
        System.out.println(s);

        // But the extra level of nesting is annoying and it feels 
        // wrong to write all the code in a big lambda.

        getOtherOptional().ifPresent(i -> {
            // Also, more optional values makes it really weird and 
            // pretty hard to read,  while with nullables I would 
            // get no extra nesting, it would looks good and be 
            // easy to read.
            System.out.println("i: " + i);

            // It doesn't work in all cases either way.
        });
    });
}


Optional<String> getOptional() {
    throw new UnsupportedOperationException();
}

Optional<Integer> getOtherOptional() {
    throw new UnsupportedOperationException();
}

String getNullabe() {
    throw new UnsupportedOperationException();
}

How can I return from a method if an optional is empty, without having to use getin the rest of the method, without declaring an extra variable and without extra levels of block nesting?

如果可选项为空,如何从方法返回,而不必get在方法的其余部分中使用,无需声明额外的变量,也无需额外的块嵌套级别?

Or if it's not possible to get all that, what is the best way to handle this situation?

或者,如果不可能获得所有这些,那么处理这种情况的最佳方法是什么?

采纳答案by dnault

You could use orElse(null):

你可以使用orElse(null)

String o = getOptional().orElse(null);
if (o == null) {
    return;
}

回答by Joshua Taylor

The ifPresent that you're using doesn't require you to create a new lambda, you can just use a method reference:

您使用的 ifPresent 不需要您创建新的 lambda,您只需使用方法引用即可:

getOptional().ifPresent(System.out::println);

This doesn't really solve the case where you want to conditionalize on the presence of two optionals, though. But as an alternative to

但是,这并不能真正解决您希望以两个选项的存在为条件的情况。但作为替代

// And want to return if it's empty
if (!o.isPresent()) return;
// And want to return if it's empty
if (!o.isPresent()) return;

why not just reverse the condition, which works nicely in the nested case, too? There's no need to make the return explicit:

为什么不只是颠倒条件,这在嵌套情况下也能很好地工作?无需明确返回:

if (o.isPresent()) {
  System.out.println(o.get());
  if (oo.isPresent()) {
    System.out.println(oo.get());
  }
}

However, this kind of use case suggests that you're not really benefiting from Optional as opposed to a nullable value. In general, if you're using isPresent and get, then Optional might not really be getting you all that much (except that it forces you to consider the case where the value is missing). Using ifPresent, map, filter, and other "more functional" methods might be more typical uses for an Optional value.

但是,这种用例表明您并没有真正受益于 Optional 而不是可空值。一般来说,如果您使用 isPresent 和 get,那么 Optional 可能不会真正让您获得那么多(除了它迫使您考虑缺少值的情况)。使用 ifPresent、map、filter 和其他“功能更强大”的方法可能是 Optional 值的更典型用途。



But in any case, please don't return null when you're promising an Optional. Though it's perfectly legal to return null when an object is expect, the point of Optional is precisely to avoid having to check for null. So don't do:

但无论如何,当您承诺一个 Optional 时,请不要返回 null。尽管在期望对象时返回 null 是完全合法的,但 Optional 的重点恰恰是为了避免必须检查 null。所以不要这样做:

Optional<String> getOptional() {
    return null;
}
Optional<String> getOptional() {
    return null;
}

but instead do:

而是做:

Optional<String> getOptional() { 
  return Optional.empty();
}

Otherwise you end up having to do:

否则你最终不得不做:

Optional<String> o = getOptional();
if (o != null && o.isPresent()) {
  // ...
}

which is really just doing the same kind of thing twice. Use an Optional, or use a nullable value, but don't do both!

这实际上只是两次做同样的事情。使用 Optional 或使用可空值,但不要同时使用!

回答by Luka Jacobowitz

I don't think what you're asking is actually possible, but I would like to suggest just taking all of your code that works directly on your String and wrap it in a function. So your function becomes something like this:

我不认为您要问的实际上是可能的,但我建议您只将所有直接在 String 上运行的代码都包含在一个函数中。所以你的函数变成了这样:

void m4() {
    Optional<String> o = getOptional();
    if (!o.isPresent()) return;

    doThings(o.get());
}

void doThings(String s){
    System.out.println(s);
    //do whatever else with the string.
}

This way you only have the String in scope and you don't have to call .get()everytime you want to access it.

这样你就只有范围内的 String 并且你不必.get()每次想要访问它时都调用它。

回答by Sleiman Jneidi

You can use ifPresentand mapmethods instead, if the function is void and you need to do side-effects you can use ifPresent,

您可以使用ifPresentandmap方法来代替,如果函数是无效的并且您需要做副作用,您可以使用ifPresent

optional.ifPresent(System.out::println); 

If another method return relies on the Optional than that method might need to return an Optional as well and use the map method

如果另一个方法返回依赖于 Optional,那么该方法可能还需要返回一个 Optional 并使用 map 方法

Optional<Integer> getLength(){
    Optional<String> hi = Optional.of("hi");
    return hi.map(String::length)
}

Mostof the time when you call isPresentand get, you are misusing Optional.

大多数情况下,当您调用isPresentand 时get,您都在滥用Optional

回答by mwdev

That's a great topic, we all love functional style of programming!

这是一个很棒的话题,我们都喜欢函数式编程风格!

Often when start an implementation of a method you are given an optional right at the top. At this point you start wondering, what is the best you can do to handle an empty optional, it only makes sense to exit and stop processing if that's the case.

通常,当开始一个方法的实现时,您会在顶部获得一个可选的权限。在这一点上,您开始想知道,处理空的可选项的最佳方法是什么,只有在这种情况下退出并停止处理才有意义。

STEP 1 - Explore and anylyze

第 1 步 - 探索和分析

public void processMedia(String mediaClassName, String mediaName) {

    // THAT MIGHT BE YOUR FIRST IDEA
    MediaClass mediaClass = mediaClassFinder.find(mediaClassName).orElse(null); 

    // RETURNING ON NULL CONDITION LIKE THE BELOW CAN BE ALRIGHT,
    // BUT POSSIBLY YOU CAN DO BETTER
    if (mediaClass == null) {
        return;
    }
    Optional<Media> media = mediaFinder.find(mediaClass.getId(), mediaName);

    // do processing

    // render the processed object
}

STEP 2 The best approach might be to extract various pieces of the implementation to a separate methods and chain them together in a functional style. As a side effect of this exercise you will probably end up with much improved interface and structure of your application. That's how refactoring works. Look below, there is no explicit null assignments and no extra return points anywhere. And the coding becomes fun.

第 2 步 最好的方法可能是将实现的各个部分提取到单独的方法中,并以函数式风格将它们链接在一起。作为本练习的一个副作用,您可能最终会大大改进应用程序的界面和结构。这就是重构的工作原理。看看下面,没有明确的空赋值,也没有任何额外的返回点。编码变得有趣。

public void processMedia(String mediaClassName, String mediaName) {
    mediaClassFinder.find(mediaClassName)
        .flatMap(mediaClass -> mediaFinder.find(mediaClass.getId(), mediaName))
        .map(this::compress)
        .ifPresent(this::render);
}
private Media compress(Media media) {
    // compress media implementation
    return media;
}
private void render(Media media) {
    // render media implementation
}

I hope you liked my example :)

我希望你喜欢我的例子:)