函数式编程
Java8的Monad
前面谈了java8的lambda,现在来了解Java8的Monad,Monad是范畴理论中一个词语,但是就像我们吃披萨不用到意大利一样,不学习饶舌的范畴论我们也可以理解Monad。范畴论中是如此隐晦地定义:
a monad in X is just a monoid in the category of endofunctors of X。
翻译软件都不知道单词endofunctors 。了解了闭包 Lambda,我们基本可以理解Monad是一个个lambda串联起来,说得标准一些,如下:
A monad is a structure that puts a value in a computational context
Monad是一种结构,这种结构能够将一个值放入一个可计算的上下文中。因为Lambda是一个和上下文环境有关的表达式,所以,这里对Monad的上下文理解就比较容易。
scala中的map就是一个monad,见:Scala入门之函数编程。下面我们看看在java8中如何自己实现一个monad。
M<A> unit(A a);
M<B> bind(M<A> ma, Function<A, M<B>> f);
interface M {
M<B> map(Function<A, B> f){
return flatMap( x -> unit( f.apply(x) ) );//
}
M<B> flatMap(Function<A, M<B>> f);
}
这里的map定义了一个monad,将flatMap和Unit绑定组合(串联)在一起。
下面看看monad的好处,假设有三个类,有关车的保险名称:
public class Person {
private Car car;
public Car getCar() { return car; }
}
public class Car {
private Insurance insurance;
public Insurance getInsurance() { return insurance; }
}
public class Insurance {
private String name;
public String getName() { return name; }
}
这里Insurance是保险,里面有保险名字,为了得到某个人的车辆的保险名字,需要下面:
String getCarInsuranceName(Person person) {
if (person != null) {
Car car = person.getCar();
if (car != null) {
Insurance insurance = car.getInsurance;
if (insurance != null) {
return insurance.getName()
}
}
}
return "Unknown";
}
需要经过很深入嵌套式的判断然后才能返回。
我们首先定义一个Optional :
public class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>(null);
private final T value;
private Optional(T value) {
this.value = value;
}
public<U> Optional<U> map(Function<? super T, ? extends U> f) {
return value == null ? EMPTY : new Optional(f.apply(value));
}
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> f) {
return value == null ? EMPTY : f.apply(value);
}
}
然后对前面三个模型重新编写,加入Optional:
public class Person {
private Optional<Car> car;
public Optional<Car> getCar() { return car; }
}
public class Car {
private Optional<Insurance> insurance;
public Optional<Insurance> getInsurance() { return insurance; }
}
public class Insurance {
private String name;
public String getName() { return name; }
}
寻找一个人的车辆保险名字的查询如下:
String getCarInsuranceName(Optional<Person> person) {
return person.flatMap(person -> person.getCar())
.flatMap(car -> car.getInsurance())
.map(insurance -> insurance.getName())
.orElse("Unknown");
}
第一句:person.flatMap(person -> person.getCar()) 得到的是 Optional<Car>类型的car.
.flatMap(car -> car.getInsurance())得到的是Optional<Insurance>的Insurance;
.map(insurance -> insurance.getName())