简介 当我们需要使用某个对象的属性或方法时,如果该对象为 null,则会抛出空指针异常。为了避免这种异常的发生,我们通常需要在代码中添加大量的 if-else 判断来检查对象是否为 null。这样的代码不仅繁琐,而且不易于阅读和维护。
Optional 类提供了一种更好的方式来处理 null 值。使用 Optional 类,可以将对象的可能存在或不存在的状态封装成一个容器对象,可以避免直接操作对象时出现空指针异常,同时还能让代码更加简洁和易于阅读。
Brian Goetz (Java语言设计架构师)对Optional设计意图的原话如下:
Optional is intended to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result,” and using null for such was overwhelmingly likely to cause errors.
这句话突出了三个点:
Optional 是用来作为方法返回值的
Optional 是为了清晰地表达返回值中没有结果的可能性
且如果直接返回 null 很可能导致调用端产生错误(尤其是NullPointerException)
Optional的机制类似于 Java 的受检异常,强迫API调用者面对没有返回值的现实。
因此,不要滥用Optional,关于Optional使用规范可以参考Java 8 Optional 最佳实践 。
示例 Optional Optional可能包含或不包含非空值的容器对象。 如果一个值存在,isPresent()将返回true并且get()将返回值。提供依赖于存在或不存在包含值的其他方法,例如orElse(),如果值不存在则返回默认值;ifPresent(),如果值存在则执行代码块。
Optional提供以下方法:
方法类型及返回值
方法名称
描述
static Optional
empty()
返回一个空的Optional实例。
boolean
equals(Object obj)
指示某个其他对象是否等于此可选项。
Optional
filter(Predicate<? super T> predicate)
如果一个值存在,并且该值给定的谓词相匹配时,返回一个 Optional描述的值,否则返回一个空的Optional 。
Optional
flatMap(Function<? super T,Optional> mapper)
如果一个值存在,应用提供的Optional映射函数给它,返回该结果,否则返回一个空的Optional 。
T
get()
如果Optional中有一个值,返回值,否则抛出 NoSuchElementException 。
int
hashCode()
返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
void
ifPresent(Consumer<? super T> consumer)
如果存在值,则使用该值调用指定的消费者,否则不执行任何操作。
boolean
isPresent()
返回true如果存在值,否则为 false 。
Optional
map(Function<? super T,? extends U> mapper)
如果存在一个值,则应用提供的映射函数,如果结果不为空,则返回一个Optional结果的Optional 。
static Optional
of(T value)
返回具有Optional的当前非空值的Optional。
static Optional
ofNullable(T value)
返回一个Optional指定值的Optional,如果非空,则返回一个空的Optional 。
T
orElse(T other)
返回值如果存在,否则返回other 。
T
orElseGet(Supplier<? extends T> other)
返回值(如果存在),否则调用other并返回该调用的结果。
T
orElseThrow(Supplier<? extends X> exceptionSupplier)
返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
String
toString()
返回此可选的非空字符串表示,适用于调试。
测试方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 private static void test1 () { Optional<User> empty = Optional.<User>empty(); System.out.println("测试empty方法:" ); System.out.println(empty); System.out.println("-----------------------" ); Optional<User> optional1 = Optional.of(User.builder().username("lisi" ).build()); Optional<User> optional2 = Optional.of(User.builder().username("zhangsan" ).build()); System.out.println("测试equals方法:" ); System.out.println(optional1.equals(optional2)); System.out.println("-----------------------" ); Optional<User> optional3 = Optional.of(User.builder().username("zhangsan" ).build()); Optional<User> optional4 = optional3.filter(new Predicate <User>() { @Override public boolean test (User user) { return Objects.equals("zhangsan" , user.getUsername()); } }); System.out.println("测试filter方法:" ); System.out.println(optional4); System.out.println("-----------------------" ); Optional<User> optional5 = Optional.of(User.builder().username("zhangsan" ).build()); Optional<User> optional6 = optional5.flatMap(new Function <User, Optional<User>>() { @Override public Optional<User> apply (User user) { if (Objects.equals("zhangsan" , user.getUsername())) { return Optional.of(user); } return Optional.empty(); } }); System.out.println("测试flatMap方法:" ); System.out.println(optional6); System.out.println("-----------------------" ); Optional<User> optional7 = Optional.of(User.builder().username("zhangsan" ).build()); System.out.println("测试get方法:" ); System.out.println(optional7.get()); System.out.println("-----------------------" ); Optional<User> optional8 = Optional.of(User.builder().username("zhangsan" ).build()); System.out.println("测试hashCode方法:" ); System.out.println(optional8.hashCode()); System.out.println("-----------------------" ); Optional<User> optional9 = Optional.of(User.builder().username("zhangsan" ).build()); System.out.println("测试ifPresent方法:" ); optional9.ifPresent(new Consumer <User>() { @Override public void accept (User user) { System.out.println(user); } }); System.out.println("-----------------------" ); Optional<User> optional10 = Optional.of(User.builder().username("zhangsan" ).build()); System.out.println("测试isPresent方法:" ); System.out.println(optional10.isPresent()); System.out.println("-----------------------" ); Optional<User> optional11 = Optional.of(User.builder().username("zhangsan" ).build()); System.out.println("测试map方法:" ); Optional<User> optional12 = optional11.map(new Function <User, User>() { @Override public User apply (User user) { if (Objects.equals("zhangsan" , user.getUsername())) { return user; } return null ; } }); System.out.println(optional12); System.out.println("-----------------------" ); Optional<User> optional13 = Optional.of(User.builder().username("zhangsan" ).build()); System.out.println("测试of方法:" ); System.out.println(optional13); System.out.println("-----------------------" ); Optional<User> optional14 = Optional.ofNullable(User.builder().username("zhangsan" ).build()); System.out.println("测试ofNullable方法:" ); System.out.println(optional14); System.out.println("-----------------------" ); Optional<User> optional15 = Optional.empty(); System.out.println("测试orElse方法:" ); System.out.println(optional15.orElse(User.builder().username("zhangsan" ).build())); System.out.println("-----------------------" ); Optional<User> optional16 = Optional.empty(); System.out.println("测试orElse方法:" ); System.out.println(optional16.orElseGet(new Supplier <User>() { @Override public User get () { return User.builder().username("zhangsan" ).build(); } })); System.out.println("-----------------------" ); System.out.println("测试toString方法:" ); Optional<User> optional17 = Optional.of(User.builder().username("zhangsan" ).build()); String s = optional17.toString(); System.out.println(s); System.out.println("-----------------------" ); }
控制台输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 测试empty方法: Optional.empty ----------------------- 测试equals方法: false ----------------------- 测试filter方法: Optional[User(age=null, height=null, weight=null, username=zhangsan)] ----------------------- 测试flatMap方法: Optional[User(age=null, height=null, weight=null, username=zhangsan)] ----------------------- 测试get方法: User(age=null, height=null, weight=null, username=zhangsan) ----------------------- 测试hashCode方法: -1431681035 ----------------------- 测试ifPresent方法: User(age=null, height=null, weight=null, username=zhangsan) ----------------------- 测试isPresent方法: true ----------------------- 测试map方法: Optional[User(age=null, height=null, weight=null, username=zhangsan)] ----------------------- 测试of方法: Optional[User(age=null, height=null, weight=null, username=zhangsan)] ----------------------- 测试ofNullable方法: Optional[User(age=null, height=null, weight=null, username=zhangsan)] ----------------------- 测试orElse方法: User(age=null, height=null, weight=null, username=zhangsan) ----------------------- 测试orElse方法: User(age=null, height=null, weight=null, username=zhangsan) ----------------------- 测试toString方法: Optional[User(age=null, height=null, weight=null, username=zhangsan)] -----------------------
OptionalInt OptionalInt可能含有也可能不包含int值的容器对象。 如果值存在, isPresent()将返回true并且getAsInt()将返回值。
提供依赖于包含值的存在或不存在的附加方法,例如orElse(),如果值不存在则返回默认值;ifPresent(),如果值存在则执行代码块。
OptionalInt提供以下方法:
方法类型及返回值
方法名称
描述
static OptionalInt
empty()
返回一个空的 OptionalInt实例。
boolean
equals(Object obj)
指示某个其他对象是否等于此OptionalInt。
int
getAsInt()
如果 OptionalInt中存在值,则返回值,否则抛出 NoSuchElementException 。
int
hashCode()
返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
void
ifPresent(IntConsumer consumer)
让指定的消费者接受该值,如果一个值存在,否则什么也不做。
boolean
isPresent()
如果有值存在,返回 true ,否则 false 。
static OptionalInt
of(int value)
返回一个 OptionalInt具有指定值存在。
int
orElse(int other)
返回值如果存在,否则返回 other 。
int
orElseGet(IntSupplier other)
返回值(如果存在),否则调用 other并返回该调用的结果。
int
orElseThrow(Supplier exceptionSupplier)
返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
String
toString()
返回对象的字符串表示形式。
测试方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 @SneakyThrows private static void test2 () { System.out.println("测试empty方法:" ); OptionalInt empty = OptionalInt.empty(); System.out.println(empty); System.out.println("-----------------------" ); System.out.println("测试equals方法:" ); OptionalInt optionalInt = OptionalInt.of(3 ); OptionalInt optionalInt1 = OptionalInt.of(4 ); System.out.println(optionalInt.equals(optionalInt1)); System.out.println("-----------------------" ); System.out.println("测试getAsInt方法:" ); OptionalInt optionalInt2 = OptionalInt.of(1 ); System.out.println(optionalInt2.getAsInt()); System.out.println("-----------------------" ); System.out.println("测试hashCode方法:" ); OptionalInt optionalInt3 = OptionalInt.of(1 ); System.out.println(optionalInt3.hashCode()); System.out.println("-----------------------" ); System.out.println("测试ifPresent方法:" ); OptionalInt optionalInt4 = OptionalInt.of(1 ); optionalInt4.ifPresent(new IntConsumer () { @Override public void accept (int value) { System.out.println("打印值:" + value); } }); System.out.println("-----------------------" ); System.out.println("测试of方法:" ); OptionalInt optionalInt5 = OptionalInt.of(1 ); System.out.println(optionalInt5); System.out.println("-----------------------" ); System.out.println("测试orElse方法:" ); OptionalInt optionalInt6 = OptionalInt.of(1 ); System.out.println(optionalInt6.orElse(-1 )); System.out.println("-----------------------" ); System.out.println("测试orElseGet方法:" ); OptionalInt optionalInt7 = OptionalInt.of(1 ); System.out.println(optionalInt7.orElseGet(new IntSupplier () { @Override public int getAsInt () { return -1 ; } })); System.out.println("-----------------------" ); System.out.println("测试orElseGet方法:" ); OptionalInt optionalInt8 = OptionalInt.of(1 ); optionalInt8.orElseThrow(new Supplier <Throwable>() { @Override public Throwable get () { return new Throwable ("没有值" ); } }); System.out.println("-----------------------" ); System.out.println("测试toString方法:" ); OptionalInt optionalInt9 = OptionalInt.of(1 ); String s = optionalInt9.toString(); System.out.println(s); System.out.println("-----------------------" ); }
控制台输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 测试empty方法: OptionalInt.empty ----------------------- 测试equals方法: false ----------------------- 测试getAsInt方法: 1 ----------------------- 测试hashCode方法: 1 ----------------------- 测试ifPresent方法: 打印值:1 ----------------------- 测试of方法: OptionalInt[1] ----------------------- 测试orElse方法: 1 ----------------------- 测试orElseGet方法: 1 ----------------------- 测试orElseGet方法: ----------------------- 测试toString方法: OptionalInt[1] -----------------------
OptionalLong OptionalLong可能含有也可能不包含int值的容器对象。 如果值存在, isPresent()将返回true并且getAsLong()将返回值。
提供依赖于包含值的存在或不存在的附加方法,例如orElse(),如果值不存在则返回默认值;ifPresent(),如果值存在则执行代码块。
OptionalLong提供以下方法:
方法类型及返回值
方法名称
描述
static OptionalLong
empty()
返回一个空的OptionalLong实例。
boolean
equals(Object obj)
指示一些其他对象是否等于此OptionalLong。
long
getAsLong()
如果 OptionalLong中存在值,则返回值,否则抛出 NoSuchElementException 。
int
hashCode()
返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
void
ifPresent(LongConsumer consumer)
让指定的消费者接受该值,如果一个值存在,否则什么也不做。
boolean
isPresent()
如果存在值,则返回true ,否则为 false 。
static OptionalLong
of(long value)
返回一个OptionalLong具有指定值存在。
long
orElse(long other)
返回值如果存在,否则返回other 。
long
orElseGet(LongSupplier other)
返回值(如果存在),否则调用other并返回该调用的结果。
long
orElseThrow(Supplier exceptionSupplier)
返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
String
toString()
返回对象的字符串表示形式。
测试方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 @SneakyThrows private static void test3 () { System.out.println("测试empty方法:" ); OptionalLong empty = OptionalLong.empty(); System.out.println(empty); System.out.println("-----------------------" ); System.out.println("测试equals方法:" ); OptionalLong optionalInt = OptionalLong.of(3 ); OptionalLong optionalInt1 = OptionalLong.of(4 ); System.out.println(optionalInt.equals(optionalInt1)); System.out.println("-----------------------" ); System.out.println("测试getAsLong方法:" ); OptionalLong optionalInt2 = OptionalLong.of(1 ); System.out.println(optionalInt2.getAsLong()); System.out.println("-----------------------" ); System.out.println("测试hashCode方法:" ); OptionalLong optionalInt3 = OptionalLong.of(1 ); System.out.println(optionalInt3.hashCode()); System.out.println("-----------------------" ); System.out.println("测试ifPresent方法:" ); OptionalLong optionalInt4 = OptionalLong.of(1 ); optionalInt4.ifPresent(new LongConsumer () { @Override public void accept (long value) { System.out.println("打印值:" + value); } }); System.out.println("-----------------------" ); System.out.println("测试of方法:" ); OptionalLong optionalInt5 = OptionalLong.of(1 ); System.out.println(optionalInt5); System.out.println("-----------------------" ); System.out.println("测试orElse方法:" ); OptionalLong optionalInt6 = OptionalLong.of(1 ); System.out.println(optionalInt6.orElse(-1 )); System.out.println("-----------------------" ); System.out.println("测试orElseGet方法:" ); OptionalLong optionalInt7 = OptionalLong.of(1 ); System.out.println(optionalInt7.orElseGet(new LongSupplier () { @Override public long getAsLong () { return -1 ; } })); System.out.println("-----------------------" ); System.out.println("测试orElseGet方法:" ); OptionalLong optionalInt8 = OptionalLong.of(1 ); optionalInt8.orElseThrow(new Supplier <Throwable>() { @Override public Throwable get () { return new Throwable ("没有值" ); } }); System.out.println("-----------------------" ); System.out.println("测试toString方法:" ); OptionalLong optionalInt9 = OptionalLong.of(1 ); String s = optionalInt9.toString(); System.out.println(s); System.out.println("-----------------------" ); }
控制台输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 测试empty方法: OptionalLong.empty ----------------------- 测试equals方法: false ----------------------- 测试getAsLong方法: 1 ----------------------- 测试hashCode方法: 1 ----------------------- 测试ifPresent方法: 打印值:1 ----------------------- 测试of方法: OptionalLong[1] ----------------------- 测试orElse方法: 1 ----------------------- 测试orElseGet方法: 1 ----------------------- 测试orElseGet方法: ----------------------- 测试toString方法: OptionalLong[1] -----------------------
OptionalDouble OptionalDouble可能含有也可能不包含int值的容器对象。 如果值存在, isPresent()将返回true并且getAsDouble()将返回值。
提供依赖于包含值的存在或不存在的附加方法,例如orElse(),如果值不存在则返回默认值;ifPresent(),如果值存在则执行代码块。
OptionalDouble提供以下方法:
方法类型及返回值
方法名称
描述
static OptionalDouble
empty()
返回一个空的 OptionalDouble实例。
boolean
equals(Object obj)
指示某个其他对象是否等于此OptionalDouble。
double
getAsDouble()
如果 OptionalDouble中有值,则返回值,否则抛出 NoSuchElementException 。
int
hashCode()
返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
void
ifPresent(DoubleConsumer consumer)
让指定的消费者接受该值,如果一个值存在,否则什么也不做。
boolean
isPresent()
返回 true如果存在值,否则为 false 。
static OptionalDouble
of(double value)
返回一个 OptionalDouble具有指定值存在。
double
orElse(double other)
返回值如果存在,否则返回 other 。
double
orElseGet(DoubleSupplier other)
返回值(如果存在),否则调用 other并返回该调用的结果。
double
orElseThrow(Supplier exceptionSupplier)
返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
String
toString()
返回对象的字符串表示形式。
测试方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 @SneakyThrows private static void test4 () { System.out.println("测试empty方法:" ); OptionalDouble empty = OptionalDouble.empty(); System.out.println(empty); System.out.println("-----------------------" ); System.out.println("测试equals方法:" ); OptionalDouble optionalInt = OptionalDouble.of(3 ); OptionalDouble optionalInt1 = OptionalDouble.of(4 ); System.out.println(optionalInt.equals(optionalInt1)); System.out.println("-----------------------" ); System.out.println("测试getAsDouble方法:" ); OptionalDouble optionalInt2 = OptionalDouble.of(1 ); System.out.println(optionalInt2.getAsDouble()); System.out.println("-----------------------" ); System.out.println("测试hashCode方法:" ); OptionalDouble optionalInt3 = OptionalDouble.of(1 ); System.out.println(optionalInt3.hashCode()); System.out.println("-----------------------" ); System.out.println("测试ifPresent方法:" ); OptionalDouble optionalInt4 = OptionalDouble.of(1 ); optionalInt4.ifPresent(new DoubleConsumer () { @Override public void accept (double value) { System.out.println("打印值:" + value); } }); System.out.println("-----------------------" ); System.out.println("测试of方法:" ); OptionalDouble optionalInt5 = OptionalDouble.of(1 ); System.out.println(optionalInt5); System.out.println("-----------------------" ); System.out.println("测试orElse方法:" ); OptionalDouble optionalInt6 = OptionalDouble.of(1 ); System.out.println(optionalInt6.orElse(-1 )); System.out.println("-----------------------" ); System.out.println("测试orElseGet方法:" ); OptionalDouble optionalInt7 = OptionalDouble.of(1 ); System.out.println(optionalInt7.orElseGet(new DoubleSupplier () { @Override public double getAsDouble () { return -1 ; } })); System.out.println("-----------------------" ); System.out.println("测试orElseGet方法:" ); OptionalDouble optionalInt8 = OptionalDouble.of(1 ); optionalInt8.orElseThrow(new Supplier <Throwable>() { @Override public Throwable get () { return new Throwable ("没有值" ); } }); System.out.println("-----------------------" ); System.out.println("测试toString方法:" ); OptionalDouble optionalInt9 = OptionalDouble.of(1 ); String s = optionalInt9.toString(); System.out.println(s); System.out.println("-----------------------" ); }
控制台输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 测试empty方法: OptionalDouble.empty ----------------------- 测试equals方法: false ----------------------- 测试getAsDouble方法: 1.0 ----------------------- 测试hashCode方法: 1072693248 ----------------------- 测试ifPresent方法: 打印值:1.0 ----------------------- 测试of方法: OptionalDouble[1.0] ----------------------- 测试orElse方法: 1.0 ----------------------- 测试orElseGet方法: 1.0 ----------------------- 测试orElseGet方法: ----------------------- 测试toString方法: OptionalDouble[1.0] -----------------------