Java 中Optional的用法一则

一直以来都觉得Java引入的Optional相当鸡肋。虽说目的是为了避免返回null造成NPE,但是由于大量现存的代码没有采用函数式风格,加上有些程序员对这个特性的理解不足。往往看到一些一言难尽的代码。
比如:

        Optional optional = Optional.ofNullable(getSomething());
        optional.ifPresent( s -> {
            System.out.println(s);
        });

或是

        Optional optional = Optional.ofNullable(getSomething());
        if (optional.isPresent()) {
            System.out.println(optional.get());
        }

面对这种代码很难不让人产生何必多此一举的想法。

今天偶然发现在一个场景中Optional还是有点用处的。
首先先造一个容易产生NPE的结构。
这个结构本身没什么含义,就是为了方便写出a.b.c.d这样的代码。
注意:这种代码风格是非常不好的风格,违反了迪米特法则。容易NPE是不良设计附带产生的问题,所以如果能重构消除这种代码是更好的解决方案

    public static class Wrap {
        T child;
        public Wrap(T child) {
            this.child = child;
        }
        static  Wrap of(T child) {
            return new Wrap<>(child);
        }
    }

有了这个递归的结构,就可以造出任意层嵌套的结构。

    Wrap>> wrap1 = Wrap.of(Wrap.of(Wrap.of("A")));
    Wrap>> wrap2 = Wrap.of(Wrap.of(null));
    Wrap>> wrap3 = Wrap.of(null);

如果客户代码从最外层依次访问这个结构(违反信息隐藏原则),而结构中的任何一层都有为null的可能性。那就很容易出现NPE。
比如

    assertEquals(wrap2.child.child.child, null);  //throw NPE

要安全的处理也相当的繁琐。

    if (wrap2.child != null) {
        if (wrap2.child.child != null) {
            ...
        }
    }

这里可以用Optional相对简洁的处理这个问题。

    String s = Optional.ofNullable(wrap2)
            .map(w -> w.child)
            .map(w -> w.child)
            .map(w -> w.child)
            .orElse("");
    assertEquals(s, ""); 

简单来说就是:

  • 不要急着从Optionalget出值来,让FP代码飞一会
  • 使用map来处理Optional中包装的值,而不要采用ifPresent这样产生副作用的操作
  • map可以连续使用,每次向下一层,就可以不必在每层处理null的判断

你可能感兴趣的:(Java 中Optional的用法一则)