Java 8中的多个空检查

spa*_*ker 95 java lambda optional java-8 java-stream

我有下面的代码,对于多次空检查有点难看.

String s = null;

if (str1 != null) {
    s = str1;
} else if (str2 != null) {
    s = str2;
} else if (str3 != null) {
    s = str3;
} else {
    s = str4;
}
Run Code Online (Sandbox Code Playgroud)

所以我尝试使用Optional.ofNullable如下所示,但如果有人读取我的代码仍然很难理解.在Java 8中这样做的最佳方法是什么.

String s = Optional.ofNullable(str1)
                   .orElse(Optional.ofNullable(str2)
                                   .orElse(Optional.ofNullable(str3)
                                                   .orElse(str4)));
Run Code Online (Sandbox Code Playgroud)

在Java中9,我们可以使用Optional.ofNullableOR,但在Java8还有没有其他办法?

Rav*_*ala 167

你可以这样做:

String s = Stream.of(str1, str2, str3)
    .filter(Objects::nonNull)
    .findFirst()
    .orElse(str4);
Run Code Online (Sandbox Code Playgroud)

  • 插入强制性的过早优化注释. (42认同)
  • 速度开销是多少?创建Stream对象,调用4个方法,创建临时数组(`{str1,str2,str3}`)看起来比Java运行时可以优化的本地`if`或`?:`慢得多.在`javac`和Java运行库中是否有一些特定于Stream的优化,它使它像`?:`一样快?如果没有,我不会在性能关键代码中推荐这个解决方案. (21认同)
  • 好方案!为了提高可读性,我建议将`str4`添加到`Stream.of(...)`的参数中,最后使用`orElse(null)`. (21认同)
  • 这个.想想你需要什么,而不是你拥有什么. (16认同)
  • @pts这很可能比`?:`代码慢,我确信你应该在性能关键代码中避免它.然而,它更具可读性,你应该在非性能关键代码IMO中推荐它,我确信它可以生成超过99%的代码. (16认同)
  • @pts在`javac`和运行时都没有Stream特定的优化.这并不排除一般优化,例如内联所有代码,然后消除冗余操作.原则上,最终结果可能与普通条件表达式一样有效,但是,它不太可能到达那里,因为运行时将仅在最热的代码路径上花费必要的努力. (7认同)
  • @pts创建和回收构造函数几乎没有显式工作的小对象很便宜,特别是在现代JVM实现上.创建其他对象以增强程序的清晰度,简单性或功能通常是一件好事.关于优化有一个深刻的事实:它很容易弊大于利,特别是如果你过早优化的话.因此,除非您的应用程序性能严格,否则您可以毫不犹豫地使用此方法. (4认同)

Era*_*ran 72

三元条件运算符怎么样?

String s = 
    str1 != null ? str1 : 
    str2 != null ? str2 : 
    str3 != null ? str3 : str4
;
Run Code Online (Sandbox Code Playgroud)

  • 实际上,他正在寻找"在Java8中实现这一目标的最佳方法".这种方法可以在Java8中使用,所以这一切只取决于OP意味着什么是"最好的",并且基于什么理由他决定什么是更好的. (48认同)
  • 我通常不喜欢嵌套的三元组,但这看起来很干净. (17认同)
  • 对于那些每天都没有阅读嵌套三元运算符的人来说,这是一个巨大的痛苦. (11认同)
  • @Cubic然而,这是一个简单的**重复模式.解析第2行后,无论包含多少个案例,您都会解析整个事物.一旦你完成了,你就学会了以简短而相对简单的方式表达十种不同案例的类似选择.下次你会看到一个`?:`梯子,你会知道它的作用.(顺便说一句,函数式程序员知道这是`(cond ...)`子句:它总是一个后卫​​,后面跟着适当的值,当守卫是真的.) (4认同)
  • @Cubic:如果您认为很难解析,请写一个类似`//的注释,将str1..3的第一个非null值。一旦知道了它的作用,就很容易看到它是如何做的。 (2认同)

ern*_*t_k 33

你也可以使用循环:

String[] strings = {str1, str2, str3, str4};
for(String str : strings) {
    s = str;
    if(s != null) break;
}
Run Code Online (Sandbox Code Playgroud)


wal*_*len 26

目前的答案很好,但你真的应该把它放在一个实用工具方法:

public static Optional<String> firstNonNull(String... strings) {
    return Arrays.stream(strings)
            .filter(Objects::nonNull)
            .findFirst();
}
Run Code Online (Sandbox Code Playgroud)

这种方法已经在我的Util班上多年,使代码更清洁:

String s = firstNonNull(str1, str2, str3).orElse(str4);
Run Code Online (Sandbox Code Playgroud)

你甚至可以把它变成通用的:

@SafeVarargs
public static <T> Optional<T> firstNonNull(T... objects) {
    return Arrays.stream(objects)
            .filter(Objects::nonNull)
            .findFirst();
}

// Use
Student student = firstNonNull(student1, student2, student3).orElseGet(Student::new);
Run Code Online (Sandbox Code Playgroud)

  • FWIW,在SQL中,这个函数被称为[coalesce](https://www.postgresql.org/docs/11/functions-conditional.html#FUNCTIONS-COALESCE-NVL-IFNULL),所以我在我的代码中称之为太.这对你有用取决于你对SQL的喜爱程度. (10认同)
  • 如果您打算将它放在一个实用工具方法中,您也可以使其高效. (5认同)
  • @GustavoSilva Todd可能意味着,这是我的一个实用方法,当我可以用`for`和`!= null`做同样的事情时,使用`Arrays.stream()`是没有意义的,这样效率更高.托德是对的.但是,当我编写这个方法时,我正在寻找一种使用Java 8功能的方法,就像OP一样,所以就是这样. (5认同)
  • @GustavoSilva是的,基本上就是这样:如果你要放这个是一个util函数关于干净代码的问题不再那么重要了,所以你不妨使用更快的版本. (4认同)

Mic*_*son 13

我使用辅助函数,如

T firstNonNull<T>(T v0, T... vs) {
  if(v0 != null)
    return v0;
  for(T x : vs) {
    if (x != null) 
      return x;
  }
  return null;
}
Run Code Online (Sandbox Code Playgroud)

然后这种代码可以写成

String s = firstNonNull(str1, str2, str3, str4);
Run Code Online (Sandbox Code Playgroud)

  • @Nick是的,我猜了很多,但是如果没有它,函数也可以正常工作(实际上表现完全一样). (3认同)
  • @tobias_k 使用 varargs 时的额外参数是 Java 中需要 1 个或多个参数而不是 0 个或更多参数的惯用方式。(参见 Effective Java,Ed. 3. 的第 53 条,它以 `min` 为例。)我不太相信这在这里是合适的。 (2认同)
  • 传递额外的第一个参数的一个关键原因是明确传递数组时的行为。在这种情况下,如果 arr 不为空,我希望 `firstNonNull(arr)` 返回。如果它是 `firstNonNull(T... vs)`,它将返回 arr 中的第一个非空条目。 (2认同)