JDK 8 新特性:Optional
文章目录
JDK 8 新特性:Optional
参考文献:java.util.Optional
Optional
public final class Optional<T>
可能包含或不包含非空值的容器对象
如果存在值,
isPresent()
方法返回true
,get()
方法返回值;提供依赖于存在或不存在包含值的其他方法,orElse()
(如果值不存在则返回默认值)和isPresent()
(如果值存在则执行代码块)
在Java开发中有很多的异常,其中空指针异常(NullPointerException )是一个极为常见的问题,目前对于NPE问题的处理通常是进行一层判空,如果要对一个对象进行嵌套处理的话,那可能就是多层的判空,显得代码冗余又不美观,Optional
类是一个很好的解决方案。
值得注意的是,Optional
并不是对null
的替代,而是一种处理方式,是可以包含null
值的容器对象,结合流式处理的特点,更加便捷方便的处理NPE,优化代码。
Optional方法
1.创建Optional对象
创建空对象
Optional.empty()
:返回一个空的Optional
实例。
-
源码解析
/** * Common instance for {@code empty()}. */ private static final Optional<?> EMPTY = new Optional<>(); /** * Returns an empty {@code Optional} instance. No value is present for this * Optional. * * @apiNote Though it may be tempting to do so, avoid testing if an object * is empty by comparing with {@code ==} against instances returned by * {@code Option.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * * @param <T> Type of the non-existent value * @return an empty {@code Optional} */ public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
-
使用实例
Optional<String> empty = Optional.empty();
创建对象:不允许为空
Optional.of(T value)
:返回具有Optional
的当前非空值的Optional。
-
源码解析
/** * Constructs an instance with the value present. * * @param value the non-null value to be present * @throws NullPointerException if value is null */ private Optional(T value) { this.value = Objects.requireNonNull(value); } /** * Returns an {@code Optional} with the specified present non-null value. * * @param <T> the class of the value * @param value the value to be present, which must be non-null * @return an {@code Optional} with the value present * @throws NullPointerException if value is null */ public static <T> Optional<T> of(T value) { return new Optional<>(value); }
-
使用实例
// str为null时,抛出异常NullPointerException Optional<String> optional = Optional.of(str);
创建对象:允许为空
Optional.ofNullable(T value)
:返回一个Optional
指定值的Optional,如果非空,则返回一个空的Optional
。
-
源码解析
/** * Returns an {@code Optional} describing the specified value, if non-null, * otherwise returns an empty {@code Optional}. * * @param <T> the class of the value * @param value the possibly-null value to describe * @return an {@code Optional} with a present value if the specified value * is non-null, otherwise an empty {@code Optional} */ public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
-
使用实例
// str为null时,返回一个空的Optional Optional<String> optional = Optional.ofNullable(str);
2.判空:isPresent()
isPresent()
:返回true
如果存在值,否则为false
。
Object判空,new
的对象作为Optional
的值,此时isPresent() = true
List判空,new
的对象作为Optional
的值,此时isPresent() = true
,List判空是list != null || list.size != 0
,使用ifPresent
判断不准确
-
源码解析
/** * Return {@code true} if there is a value present, otherwise {@code false}. * * @return {@code true} if there is a value present, otherwise {@code false} */ public boolean isPresent() { return value != null; }
-
使用实例
Optional<String> empty = Optional.empty(); // Optional contain String which is not null String str = "test"; Optional<String> optional = Optional.of(str); System.out.println("Optional value: " + str); System.out.println("optional.isPresent() = " + optional.isPresent()); // Optional contain String which is null String str1 = null; Optional<String> optional1 = Optional.ofNullable(str1); System.out.println("optional1 value: " + str1); System.out.println("optional1.isPresent() = " + optional1.isPresent()); // Optional contain object which is not null CodeType c1 = new CodeType(); c1.setCodeType("001"); c1.setCode("1"); c1.setName("字符串"); Optional<CodeType> optional2 = Optional.ofNullable(c1); System.out.println("optional2 value: " + c1); System.out.println("optional2.isPresent() = " + optional2.isPresent()); // Optional contain object which is new Object CodeType c2 = new CodeType(); Optional<CodeType> optional3 = Optional.ofNullable(c2); System.out.println("optional3 value: " + c2); System.out.println("optional3.isPresent() = " + optional3.isPresent()); // Optional contain object which is null CodeType c3 = null; Optional<CodeType> optional4 = Optional.ofNullable(c3); System.out.println("optional4 value: " + c3); System.out.println("optional4.isPresent() = " + optional4.isPresent()); // Optional contain list which size is 0 List<CodeType> list = new ArrayList<>(); Optional<List<CodeType>> optional5 = Optional.ofNullable(list); System.out.println("optional5 value: " + list); System.out.println("optional5.isPresent() = " + optional5.isPresent());
-
结果
Optional value: test optional.isPresent() = true optional1 value: null optional1.isPresent() = false optional2 value: CodeType{ codeType='001', code='1', name='字符串'} optional2.isPresent() = true optional3 value: CodeType{ codeType='null', code='null', name='null'} optional3.isPresent() = true optional4 value: null optional4.isPresent() = false optional5 value: [] optional5.isPresent() = true
Object判空:
new Object
: ifPresent()
= true
null
: ifPresent()
= false
List判空:
new List
: ifPresent()
= true
null
: ifPresent()
= false
3.取值:get()
get()
:如果Optional
中有一个值,返回值,否则抛出NoSuchElementException
。
-
源码解析
/** * If a value is present in this {@code Optional}, returns the value, * otherwise throws {@code NoSuchElementException}. * * @return the non-null value held by this {@code Optional} * @throws NoSuchElementException if there is no value present * * @see Optional#isPresent() */ public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; }
4.条件处理
ifPresent
public void ifPresent(Consumer<? super T> consumer)
如果存在值,则使用该值调用指定的消费者,否则不执行任何操作。
参数:consumer: 如果存在值,则执行块;在
Consumer
中执行的操作会影响Optional
中的值异常:NullPointerException: 如果值存在且
consumer
为空
-
源码解析
/** * If a value is present, invoke the specified consumer with the value, * otherwise do nothing. * * @param consumer block to be executed if a value is present * @throws NullPointerException if value is present and {@code consumer} is * null */ public void ifPresent(Consumer<? super T> consumer) { if (value != null) consumer.accept(value); }
-
使用实例
CodeType c1 = new CodeType(); c1.setCodeType("001"); c1.setCode("1"); c1.setName("字符串"); Optional<CodeType> optional2 = Optional.ofNullable(c1); optional2.ifPresent(x ->{ // x 为Optional的value // 执行的代码块 System.out.println(x); x.setCode("2"); System.out.println(x); System.out.println(optional2.get()); });
CodeType{ codeType='001', code='1', name='字符串'} CodeType{ codeType='001', code='2', name='字符串'} CodeType{ codeType='001', code='2', name='字符串'}
orElse
public T orElse(T other)
如果存在/符合给定条件,返回值
value
;否则,返回other
。
- 参数:
other
- 如果没有值存在则返回的值,可以为null;- 结果:
value
-
使用情况
当
Optional
的值不符合给定条件的时候,则执行orElse
orElse:有取值的含义,承接的变量要和
Optional
中的value
的类一致 -
源码解析
/** * Return the value if present, otherwise return {@code other}. * * @param other the value to be returned if there is no value present, may * be null * @return the value, if present, otherwise {@code other} */ public T orElse(T other) { return value != null ? value : other; }
-
使用实例
// 对返回结果赋予默认值 String str = getStr(); String result = Optional.ofNullable(str).orElse("01"); // 对返回数组做处理 List<String> str1 = getList(); // Optional中Class 与 orElse()中Class一致 // 承接的变量也要一致 List<String> list = Optional.ofNullable(str1).orElse(new ArrayList<>());
orElseGet
public T orElseGet(Supplier<? extends T> other)
如果存在/符合给定条件,返回值
value
;否则,调用 other并返回该调用的结果。
- 参数:
other
- 一个Supplier
,如果没有值,则返回其结果- 结果:
value
- 异常:
NullPointerException
- 如果值不存在,并且other
为空
-
使用情况
如果条件不成立时,需要执行相对复杂的逻辑,而不是简单的返回操作,则可以使用orElseGet实现:
orElseGet:有取值的含义,承接的变量要和
Optional
中的value
的类一致 -
源码解析
/** * Return the value if present, otherwise invoke {@code other} and return * the result of that invocation. * * @param other a {@code Supplier} whose result is returned if no value * is present * @return the value if present otherwise the result of {@code other.get()} * @throws NullPointerException if value is not present and {@code other} is * null */ public T orElseGet(Supplier<? extends T> other) { return value != null ? value : other.get(); }
-
使用实例
String str = "112"; String result = Optional.ofNullable(str).orElseGet(() -> { // do something here return "0"; });
orElseThrow
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends Throwable
如果存在,返回包含的值;否则,抛出由提供的供应商创建的异常。
参数:
X
- 要抛出的异常的类型
exceptionSupplier
- 将返回要抛出的异常的供应商结果:
value
异常:
NullPointerException
- 如果没有值,exceptionSupplier
为空
-
使用情况
与
get()
方法类型,在不满足条件的时候get()
返回 NullPointerException,orElseThrow
返回指定的异常类型和异常信息可以使用具有空参数列表的异常构造函数的方法引用作为供应商。 例如,
IllegalStateException::new
-
源码解析
/** * Return the contained value, if present, otherwise throw an exception * to be created by the provided supplier. * * @apiNote A method reference to the exception constructor with an empty * argument list can be used as the supplier. For example, * {@code IllegalStateException::new} * * @param <X> Type of the exception to be thrown * @param exceptionSupplier The supplier which will return the exception to * be thrown * @return the present value * @throws X if there is no value present * @throws NullPointerException if no value is present and * {@code exceptionSupplier} is null */ public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { if (value != null) { return value; } else { throw exceptionSupplier.get(); } }
-
使用实例
String Id = getId(); return Optional.ofNullable(Id) // 处理不存在的情况,抛出指定的异常 .orElseThrow(() -> (Exception) new IllegalStateException("xx的Id不能为空"));
5.流式处理
过滤:filter
public Optional<T> filter(Predicate<? super T> predicate)
如果一个值存在,并且该值给定的谓词相匹配时,返回一个
Optional
描述的值,否则返回一个空的Optional
。
参数:
predicate
- 一个应用于该值的谓词(如果存在)结果:一个
Optional
描述此的值Optional
一个值是否存在,并且值给定的谓词相匹配,否则一个空Optional
异常:
NullPointerException
- 如果谓词为空
-
使用条件
过滤操作,将过滤操作作为参数传递给该方法
-
源码解析
/** * If a value is present, and the value matches the given predicate, * return an {@code Optional} describing the value, otherwise return an * empty {@code Optional}. * * @param predicate a predicate to apply to the value, if present * @return an {@code Optional} describing the value of this {@code Optional} * if a value is present and the value matches the given predicate, * otherwise an empty {@code Optional} * @throws NullPointerException if the predicate is null */ public Optional<T> filter(Predicate<? super T> predicate) { Objects.requireNonNull(predicate); if (!isPresent()) return this; else return predicate.test(value) ? this : empty(); }
-
使用实例
// CodeType codeType = new CodeType(); CodeType codeType = getCodeType(); Optional.ofNullable(codeType) // 进行过滤,codetype == "001" .filter(x -> "001".equals(x.getCodeType())) .ifPresent(x -> { x.setCode("001"); System.out.println(x); } );
映射: map
public < U > Optional< U > map(Function< ? super T, ? extends U > mapper)
如果存在值,则应用提供的映射函数,如果结果不为空,则返回一个Optional结果的Optional 。 否则返回一个空的Optional 。
- 参数:
mapper
- 应用于值的映射函数(如果存在)- 结果:一个
Optional
描述了将映射函数应用于该值Optional
的值的Optional
,如果存在值,否则为空Optional
- 异常:
NullPointerException
- 如果映射函数为空
-
使用条件
参考Stream流式操作,对输入做指定的操作,转为另一个输出
-
源码解析
/** * If a value is present, apply the provided mapping function to it, * and if the result is non-null, return an {@code Optional} describing the * result. Otherwise return an empty {@code Optional}. * * @apiNote This method supports post-processing on optional values, without * the need to explicitly check for a return status. For example, the * following code traverses a stream of file names, selects one that has * not yet been processed, and then opens that file, returning an * {@code Optional<FileInputStream>}: * * <pre>{@code * Optional<FileInputStream> fis = * names.stream().filter(name -> !isProcessedYet(name)) * .findFirst() * .map(name -> new FileInputStream(name)); * }</pre> * * Here, {@code findFirst} returns an {@code Optional<String>}, and then * {@code map} returns an {@code Optional<FileInputStream>} for the desired * file if one exists. * * @param <U> The type of the result of the mapping function * @param mapper a mapping function to apply to the value, if present * @return an {@code Optional} describing the result of applying a mapping * function to the value of this {@code Optional}, if a value is present, * otherwise an empty {@code Optional} * @throws NullPointerException if the mapping function is null */ public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Optional.ofNullable(mapper.apply(value)); } }
-
使用实例
// 获取CodeType的name CodeType codeType = getCodeType(); String name; // if-else if(Objects.nonNull(codeType)){ name = codeType.getName(); }else { name = "no name"; } // Optional:map可以嵌套 name = Optional.ofNullable(codeType) // 取出name .map(o -> o.getName()) // 对name进行操作 .map(x -> x.toUpperCase()) .orElse("no name");
映射: flatMap
public <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)
如果一个值存在,应用提供的
Optional
映射函数给它,返回该结果,否则返回一个空的Optional
。 这种方法类似于map(Function)
,但是提供的映射器是一个结果已经是Optional
映射器,如果被调用,flatMap
不会用额外的Optional
。
- 参数:
mapper
- 应用于值的映射函数,如果存在映射函数- 结果:施加的结果
Optional
荷瘤映射函数此的值Optional
,如果一个值存在,否则一个空Optional
- 异常:
NullPointerException
- 如果映射函数为空或返回空结果
-
使用条件
与
map
相似,返回结果为Optional
-
源码解析
/** * If a value is present, apply the provided {@code Optional}-bearing * mapping function to it, return that result, otherwise return an empty * {@code Optional}. This method is similar to {@link #map(Function)}, * but the provided mapper is one whose result is already an {@code Optional}, * and if invoked, {@code flatMap} does not wrap it with an additional * {@code Optional}. * * @param <U> The type parameter to the {@code Optional} returned by * @param mapper a mapping function to apply to the value, if present * the mapping function * @return the result of applying an {@code Optional}-bearing mapping * function to the value of this {@code Optional}, if a value is present, * otherwise an empty {@code Optional} * @throws NullPointerException if the mapping function is null or returns * a null result */ public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { Objects.requireNonNull(mapper); if (!isPresent()) return empty(); else { return Objects.requireNonNull(mapper.apply(value)); } }
-
使用实例
// Optional Optional<String> optional = Optional.ofNullable(codeType) .flatMap(o -> Optional.of(o.getCode()));
6.其他
equals
public boolean equals(Object obj)
指示某个其他对象是否等于此可选项。
相等
obj
与该对象相等(hashcode相等)obj
它也是一个Optional
并且现在的值通过equals()
“相等”。
-
使用条件
判断相等
-
源码解析
/** * Indicates whether some other object is "equal to" this Optional. The * other object is considered equal if: * <ul> * <li>it is also an {@code Optional} and; * <li>both instances have no value present or; * <li>the present values are "equal to" each other via {@code equals()}. * </ul> * * @param obj an object to be tested for equality * @return {code true} if the other object is "equal to" this object * otherwise {@code false} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Optional)) { return false; } Optional<?> other = (Optional<?>) obj; return Objects.equals(value, other.value); }
-
使用实例
Optional<String> test = Optional.ofNullable("test"); Optional<String> test1 = test; Optional<String> test2 = Optional.ofNullable("test"); Optional<String> test3 = Optional.ofNullable("tt"); // false System.out.println(test.equals("test")); // true System.out.println(test.equals(test1)); // true System.out.println(test.equals(test2)); // false System.out.println(test.equals(test3));
hashCode
public int hashCode()
返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
-
使用条件
获取hashCode
-
源码解析
/** * Returns the hash code value of the present value, if any, or 0 (zero) if * no value is present. * * @return hash code value of the present value or 0 if no value is present */ @Override public int hashCode() { return Objects.hashCode(value); }
-
使用实例
System.out.println(Optional.empty().hashCode()); Optional<String> test = Optional.ofNullable("test"); System.out.println(test.hashCode()); Optional<String> test1 = test; System.out.println(test1.hashCode()); Optional<String> test2 = Optional.ofNullable("test"); System.out.println(test2.hashCode()); Optional<String> test3 = Optional.ofNullable("tt"); System.out.println(test3.hashCode()); // 输出结果,hashCode是value的hashCode // 0 // 3556498 // 3556498 // 3556498 // 3712
toString
public String toString()
返回此可选的非空字符串表示,适用于调试。 准确的表示格式是未指定的,可能会在实现和版本之间变化。
重写了
Object
的toString
方法
-
使用条件
调试或者输出
-
源码解析
/** * Returns a non-empty string representation of this Optional suitable for * debugging. The exact presentation format is unspecified and may vary * between implementations and versions. * * @implSpec If a value is present the result must include its string * representation in the result. Empty and present Optionals must be * unambiguously differentiable. * * @return the string representation of this instance */ @Override public String toString() { return value != null ? String.format("Optional[%s]", value) : "Optional.empty"; }
-
使用实例
// print:Optional.empty System.out.println(Optional.empty().toString()); // print:Optional[test] Optional<String> test = Optional.ofNullable("test"); System.out.println(test.toString()); // print:Optional[CodeType{codeType='001', code='1', name='null'}] CodeType codeType = new CodeType(); codeType.setCode("1"); codeType.setCodeType("001"); System.out.println(Optional.ofNullable(codeType).toString()); // print:Optional[[CodeType{codeType='001', code='1', name='null'}]] List<CodeType> list = new ArrayList<>(); list.add(codeType); System.out.println(Optional.ofNullable(list).toString());