@Test public void whenCheckIfPresent_thenOk() { User user = new User("[email protected]", "1234"); Optional opt = Optional.ofNullable(user); assertTrue(opt.isPresent());
@Test public void whenEmptyValue_thenReturnDefault() { User user = null; User user2 = new User("[email protected]", "1234"); User result = Optional.ofNullable(user).orElse(user2);
@Test public void whenValueNotNull_thenIgnoreDefault() { User user = new User("[email protected]","1234"); User user2 = new User("[email protected]", "1234"); User result = Optional.ofNullable(user).orElse(user2);
第二个同类型的 API 是 orElseGet() —— 其行为略有不同。这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口,并将返回其执行结果:
User result = Optional.ofNullable(user).orElseGet( () -> user2);
orElse() 和 orElseGet() 的不同之处
乍一看,这两种方法似乎起着同样的作用。然而事实并非如此。我们创建一些示例来突出二者行为上的异同。
我们先来看看对象为空时他们的行为:
@Test public void givenEmptyValue_whenCompare_thenOk() { User user = null logger.debug("Using orElse"); User result = Optional.ofNullable(user).orElse(createNewUser()); logger.debug("Using orElseGet"); User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser()); }
private User createNewUser() { logger.debug("Creating New User"); return new User("[email protected]", "1234"); }
上面的代码中,两种方法都调用了 createNewUser() 方法,这个方法会记录一个消息并返回 User 对象。
代码输出如下:
Using orElse Creating New User Using orElseGet Creating New User
由此可见,当对象为空而返回默认对象时,行为并无差异。
我们接下来看一个类似的示例,但这里 Optional 不为空:
@Testpublic void givenPresentValue_whenCompare_thenOk() { User user = new User("[email protected]", "1234"); logger.info("Using orElse"); User result = Optional.ofNullable(user).orElse(createNewUser()); logger.info("Using orElseGet"); User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());}
这次的输出:
Using orElseCreating New UserUsing orElseGet
这个示例中,两个 Optional 对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象。
在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响。
返回异常
除了 orElse() 和 orElseGet() 方法,Optional 还定义了 orElseThrow() API —— 它会在对象为空的时候抛出异常,而不是返回备选的值:
@Test public void givenPresentValue_whenCompare_thenOk() { User user = new User("[email protected]", "1234"); logger.info("Using orElse"); User result = Optional.ofNullable(user).orElse(createNewUser()); logger.info("Using orElseGet"); User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser()); }
@Test public void whenMap_thenOk() { User user = new User("[email protected]", "1234"); String email = Optional.ofNullable(user) .map(u -> u.getEmail()).orElse("[email protected]");
@Test public void whenFlatMap_thenOk() { User user = new User("[email protected]", "1234"); user.setPosition("Developer"); String position = Optional.ofNullable(user) .flatMap(u -> u.getPosition()).orElse("default");
@Test public void whenFilter_thenOk() { User user = new User("[email protected]", "1234"); Optional result = Optional.ofNullable(user) .filter(u -> u.getEmail() != null && u.getEmail().contains("@"));
assertTrue(result.isPresent()); }
如果通过过滤器测试,result 对象会包含非空值。
Optional 类的链式方法
为了更充分的使用 Optional,你可以链接组合其大部分方法,因为它们都返回相同类似的对象。
我们使用 Optional 重写最早介绍的示例。
首先,重构类,使其 getter 方法返回 Optional 引用:
public class User { private Address address;
public Optional getAddress() { return Optional.ofNullable(address); }
// ... } public class Address { private Country country;
public OptionalgetCountry() { return Optional.ofNullable(country); }
// ... }
上面的嵌套结构可以用下面的图来表示:
现在可以删除 null 检查,替换为 Optional 的方法:
@Test public void whenChaining_thenOk() { User user = new User("[email protected]", "1234");