函数式编程

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())

 

如何更好地使用Java 8的Optional?

什么是Monad?

用monad替代嵌套回调

Java8教程

用Java 8 lambda优化JDBC

使用Java8的Lambda实现Monda