函数式接口(行为参数化)、Stream、Optional是独立的三个部分,在Java中,他们却能组成一个漂亮的三重奏。函数式接口本身限制很大,它就像天生为Stream设计的,而Optional也是Stream处理终端操作结果的一个重要方式。

创建Optional

  • Optional.empty() ,创建空Optional
  • Optional.of(value) ,包装value到Optional内部,如果强行传null的话,汇报NullPointerException
  • ofNullable(value) ,同上,但是可以传递null,这样会生成 Optional.empty
  • Optional本身是一个包装类,如果按照它的API合理操作,可以避免空指针异常问题.

    if (optString.isPresent()){
    	ostString.get();
    }else{
        //....
    

    除了上面最基本的套路——先验证再取值的方式,还有一些方法可以将两步合一步的方式。

  • ifPresent(Consumer),如果值存在就调用Consumer消费,否则什么也不做
  • orElse(otherObj),如果存在就get,否则返回otherObj
  • orElseGet(Supplier),如果存在就get,否则返回Supplier的生成对象
  • orElseThrow(Supplier),存在就get,否则返回Supplier生成的异常
  • 其他的都是显而易见的,对于生成异常,这里有个示例,

    optString.orElseThrow(()->new Exception("supplier"));
    

    具体代码Optionals.java

    返回Optional的流操作

  • findFirst
  • findAny
  • reduce
  • IntStream等数字Stream,使用的average
  • filter(Predicate),如果通过测试,则返回;如果没通过,或者Optional本身为空,则返回Optional.empty()
    示例代码OptionalFilter.java

    map(Function<T,R>),将Optional内部的值通过Function转化,返回包装结果的Optional;如果内部value为空,则返回Optional.empty()
    示例代码OptionalMap

    flatMap(Function<T,R>),与map一样,提取Optional内部的值,进行转化。不同的是,它不会自动将value包装进Optional,这一点需要调用者自己提供能够返回Optional的Function。
    示例代码OptionalFlatMap.java

    处理Optional流

    所谓Optional流,就是元素为Optional类型的Stream,当我们想处理null值的时候,自然会想到Optional

    将普通的流转化成Optional

    Stream.generate(Signal::morse)
        .map(signal->Optional.ofNullable(signal));
    

    这里的Signal::morse是普通Supplier函数。(注意当使用::的时候,jvm会自动根据函数签名,将其包装成Supplier对象,不需要函数显示的实现Supplier接口)。

    消费Optional流

    optSingnalStream.limit(10)
        .filter(Optional::isPresent)
        .map(Optional::get)
        .forEach(System.out::println);
    

    首先通过filter过滤掉空值,再通过map选出包装value。如果不这么做,直接打印的话,是一个个Optional对象,而不是其内包含的值。
    示例代码StreamOfOptionals.java

    我变秃了,但是没变强