如何使用Guava将可能为null的值转换为默认值?

59
Guava提供了一种方法来获取默认值,如果传递的对象引用是null,则返回该默认值。我正在寻找类似于<T> T nullToDefault(T obj, T default)的东西,其中defaultobjnull时返回。

在stackoverflow上我没有找到任何关于它的信息。如果有的话,我只是寻找一个纯Guava解决方案!

我在Gauva 10 API中没有找到任何东西,只有com.google.common.base.Objects看起来很有前途,但缺少类似的东西。

10个回答

74
除了Objects.firstNonNull之外,Guava 10.0还增加了Optional类,作为这种类型问题的更一般解决方案。 Optional是可能包含值的东西。有各种创建Optional实例的方法,但对于您的情况,工厂方法Optional.fromNullable(T)是适当的。
一旦您拥有一个Optional,您就可以使用其中一个or方法来获取Optional包含的值(如果它包含值)或其他值(如果它不包含值)。
将所有内容组合在一起,您的简单示例如下:
T value = Optional.fromNullable(obj).or(defaultValue);
Optional 的额外灵活性在于,如果您想要使用 Supplier 来获取默认值(这样可以避免不必要的计算),或者如果您想要将多个可选值链接在一起以获取第一个存在的值,例如:
T value = someOptional.or(someOtherOptional).or(someDefault);

有趣!它能用于不同类型参数的Optional实例的空安全操作吗?我猜不行,因为它都绑定在T的类型上了。我们得等待Java 8+中的Elvis运算符 - Chriss
你是说你想要类似于Pet pet = Optional.fromNullable(cat).or(Optional.fromNullable(dog)).orNull()这样的代码,其中CatDog都继承自Pet。看起来你需要先将第一个Optional强制转换为Pet类型,然后就可以从那里顺利进行了。 - Ray
我认为这是一种性能反模式,因为它将至少创建一个对象(如果默认值是空数组,则可能创建两个对象)。 - David Burström
如果你在使用Android系统,那就有所影响了...否则,这个问题很可能不会出现,或者至少不足以让人担心。 - ColinD
更新:在JDK 1.8u91上进行基准测试后,一旦JIT启动,性能相同。我会提供ART的数字。 - David Burström
1
更新:在Android 22上运行显示,如果对象为空,则使用Optional比使用简单条件语句需要4倍的时间。而如果对象不为空,则需要14倍的时间。如果您还不必要地创建默认值,则根据类型会有进一步的惩罚。 - David Burström

61

怎么样

MoreObjects.firstNonNull(obj, default)

请查看JavaDoc

(历史注:原来的MoreObjects类被称为Objects,但由于与Java 7中引入的java.util.Objects类产生混淆而被重命名。Guava Objects类现在已经被弃用。)


1
方法名称在我的使用情况下有点令人困惑。我猜我必须读两遍才能记住我想要获取默认值!但是,嘿,它有效! - Chriss
现在这已经被弃用了,guava文档建议使用MoreObjects.firstNonNull(obj, default) - antogerva
@antogerva 谢谢 - 我已经更新了我的答案,推荐使用MoreObjects。 - Simon Nickerson
请注意,此方法要求任何参数都不能为空,并且不适用于默认值可能为空的情况。 - kairius

42

正如先前所说的,Guava解决方案是正确的。

然而,使用Java 8存在一个纯JDK解决方案:

Optional.ofNullable( var ).orElse( defaultValue );

查看java.util.Optional的文档。


9
这应该可以解决问题:Objects.firstNonNull(o, default)
请参阅guava API文档

8
如果你只是讨论字符串,那么还有Apache Commons的defaultString和defaultIfEmpty方法。
defaultString只会在真正为null时提供默认值,而defaultIfEmpty会在null或空字符串上提供默认值。
此外,还有defaultIfBlank,它甚至可以在空白字符串上提供默认值。
例如:
String description = "";
description = StringUtils.defaultIfBlank(description, "Theodore"); 

描述现在将等于"Theodore"

编辑: Apache Commons还有一个ObjectUtils类,可以对完全烘焙的对象进行空值默认处理...


7

提供信息,Java 9有两种方法可以完全满足您的需求:

public static <T> T requireNonNullElse(T obj, T defaultObj);

还有一种懒惰的方式:

public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)

7
如果您的对象尚未是Optional类型,则Optional/firstNotNull建议会使一个简单的Java特性——三元运算符变得复杂。
T myVal = (val != null) ? val : defaultVal;

包含依赖项和多个方法调用引入了与三元运算符一样的阅读复杂性。我甚至会认为,与其“我的方法可能返回一个对象或者不返回”语义相反地使用Optional是一个红旗,表明您正在做一些错误的事情(就像在其他情况下滥用某些东西的语义含义一样)。
有关三元运算符的更多讨论,请参见http://alvinalexander.com/java/edu/pj/pj010018

1
我认为你说得有道理。然而,如果你想测试一个昂贵的方法返回,可选方案更好: Optional.ofNullable( superExpensiveMethod() ).orElse( defaultValue );使用三元运算符,你必须先将其放入变量中。 - Nicolas Nobelis

3

java.util.Objects和Guava的optional提供了一种很好的方式来将null覆盖为默认值...我经常使用它们

但是,对于更加命令式的思维方式,这里有一些内容:

public static <T> T firstNotNuLL(T...args){
    for (T arg : args)
        if ( arg != null) return arg;
    throw new NullPointerException();  
}

1

0
请考虑使用 Guava 10 中内置的 Optional。您可以将多个可选项串联在一起,例如 Optional.fromNullable(var).orNull()Optional.fromNullable(var).or(Optional.of(var2)).orNull()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接