文章目录
初步认识:
Java 8 中引入了一个很有趣的特性是 Optional 类。Optional 类主要解决的问题是空指针异常(NullPointerException)。这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
简单示例一:
从前的写法:
public String getName(User user) {
if (null == user) {
return "未知用户";
}
return user.name;
}
使用了Optional 类的写法:
public String getName(User user) {
return Optional.ofNullable(user)
.map(x -> x.name)
.orElse("未知用户");
}
简单示例二:
从前的写法:
public String getName(King king) throws IllegalArgumentException {
if (null != king) {
King result = king.getResult();
if (null != result) {
User realKing = result.getKing();
if (null != realKing) {
return realKing.getName();
}
}
}
throw new IllegalArgumentException("本届海贼王尚未诞生!");
}
使用了Optional 类的写法:
public String getName(King king) throws IllegalArgumentException {
return Optional.ofNullable(king)
.map(x -> x.getResult())
.map(y -> y.getKing())
.map(z -> z.getName())
.orElseThrow(() -> new IllegalArgumentException("本届海贼王尚未诞生!"));
}
看到这里,相信大家已经对Optional 类有了足够的兴趣,接下来我们就看看它的具体方法及使用。
具体使用:
1、of:
为非null的值创建一个Optional。(如果传入参数为null,则抛出NullPointerException)
@Test
public void testOf() {
Optional<String> ofOptional = Optional.of("张三");
Optional<String> nullOptional = Optional.of(null);
}
2、ofNullable:
为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。
@Test
public void testOfNullable() {
Optional<String> nullOptional = Optional.ofNullable(null);
System.out.println(nullOptional);
Optional<String> ofNullableOptional = Optional.ofNullable("李四");
System.out.println(ofNullableOptional);
}
3、empty:
创建一个空的Optional对象。
@Test
public void testEmpty() {
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional);
}
4、get:
如果Optional对象中有值存在则返回此值。(如果没有值存在,则抛出NoSuchElementException)
@Test
public void testGet() {
Optional<String> stringOptional = Optional.of("王五");
System.out.println(stringOptional.get());
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.get());
}
5、orElse:
如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。
@Test
public void testOrElse() {
Optional<String> stringOptional = Optional.of("赵六");
System.out.println(stringOptional.orElse("备用输出(赵六)"));
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElse("orElse(空)"));
}
6、orElseGet:
orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。
@Test
public void testOrElseGet() {
Optional<String> stringOptional = Optional.of("孙七");
System.out.println(stringOptional.orElseGet(() -> "孙七"));
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseGet(() -> "orElseGet(空)"));
}
7、orElseThrow:
如果Optional实例有值则将其返回,否则抛出一个由指定的Supplier接口生成的异常。
@Test
public void testOrElseThrow() {
Optional<String> stringOptional = Optional.of("钱八");
System.out.println(stringOptional.orElseThrow(CustomException::new));
Optional<String> emptyOptional = Optional.empty();
System.out.println(emptyOptional.orElseThrow(CustomException::new));
}
private static class CustomException extends RuntimeException {
public CustomException() {
super("自定义异常");
}
public CustomException(String message) {
super(message);
}
}
8、filter:
如果值存在并且满足断言条件返回包含该值的Optional,否则返回空Optional。
@Test
public void testFilter() {
Optional<String> stringOptional = Optional.of("biggerthanfive");
System.out.println(stringOptional.filter(e -> e.length() > 5).orElse("长度大于5"));
stringOptional = Optional.of("oh");
System.out.println(stringOptional.filter(e -> e.length() > 5).orElse("长度小于5"));
}
注意:Optional中的filter方法和Stream中的filter方法是有点不一样的。Stream中的filter方法是对一堆元素进行过滤,而Optional中的filter方法只是对一个元素进行过滤,可以把Optional看成是最多只包含一个元素的Stream。
9、map:
如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
@Test
public void testMap() {
Optional<String> stringOptional = Optional.of("small");
System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("大写转换失败"));
stringOptional = Optional.empty();
System.out.println(stringOptional.map(e -> e.toUpperCase()).orElse("大写转换失败"));
}
10、flatMap:
flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。调用结束时,flatMap不会对结果用Optional封装。
@Test
public void testFlatMap() {
Optional<String> stringOptional = Optional.of("刘九");
System.out.println(stringOptional.flatMap(e -> Optional.of("卓十")).orElse("转换失败"));
stringOptional = Optional.of("刘九");
System.out.println(stringOptional.flatMap(e -> Optional.empty()).orElse("转换失败"));
}
11、ifPresent:
如果Optional实例有值则为其调用Consumer接口,否则不做处理。
@Test
public void testIfPresent() {
Optional<String> stringOptional = Optional.of("萧十一");
stringOptional.ifPresent(e -> System.out.println("我被执行了…………" + e));
}
这里补充两段代码比较orElse与orElseGet的不同:
12、值为null时,效果一样:
@Test
public void testdiffOne() {
String str = null;
log.info("Using orElse");
String result1 = Optional.ofNullable(str).orElse(createNewString());
log.info("Using orElseGet");
String result2 = Optional.ofNullable(str).orElseGet(() -> createNewString());
}
private String createNewString() {
log.info("Creating New String");
return new String("新·字符串");
}
13、值不为null时,使用orElseGet不会调用createNewString方法:
@Test
public void testdiffTwo() {
String str = "不为null";
log.info("Using orElse");
String result1 = Optional.ofNullable(str).orElse(createNewString());
log.info("Using orElseGet");
String result2 = Optional.ofNullable(str).orElseGet(() -> createNewString());
}
private String createNewString() {
log.info("Creating New String");
return new String("新·字符串");
}
一句话小结:使用 Optional 时尽量不直接调用 Optional.get() 方法,Optional.isPresent() 更应该被视为一个私有方法,应依赖于其他像 Optional.orElse(),Optional.orElseGet(),Optional.map() 等这样的方法。
最后,Java 9 为 Optional 类添加了三个方法:or()、ifPresentOrElse() 和 stream()。有兴趣的朋友可以自行继续拓展,此处只做引出不再深入。