import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * @author 陈杨
 */


@RunWith(SpringRunner.class)
@SpringBootTest
public class OptionalTest {


    @Test

    public void testOptional() {

一、Optional出现的缘由

/*
 *   A container object which may or may not contain a non-{@code null} value.
 *
 *   一个装泛型为T的 值容器 可以包含Null  以规避 空指针异常
 *   public final class Optional<T>
 */

二、深入理解 Value-based Classes

/*
 *   Value-based Classes
 *
 *   https://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html
 *
 *   final  immutable (但里面可以包含指向 可变对象的引用)
 *   具有equals、hashCode和toString的实现  仅从实例的状态计算 而不是从其标识或任何其他对象或变量的状态计算
 *   不使用身份敏感的操作,例如实例之间的引用相等(==) 实例的hashCode,或实例的内部锁(intrinsic lock)同步
 *   判断是否相等 仅比较equals()方法  而非对象的引用(==)
 *   没有可访问的构造函数   通过工厂方法实例化,不保证实例创建的一致性(不一定是单例)
 *
 *   基于值的对象  没有public的构造方法  比较值是否相等(不比较引用)
 */

三、Optional容器的构造

//    private static final Optional<?> EMPTY = new Optional<>();
//    private final T value;

//    Constructs an empty instance.
//    private Optional() { this.value = null; }


/*
 *    Constructs an instance with the described value.
 *
 *    private Optional(T value) {  this.value = Objects.requireNonNull(value); }
 */



/*
 *    Returns an empty {@code Optional} instance.  No value is present for this {@code Optional}.
 *
 *       public static<T> Optional<T> empty() {
 *           @SuppressWarnings("unchecked")
 *            Optional<T> t = (Optional<T>) EMPTY;
 *                 return t;
 *                 }
 */
Optional<List<String>> empty = Optional.empty();


/*    构造一个容器里不为 null 的容器对象
 *
 *    public static <T> Optional<T> of(T value) { return new Optional<>(value);  }
 */
Optional<List<String>> optional = Optional.of(Arrays.asList("Kirito", "Love", "Asuna"));


/*     构造一个容器里可能为 null 的容器对象
 *
 *     public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value);  }
 */

四、普通方法

/*     获取容器中的所有值
 *     public T get() {
 *          if (value == null) {
 *                throw new NoSuchElementException("No value present");
 *                             }
 *           return value;
 *           }
 */
System.out.println("---------------------------------------\n");
System.out.println("optional容器中存在的值:" + optional.get());


//     判断 容器中存在值 返回true
//     public boolean isPresent() { return value != null; }
System.out.println("---------------------------------------\n");
System.out.println("optional容器中存在值:" + optional.isPresent());
System.out.println("empty容器中存在值:" + empty.isPresent());


//     判断 容器中不存在值 返回true
//     @since   11
//     public boolean isEmpty() { return value == null; }
System.out.println("---------------------------------------\n");
System.out.println("optional容器中不存在值:" + optional.isEmpty());
System.out.println("empty容器中不存在值:" + empty.isEmpty());

五、高级拓展

1、ifPresent(Consumer)

/*
 *     如果存在 value 对 value 进行一个 Consumer消费
 *     public void ifPresent(Consumer<? super T> action) {
 *                  if (value != null) {
 *                   action.accept(value);
 *                  }
 *      }
 *
 */
System.out.println("---------------------------------------\n");
System.out.println("optional容器中存在值就进行Consumer消费(打印输出)");
optional.ifPresent(System.out::println);

2、ifPresentOrElse(Consumer)

/*    如果存在 value 对 value 进行一个 Consumer消费  不存在 执行emptyAction(empty-based action)
 *    @since 9
 *    public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
 *             if (value != null) {
 *              action.accept(value);
 *             } else {
 *                emptyAction.run();
 *             }
 *    }
 */
System.out.println("---------------------------------------\n");
System.out.println("容器中存在值就打印值,不存在打印 hello world");
optional.ifPresentOrElse(System.out::println, () -> System.out.println("hello world"));
empty.ifPresentOrElse(System.out::println, () -> System.out.println("hello world"));

3、filter(Predicate)

/*
 *     如果存在value  且符合预期predicate 则对 value 进行预期操作predicate.test(value) 否则返回empty
 *     public Optional<T> filter(Predicate<? super T> predicate) {
 *                Objects.requireNonNull(predicate);
 *                if (!isPresent()) {
 *                  return this;
 *                } else {
 *                return predicate.test(value) ? this : empty();
 *                }
 *      }
 */
System.out.println("---------------------------------------\n");
System.out.println("遍历集合元素");
optional.filter(strings -> {
    strings.forEach(System.out::println);
    return true;
});

4、or(Supplier)

/*
 *      如果存在value 则返回value  否则使用supplier接口的get()方法 构造出一个Optional
 *      @since 9
 *      public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
 *             Objects.requireNonNull(supplier);
 *                if (isPresent()) {
 *                 return this;
 *                } else {
 *              @SuppressWarnings("unchecked")
 *                Optional<T> r = (Optional<T>) supplier.get();
 *                    return Objects.requireNonNull(r);
 *                }
 *        }
 */
System.out.println("---------------------------------------\n");
Supplier<Optional<List<String>>> sup =
        () -> Optional.ofNullable(Arrays.asList("Optional", "or", "supplier"));

System.out.println(empty.or(sup));

5、Stream.of(value)

/*
 *      如果存在value 则返回Stream.of(value)  否则返回一个Stream.empty()
 *      @since 9
 *      public Stream<T> stream() {
 *             if (!isPresent()) {
 *             return Stream.empty();
 *              } else {
 *             return Stream.of(value);
 *             }
 *      }
 */
System.out.println("---------------------------------------\n");
System.out.println("以stream流 遍历optional容器内的值");
Stream<List<String>> stream = Stream.of(optional.get());
stream.forEach(System.out::println);

6、orElse(T other)

/*
 *      如果存在value 则返回value  否则返回T other
 *      public T orElse(T other) {
 *             return value != null ? value : other;
 *         }
 */
System.out.println("---------------------------------------\n");
System.out.println("  容器中存在值就返回值 不存在就返回{\"hello\",\"world\"}");
System.out.println(empty.orElse(Arrays.asList("hello", "world")));

7、orElseGet(Supplier)

/*
 *       如果存在value 则返回value  否则返回Supplier接口实现
 *       public T orElseGet(Supplier<? extends T> supplier) {
 *                return value != null ? value : supplier.get();
 *        }
 */
System.out.println("---------------------------------------\n");
Supplier<List<String>> listSupplier = () -> Arrays.asList("do", "orElseGet");
System.out.println(empty.orElseGet(listSupplier));

8、orElseThrow

/*
 *       如果存在value 则返回value  否则抛出异常NoSuchElementException
 *       @since 10
 *       public T orElseThrow() {
 *            if (value == null) {
 *             throw new NoSuchElementException("No value present");
 *              }
 *         return value;
 *        }
 */
System.out.println("---------------------------------------\n");
System.out.println("  容器中存在值就返回值 不存在就返回NoSuchElementException");

System.out.println(optional.orElseThrow());
try {
    System.out.println(empty.orElseThrow());
} catch (NoSuchElementException e) {
    System.out.println(" NoSuchElementException ---> No value present");
}

9、orElseThrow(Supplier)

/*
 *      如果存在value 则返回value  否则使用Supplier接口生成一个被抛出的exceptionSupplier -->exception
 *      public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
 *                        if (value != null) {
 *                             return value;
 *                            } else {
 *                    throw exceptionSupplier.get();
 *                        }
 *        }
 */
System.out.println("---------------------------------------\n");
Supplier<NoSuchElementException> noSuchElementException = NoSuchElementException::new;

try {
    System.out.println(empty.orElseThrow(noSuchElementException));
} catch (NoSuchElementException e) {
    System.out.println(" Supplier NoSuchElementException ---> No value present");
}

10、map(Function)

/*
 *
 *      如果存在value 则返回value并作为mapper的输入 将其输出作为新的value存放至Optional  否则返回一个null的Optional
 *      如果经过mapper 后得到的结果为null  返回一个null的Optional
 *      mapper函数若为null 则抛出NullPointerException
 *      map:对集合中每个元素进行操作
 *
 *
 *      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));
 *                    }
 *       }
 */
System.out.println("---------------------------------------\n");
Function<List<String>, List<String>> function =
        up -> up.stream().map(String::toUpperCase).collect(Collectors.toList());
Optional<List<String>> o = optional.map(function);
System.out.println(o.get());

11、flatMap(Function)

        /*
         *      如果存在value 则返回value并作为mapper的输入 将其输出作为新的value存放至Optional  否则返回一个null的Optional
         *      如果经过mapper 后得到的结果为null  返回一个null的Optional
         *      mapper函数若为null 则抛出NullPointerException
         *
         *      与map的方法的区别:
         *      map
         *
         *     return Optional.ofNullable(mapper.apply(value));
         *
         *      flatMap
         *
         *      Optional<U> r = (Optional<U>) mapper.apply(value);
         *      return Objects.requireNonNull(r);
         *      flatMap:对集合中每个元素进行操作然后再扁平化
         *
         *
         *       public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
         *                     Objects.requireNonNull(mapper);
         *                             if (!isPresent()) {
         *                                 return empty();
         *                                } else {
         *                  @SuppressWarnings("unchecked")
         *                 Optional<U> r = (Optional<U>) mapper.apply(value);
         *                   return Objects.requireNonNull(r);
         *                             }
         *        }
         */
        System.out.println("---------------------------------------\n");
        Function<List<String>, Optional<List<String>>> func =
                up -> Optional.of(up.stream().map(String::toUpperCase).collect(Collectors.toList()));
        Optional<List<String>> u = optional.flatMap(func);
        System.out.println(u.get());

    }

}

