0x01 什么是Monads
简单说,Monad就是一种设计模式,表示将一个运算过程,通过函数拆解成互相连接的多个步骤。你只要提供下一步运算所需的函数,整个运算就会自动进行下去。
下面这两篇文章通过图解的方式讲解了什么是Monads
0x02 为什么要使用Monads?
一段不优雅的例子
编程时检查参数是否为null是最常见的功能。以下面的代码为例子:
public static class Userdetails{
public Address address;
public Name name;
}
public static class Name{
public String firstName;
public String lastName;
}
public static class Address{
public String houseNumber;
public Street street;
public City city;
}
public static class Street{
public String name;
}
public static class City{
public String name;
}
现在我想获得
user.address.street.name
,常见代码如下:
if(user == null )
return null;
else if(user.address == null)
return null;
else if(user.address.street == null)
return null;
else
return user.address.street.name;
这段检测代码淹没了真正取值的代码,阅读性非常不优雅
使用Monads来实现的例子
为了使用Lambda表达式,先定义一个函数接口:
SingleArgExpression
package function;
/**
* Created by haicheng.lhc on 13/04/2017.
*
* @author haicheng.lhc
* @date 2017/04/13
*/
@FunctionalInterface
public interface SingleArgExpression<P, R> {
public R function(P param);
}
然后创建一个类:
Option
package function;
import java.lang.reflect.ParameterizedType;
/**
* Created by haicheng.lhc on 13/04/2017.
*
* @author haicheng.lhc
* @date 2017/04/13
*/
public class Option<T> {
T value;
public Option(T value) {
this.value = value;
}
public <E> Option<E> flatMap(SingleArgExpression<T, Option<E>> mapper) {
if (value == null) {
return new Option<E>(null);
}
return mapper.function(value);
}
@Override
public boolean equals(Object rhs) {
if (rhs instanceof Option) {
Option o = (Option) rhs;
if (value == null) {
return (o.value == null);
} else {
return value.equals(o.value);
}
} else {
return false;
}
}
@Override
public int hashCode() {
return value == null ? 0 : value.hashCode();
}
public T get() {
System.out.println("hello");
return value;
}
}
接下来创建我们的测试类:
OptionExample
package function;
/**
* Created by haicheng.lhc on 13/04/2017.
*
* @author haicheng.lhc
* @date 2017/04/13
*/
public class OptionExample {
public static class Userdetails {
public Option<Address> address = new Option<>(null);
public Option<Name> name = new Option<>(null);
}
public static class Name {
public Option<String> firstName = new Option<String>(null);
public Option<String> lastName = new Option<String>(null);
}
public static class Address {
public Option<String> houseNumber;
public Option<Street> street;
public Option<City> city;
}
public static class Street {
public Option<String> name = new Option<>("alibaba");
}
public static class City {
public Option<String> name;
}
public static void main(String[] args) {
Option<Userdetails> userOpt = new Option<Userdetails>(new Userdetails());
//And look how simple it is now
String streetName = userOpt.flatMap(user -> user.address)
.flatMap(address1 -> address1.street)
.flatMap(street -> street.name)
.get();
System.out.println(streetName);
}
}
可以看出,通过这个方法获取
user.address.street.name
的时候,代码是非常简洁易懂的。
思路解析:
create a class Option that represents an optional value. And lets then have a map method that will run a lambda on its wrapped value and return another option. If the wrapped value is null, it will return an Option containing null without processing the lambda, thus avaoiding a null pointer exception