接上回,聊聊函子 functor
。
functor
是一个容器。该容器的 value
属性指向被包裹的数据;该容器的 map
方法对容器进行映射变换。
以下代码实现一个最普通的 functor
,称之为 Just
, 根据 map
的传参 fn
对 value
进行变换:
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; } }}
由于 Maybe
的 map
中包含判空的逻辑,因此调用 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 更易用。