====== 空值处理 ====== * 不合法的对象实例化应该失败 * 校验集合中的数据是否为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) { }