JDK 8 新特性:Optional

参考文献:java.util.Optional

Optional

public final class Optional<T>

可能包含或不包含非空值的容器对象

如果存在值,isPresent()方法返回trueget()方法返回值;提供依赖于存在或不存在包含值的其他方法,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()返回 NullPointerExceptionorElseThrow返回指定的异常类型和异常信息

    可以使用具有空参数列表的异常构造函数的方法引用作为供应商。 例如, 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)

指示某个其他对象是否等于此可选项。

相等

  1. obj与该对象相等(hashcode相等)
  2. 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()

返回此可选的非空字符串表示,适用于调试。 准确的表示格式是未指定的,可能会在实现和版本之间变化。

重写了ObjecttoString方法

  • 使用条件

    调试或者输出

  • 源码解析

        /** * 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());