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

Lii*_*Lii 19 java nullable optional

我喜欢自选是在Java标准库现在.但是我仍然遇到一个基本问题,我还没有弄清楚如何以最好的方式解决(最容易阅读和理解,最漂亮,最短)的方式:

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

我正在寻找一个通用的解决方案,适用于选项数和代码块大小的不同组合.

在下面的例子中,我将尝试展示我的意思:

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);
}
Run Code Online (Sandbox Code Playgroud)

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

其余的例子更多地说明了这一点.

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();
}
Run Code Online (Sandbox Code Playgroud)

如果可选项为空,如何get在不声明额外变量且没有额外级别的块嵌套的情况下使用方法的其余部分,如何从方法返回?

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

dna*_*ult 23

你可以使用orElse(null):

String o = getOptional().orElse(null);
if (o == null) {
    return;
}
Run Code Online (Sandbox Code Playgroud)

  • 引入“Optional”是为了避免“null”的*问题*;它允许您在方法签名中明确表示您可能会返回空值。你无法阻止人们做愚蠢的事情,但你可以尝试帮助人们停止犯愚蠢的错误。 (3认同)
  • 我的第一个想法是:"嗯,然后我又回到了使用nullables." 但是第二个想法也许这不是那么糟糕!因为在'getOptional`类型中仍然可以看到可能缺少值,并且可空字符串在一个小范围内使用,其中非常清楚正在发生什么. (2认同)

Sle*_*idi 8

你可以使用ifPresentmap方法,如果函数是无效的,你需要做你可以使用的副作用ifPresent,

optional.ifPresent(System.out::println); 
Run Code Online (Sandbox Code Playgroud)

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

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

大多数的时候,你打电话isPresentget你在不当使用Optional.


mwd*_*dev 6

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

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

第 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
}
Run Code Online (Sandbox Code Playgroud)

步骤 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
}
Run Code Online (Sandbox Code Playgroud)

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


Jos*_*lor 5

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

getOptional().ifPresent(System.out::println);
Run Code Online (Sandbox Code Playgroud)

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

// And want to return if it's empty
if (!o.isPresent()) return;
Run Code Online (Sandbox Code Playgroud)

为什么不只是反转条件,这在嵌套的情况下也很好用?没有必要明确返回:

if (o.isPresent()) {
  System.out.println(o.get());
  if (oo.isPresent()) {
    System.out.println(oo.get());
  }
}
Run Code Online (Sandbox Code Playgroud)

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


但无论如何,当你承诺选择时,请不要返回null.虽然在期望对象时返回null是完全合法的,但Optional的要点正是为了避免必须检查null.所以不要这样做:

Optional<String> getOptional() {
    return null;
}
Run Code Online (Sandbox Code Playgroud)

而是做:

Optional<String> getOptional() { 
  return Optional.empty();
}
Run Code Online (Sandbox Code Playgroud)

否则你最终不得不做:

Optional<String> o = getOptional();
if (o != null && o.isPresent()) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

这真的只是两次做同样的事情.使用Optional,或使用可空值,但不要同时执行这两项操作!