Java|Effective Java 在工作中的应用总结( 二 )
不可变类(immutable class)是指类对应的实例被创建后 , 就无法改变其成员变量值 。 即实例中包含的所有信息都必须在创建该实例的时候提供 , 并在对象的生命周期内固定不变 。
不可变类一般采用函数(functional)模式 , 即对应的方法返回一个函数的结果 , 函数对操作数进行运算但并不修改它 。 与之相对应的更常见的是过程的(procedure)或者命令式的(imperative)做法 。 使用这些方法时 , 将一个过程作用在它们的操作数上 , 会导致它的状态发生改变 。
如在“若有多个构造器参数时 , 优先考虑构造器”一节中提到 , 不可变对象比较简单 , 线程安全 , 只有一种状态 。 使用该类的开发者无需再做额外的工作来维护约束关系 。 另外 , 可变的对象可以有任意复杂的状态 。 若 mutator 方法(e.g. update)无详细的描述 , 开发者需要自行阅读方法内容 。 笔者经常会花费较多时间弄清楚在某方法内 , 可变对象的哪些字段被更改 , 方法结束后会不会影响后续的对象操作 。 笔者推荐传入不可变对象 , 基于此用更新的参数创建新的不可变对象返回 。 虽然会创建更多的对象 , 但是保证了不可变形 , 以及更可读性 。
推荐:Guava Collection之Immutable类
笔者在日常开发中倾向将 Immutable 类(ImmutableList , ImmutableSet , ImmuableMap)和上文提到的函数模式集合 , 实现mutator 类方法 。
import static com.google.common.collect.ImmutableList.toImmutableList;import com.google.common.collect.ImmutableList;import com.google.common.collect.ImmutableMap;/** 推荐 */private static final ImmutableMapString IntegerSAMPLE_MAP = ImmutableMap.of(\"One\" 1 \"Two\" 2);/** 推荐:确保原input列表不会变化 */public ImmutableListTestObjupdateXXX(ImmutableListTestObjinput) { return input.stream() .map(obj -obj.setXXX(true)) .collect(toImmutableList());/** 不推荐:改变input的信息 */public void filterXXX(ListTestObjinput) { input.forEach(obj -obj.setXXX(true)); 三 泛型篇 1 列表优先于数组
数组是协变的(covariant) , 即Sub为Super的子类型 , 那么数组类型Sub[
就是Super[
的子类型;数组是具体化的 , 在运行时才知道并检查它们的元素类型约束 。 而泛型是不可变的和可擦除的(即编译时强化它们的类型信息 , 并在运行时丢弃) 。
需要警惕 public static final 数组的出现 。 很有可能是个安全漏洞!
四 方法篇 1 校验参数的有效性
若传递无效的参数值给方法 , 这个方法在执行复杂、耗时逻辑之前先对参数进行了校验(validation) , 便很快就会失败 , 并且可清楚地抛出适当的异常 。 若没有校验它的参数 , 就可能会在后续发生各种奇怪的异常 , 有时难以排查定位原因 。
笔者认为 , 微服务提供的API request 也应沿用这一思想 。 即在API 请求被服务处理之前 , 先进行参数校验 。 每个request应与对应的request validator 绑定 。 若参数值无效 , 则抛出特定的ClientException(e.g. IllegalArgumentException) 。
2 谨慎设计方法签名
谨慎地选择方法的名称:执行某个动作的方法通常用动词或者动词短语命名:createXXX , updateXXX , removeXXX , convertXXX , generateXXX对于返回boolean值的方法 , 一般以 is 开头:isValid , isLive , isEnabled 避免过长的参数列表:目标是四个参数 , 或者更少 。 当参数过多时 , 笔者会使用Pair , Triple或辅助类(e.g. 静态成员类) public class SampleListener { public ConsumeConcurrentlyStatus consumeMessage(String input) { SampleResult result = generateResult(input); ...private static SampleResult generateResult(String input) { .../** 辅助类 */ private static class SampleResult { private boolean success; private ListStringxxxList; private int count;3 返回零长度的数组或者集合 , 而不是null
- meta|促进更逼真AR/VR体验,Meta正在开发全新空间音频工具
- 在昨日推文中,王者荣耀将以“____文化”为主题推出限定皮肤,为乡村振兴加油? 王者荣耀6月28日每日一题答案
- ColorOS|绿厂又在憋大招?新系统和新产品接踵而至
- 零售业|确定涨价!iPhone14四款新机全面涨价!国行也在其中!
- 数字化转型|新一代iPad Pro正在路上 外观、配置大升级
- 月球也在太阳系的宜居带中,为何不能产生生命?原来个头太小了
- 在南极3500米的深海,科学家发现新物种,这是个透明的肉球?
- 新发现恐龙可能在灾难性的太空岩石撞击地球之前就已经灭绝了
- 中美科学家在琥珀中发现1亿年前的虱子,它们以恐龙羽毛为食
- 为什么现在很少有人提及“克隆技术”了?“克隆技术”有何缺点?