六、测试

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.2.RELEASE)

2019-02-01 18:29:34.870  INFO 17140 --- [           main] com.java.design.java8.OptionalTest       : Starting OptionalTest on DESKTOP-87RMBG4 with PID 17140 (started by 46250 in E:\IdeaProjects\design)
2019-02-01 18:29:34.871  INFO 17140 --- [           main] com.java.design.java8.OptionalTest       : No active profile set, falling back to default profiles: default
2019-02-01 18:29:35.437  INFO 17140 --- [           main] com.java.design.java8.OptionalTest       : Started OptionalTest in 0.775 seconds (JVM running for 1.574)
---------------------------------------

optional容器中存在的值:[Kirito, Love, Asuna]
---------------------------------------

optional容器中存在值:true
empty容器中存在值:false
---------------------------------------

optional容器中不存在值:false
empty容器中不存在值:true
---------------------------------------

optional容器中存在值就进行Consumer消费(打印输出)
[Kirito, Love, Asuna]
---------------------------------------

容器中存在值就打印值,不存在打印 hello world
[Kirito, Love, Asuna]
hello world
---------------------------------------

遍历集合元素
Kirito
Love
Asuna
---------------------------------------

Optional[[Optional, or, supplier]]
---------------------------------------

以stream流 遍历optional容器内的值
[Kirito, Love, Asuna]
---------------------------------------

  容器中存在值就返回值 不存在就返回{"hello","world"}
[hello, world]
---------------------------------------

[do, orElseGet]
---------------------------------------

  容器中存在值就返回值 不存在就返回NoSuchElementException
[Kirito, Love, Asuna]
 NoSuchElementException ---> No value present
---------------------------------------

 Supplier NoSuchElementException ---> No value present
---------------------------------------

[KIRITO, LOVE, ASUNA]
---------------------------------------

[KIRITO, LOVE, ASUNA]

Process finished with exit code 0

陈杨
12 声望3 粉丝

不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之,学至于行而止矣;行之,明也!