1. 引言
在Java 8中,并没有像Groovy或Kotlin那样的内置Elvis(空合并)运算符。然而,我们可以利用方法引用和三元运算符来实现自己的Elvis运算符。本教程将探讨如何在Java 8中实现Elvis运算符。
2. 理解Elvis运算符
Elvis运算符在Groovy和Kotlin等语言中常用,它由?:
符号表示,用于当原始值为null
时提供默认值。
运算符会评估其左侧的表达式,如果它不为null
,则返回该表达式的值。如果左侧表达式评估为null
,则返回右侧的表达式。
例如,在Kotlin中,我们可以写val name = person.name?: "Unknown"
来获取用户的名字,如果名字存在则返回,否则返回"Unknown"。
3. 使用三元运算符
三元运算符(?:)允许在表达式内进行简洁的if
-else
结构。虽然它并非真正的Elvis运算符,但也能实现类似的null
检查和默认赋值。
设想一个场景,我们有一个从数据库获取用户名字的方法,如果找不到用户,该方法可能会返回null
。传统上,我们会使用三元运算符进行null
检查并指定默认值:
User user = new User("Baeldung"); // Simulate user object return from database
String greeting = (user != null && user.getName() != null) ? user.getName() : "Hello, Stranger";
assertEquals("Baeldung", greeting);
User user = new User(null);
String greeting = (user != null && user.getName() != null) ? user.getName() : "Hello, Stranger";
assertEquals("Hello, Stranger", greeting);
三元运算符为在表达式内处理null
检查和默认赋值提供了简洁且表达式的解决方案。然而,对于嵌套的null
检查,它就显得有些冗长:
String address = user != null ? user.getAddress() != null ? user.getAddress().getCity() : null : null;
4. 使用Optional
类
Java 8引入的Optional
类是安全处理null
引用的强大工具。它表示值的存在与否。
我们可以使用ofNullable()
方法从可能为null
的值创建一个Optional
,然后链式调用map()
操作,如果值存在则在其上执行操作。最后,我们使用orElse()
指定在Optional
为空时的默认值:
现在,我们想要将用户的名字转换为大写,如果存在的话,否则返回"Hello Stranger":
User user = new User("Baeldung");
String greeting = Optional.ofNullable(user.getName())
.map(String::toUpperCase) // Transform if present
.orElse("Hello Stranger");
assertEquals("BAELDUNG", greeting);
在这个代码中,Optional.ofNullable(user.getName())
根据用户的名字创建一个Optional
,处理了null
的可能性。然后我们使用map(String::toUpperCase)
在名字存在时将其转换为大写。最后,orElse("Hello Stranger")
在名字为null
时指定默认问候语:
User user = new User(null);
String greeting = Optional.ofNullable(user.getName())
.map(String::toUpperCase)
.orElse("Hello Stranger");
assertEquals("Hello Stranger", greeting);
这种方法促进了null
安全性,避免了潜在的NullPointerException
。
5. 使用自定义方法
我们可以创建一组实用方法,接受目标对象和函数,如果目标对象不为null
,则应用函数。甚至可以将这些方法串联起来,创建一系列的null
合并操作。
为了创建一个模仿Elvis运算符的自定义实用方法,我们定义一个泛型方法,以处理不同类型的数据:
public static <T> T elvis(T value, T defaultValue) {
return value != null ? value : defaultValue;
}
这个方法接受两个参数:一个需要检查是否为null
的值和在值为null
时返回的默认值。然后根据null
检查返回value
或defaultValue
:
User user = new User("Baeldung");
String greeting = elvis(user.getName(), "Hello Stranger");
assertEquals("Baeldung", greeting);
user = new User(null);
String greeting = elvis(user.getName(), "Hello Stranger");
assertEquals("Hello Stranger", greeting);
使用像elvis()
这样的自定义实用方法,相比嵌套的三元运算符,有多个优势。它通过封装null
检查逻辑到单独的方法中,提高了代码组织性,增强了可读性和可维护性。
让我们看看这个例子:
User user = new User("Baeldung");
user.setAddress(new Address("Singapore"));
String cityName = elvis(elvis(user, new User("Stranger")).getAddress(), new Address("Default City")).getCity();
assertEquals("Singapore", cityName);
首先,我们检查user
是否为null
。如果为null
,则返回一个新的User
对象,其中默认值为"Stranger"。接下来,我们从user
对象中获取address
。如果getAddress()
返回null
,我们返回一个新的Address
对象,其中默认城市名为"Default City":
User user = new User("Baeldung");
user.setAddress(null);
String cityName = elvis(elvis(user, new User("Stranger")).getAddress(), new Address("Default City")).getCity();
assertEquals("Default City", cityName);
这种使用elvis()
方法的串联方式允许我们以简洁和可读的方式处理嵌套的null
检查,确保我们的代码优雅地处理null
情况,而不必求助于冗长的if
-else
结构。
6. 总结
在这篇文章中,我们在Java 8中使用Optional
类和三元运算符实现了Elvis运算符。此外,我们创建了一个自定义实用方法elvis()
来处理null
检查和默认赋值。通过将逻辑封装在方法中,我们提升了代码可读性和可维护性,同时促进了代码重用。
如往常一样,示例代码可在GitHub上的项目中找到。