接上回,聊聊函子 functor

functor 是一个容器。该容器的 value 属性指向被包裹的数据;该容器的 map 方法对容器进行映射变换。

以下代码实现一个最普通的 functor,称之为 Just, 根据 map 的传参 fnvalue 进行变换:

class Just {  private final T value;  private Just(T value) {    this.value = value;  }  public static  Just of(T value) {    return new Just(value);  }  public  Just map(Function fn) {    return of(fn.apply(this.value));  }  public T flat() {    return this.value;  }}

map 会继续返回 functor,因此可以链式调用:

public static void main(String[] args) {  System.out.println(    Just.of(1)      .map(a -> a + 2)      .map(a -> a * a)      .flat()  );}

将数据用容器 functor 包装,通过唯一的 map 方法对数据进行变换,使得我们很容易封装类似切面的逻辑。例如:将判空的逻辑封装到 map 中,得到函子 Maybe

class Maybe {  public static final Maybe EMPTY = new Maybe(null);  private final T value;  private Maybe(T value) {    this.value = value;  }  public static  Maybe of(T value) {    if (value == null) {      return (Maybe) EMPTY;    } else {      return new Maybe(value);    }  }  public  Maybe map(Function fn) {    if (this == EMPTY) {      return (Maybe) EMPTY;    } else {      return of(fn.apply(this.value));    }  }  public T orElse(T v) {    if (this == EMPTY) {      return v;    } else {      return this.value;    }  }}

由于 Maybemap 中包含判空的逻辑,因此调用 map 不用考虑空值,只需要在最后考虑空值。它使得我们更多地关注正常数据流。

class Person {  public String name;  public Car car;}class Car {  public String label;}public class Test {  public static void main(String[] args) {    Person apolis = new Person();    apolis.name = "apolis";    System.out.println(      Maybe.of(apolis)        .map(p -> p.car)        .map(c -> c.label)        .orElse("no car")    );  }}

Maybe 函子在 java 中对应的实现是类 Optional

如果你能找出下面代码里的问题,就证明你已经掌握了 Optional 的用法:

// 问题代码String name = "";Optional optional = result.getPrimaryMap()  .values().stream().findFirst();if (optional.isPresent()) {  name = optional.get();}

java 有了 Optional,可以表达更多的信息。例如:一个方法的返回值类型是 Optional,会告诉调用者,该方法有可能返回空值。如果我们能统一规范:会返回空值的方法都改为返回 Optional,将使 api 更易用。