【问题标题】:Java 8 Optional instead of ifJava 8 可选而不是 if
【发布时间】:2017-07-28 11:46:05
【问题描述】:

我对 Optional 有疑问,我不知道如何处理。

public void check(String name) {
   if (name != null)
      doSomething(name);
   else 
      doMore();
} 

如果变成 Optional 怎么改?

【问题讨论】:

  • 你没有! Optionals 不应该传递给方法,它们仅用于返回可选值。您的代码现在非常好(可能需要添加@Nullable 注释)
  • 在这种情况下你真的不能,但如果你的 else 是doSomething(""); 那么Optional<String> name 可以像doSomething(name.orElse("")); 一样使用
  • 在这种情况下利用方法重载可能会更好,这样没有参数的 check() 方法调用 doMore(),而只有 @NonNull 字符串名称的 check() 方法接受非空字符串。否则,请遵循 Eugene 或 luk2302 的建议。

标签: java if-statement java-8 optional


【解决方案1】:

有一个非常简洁的方法,但存在于 jdk-9 中......

public void check(String name){
     Optional.ofNullable(name)
            .ifPresentOrElse(YourClass::doSomething, YourClass::doMore);
} 

假设doSomethingdoMore 是静态方法...如果不是应该使用实例,例如this::doSomethingthis::doMore

【讨论】:

  • 我觉得应该是this::doSomethingthis::doMore
  • 我会说这与整洁相去甚远。该代码比原始代码更长,更晦涩难懂。虽然技术上是正确的,但我会在代码审查中看到它时要求对其进行更改。
  • @luk2302 有趣的一点,不能争论。我使用Optional btw 编码,但这只是我
  • ifPresentOrElse 方法从何而来?
  • 首先,起来!!我认为这是合理的。而spring mvc控制器也引入了Optional参数。但从 OP 的角度来看,只需使用 if 声明即可。
【解决方案2】:

虽然肯定有一种方法可以使用 Optionals 创建相同的代码(例如,请参阅 Eugene 的回答),但您不应该在此处使用 Optionals(恕我直言)。

您要么将Optional 传递到您的方法中,这会给调用者带来开销,并且查看为什么/对于什么用例Optional 被引入并没有真正意义。
或者您可以在方法中自己创建Optional。这更“好”但非常麻烦,掩盖了实际发生的事情,如果我在代码审查期间遇到它,我会要求更改它。只需使用Optional 和您当前的代码比较 sn-p - 您的代码在字符方面可能更短,很明显正在发生什么。在这里使用 Optionals 的唯一好处是它似乎变成了一个单行代码,首先没有什么比可读性更重要,而且如果你添加一些大括号,无论如何你都可以在没有它的情况下实现它。


底线:您的代码完全没有问题。

【讨论】:

  • 这太值得商榷了......没有有效的技术论据来拒绝@Eugene 的代码,即在审查中。只是口味问题,两种方式都可以。 说函数式的方式可读性较差,但这可能完全是因为 you 太习惯于命令式构造,以至于它对你来说看起来很奇怪或缺乏表现力。 一旦您习惯了函数式构造,这两种方法都是正确且清晰的。另一方面,没有理由用一些清晰、可读的功能等效构造来替换清晰、可读的命令式构造......
  • 我在代码审查期间发现了完全这样的代码,我要求完全按照您所写的方式对其进行更改。很高兴知道并非所有 Java 程序员都将 java.util.Optional 放在理论上可能的地方!
【解决方案3】:

没有理由更改您的实施。 在 java 8 中 没有 if 的 Optional 没有办法做你想做的事,同时尊重不使用'map'的想法。

我的意思是,你可以有

public void check(String name) {
    Optional<String> nameOpt = Optional.ofNullable(name);
    nameOpt.ifPresent(n -> doSomething(n));
    if (!nameOpt.isPresent()) {
        doMore();
    }
}

但这没有任何意义。 here 你有一篇好文章 Optional 试图解决的问题(以及它的用途):主要用于返回类型。其他东西只是过度使用它。

【讨论】:

    【解决方案4】:

    您可以通过使用 Java 8 Optional.map()Optional.orElseGet() 方法来避免 if 语句。检查以下示例:

    import java.util.Optional;
    import java.util.function.Consumer;
    
    final class OptionalTestMain {
    
        public static void main(String[] args) {
            check("test", str -> {
                System.out.println("Yay, string is not null!");
                System.out.println("It's: " + str);
            }, () -> {
                System.out.println("Crap, string is a null...");
                System.out.println("There is nothing for me to do.");
            });
    
            check(null, str -> {
                System.out.println("Yay, string is not null!");
                System.out.println("It's: " + str);
            }, () -> {
                System.out.println("Crap, string is a null...");
                System.out.println("There is nothing for me to do.");
            });
        }
    
        static void check(String str, Consumer<String> ifPresent, Runnable ifNotPresent) {
            Optional.ofNullable(str)
                    .map(s -> { ifPresent.accept(s); return s; })
                    .orElseGet(() -> { ifNotPresent.run(); return null; });
        }
    }
    

    它将产生以下输出:

    Yay, string is not null!
    It's: test
    Crap, string is a null...
    There is nothing for me to do.
    

    方法 check 需要 3 个参数:

    • 一个字符串(可能是null
    • 一个Consumer lambda 表达式,它对该值执行某些操作并且不会改变输入值。
    • 当输入Stringnull 时,一个没有参数的Runnable lambda 可以做某事。

    当然你可以很容易地修改下面的方法,然后利用Optional类的全部潜力,例如:

    static String checkAndReturn(String str, Function<String, String> ifPresent, Supplier<String> ifNotPresent) {
        return Optional.ofNullable(str)
                .map(ifPresent)
                .orElseGet(ifNotPresent);
    }
    

    然后:

    System.out.println(checkAndReturn("test", String::toUpperCase, () -> "no value"));
    System.out.println(checkAndReturn(null, String::toUpperCase, () -> "no value"));
    

    将产生以下输出:

    TEST
    no value
    

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-26
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      • 1970-01-01
      • 2019-07-31
      相关资源
      最近更新 更多