====== 空值处理 ======
* 不合法的对象实例化应该失败
* 校验集合中的数据是否为null
* 可能返回空的对象一定要用Optional封装
* 映射操作,返回值一定是Optional类型
* map操作
* 数据库操作
* 转换操作,返回值可能是Optional类型
* 字符串转成驼峰(不是Optional类型)
* 按逗号分割字符串,返回第二个字符串(是Optional类型)
* 但凡有一定业务逻辑的数据,都要用对象包装起来,这样可以在创建的时候验证数据是否合法
* 如:需要各种维度拼接成数据库的key。就可以创建一个类DBKey将拼装key的过程封装起来
===== 错误数据的定义 =====
* null,null虽然不是错误,但会导致各种错误
* 不符合业务规则的数据
===== 消灭错误数据 =====
* 阻止错误数据产生(在源头扼杀错误)
* 一个简单数据,要么一定有值(如 String),要么可能为空(Optional)
* 注意,List,Map中也不能出现null,建议使用guava中的集合(不允许出现null元素)
* 外部函数的返回值,用Optional封装
* 对于需要序列化而无法定义成Optional类的对象,设置getXxx()的返回值为Optional类型
* 一个复杂数据,在实例化时,必须判断是否满足业务规则。否则实例化失败
* 阻止错误蔓延
* 调用方绝不传递错误参数
* 严格遵守函数的参数约定(参数,返回值就是【契约】,调用方必须要遵守)
* 被调用方绝不返回错误数据
* 如果无法计算,则抛出异常
* 一定是传参不对,只有调用方才知道怎么处理
最终每个对象、每个函数都是可信任的。数据、对象在创建的时候保证合法,就无需每次使用前都判断一次了。世界清静了
==== 参数约定 ====
参数约定越严格越好,并且被调用函数需要尽量考虑到每种情况(如:List类型中的元素是否允许为空)
id: 没有任何修饰,默认一定不为空
type: Optional修饰,可能为null
value: 必须不为空,且里面不允许存在空元素。 (语言层面无法限制,推荐用注解说明,函数注释说明也可以)
返回值:Optional修饰,可能为null
public Optional fun(Integer id,
Optional type,
@AllNoneNull List value) {
}