EffectiveJava-6-方法

检查参数的有效性

绝大多数方法和构造器对于传递给它们的参数值都会有某些限制,例如,索引值必须非负数,对象引用不能为null,我们应该在文档中清楚的指明这些限制,并在方法体的开头处检查这些参数,以强制施加这些限制,清楚的抛出适当的异常,以便在发生错误后尽快的检测出错误,例如下面这样:

如果不检查:

1. 可能在处理过程中失败,并产生令人费解的异常

2. 更糟糕的情况是正常返回,但计算出错误的结果

3. 最糟糕的是正常返回,但使得某个对象处于被破坏但状态,在将来某个不确定的时候,某个不想干的点上引发错误

对于某些参数,方法本身没有用到,却被保存起来供以后使用,检验这类参数的有效性尤为重要,构造器就是属于这种情景之一。

例外情况:有些情况下有效性检查工作是非常昂贵的,或是根本不切实际的,或是有效性检查已经隐含在计算过程中完成来。

必要时进行保护性拷贝

假设类的客户端会尽其所能来破坏这个类的约束条件,因此你必须保护性的设计程序;

对于构造器的每个可变参数进行保护性拷贝是必要的 请看下面例子:

下面使用保护性拷贝进行改进:

保护性拷贝会使性能收到一定损失,如果类信任它的客户端不会进行不恰当的修改组件,可以在文档中指明客户端的职责是:不得修改受到影响的组件,以此来代替保护性拷贝。

谨慎设计方法签名

谨慎的选择方法的名称:方法名称应始终遵循标准的命名习惯,1. 应易于理解并与同包中其他方法名称风格一致,2. 应选择与大众认可的名称相一致的名称,如java类库的API;

不要过于追求提供便利的方法:每个方法都应该尽其所能,功能齐全,方法太多会使类难以学习,使用,文档化,测试和维护,会使接口的实现者和用户的工作变得复杂;

避免过长的参数列表:

1. 目标是4个或更少,相同类型的长参数序列格外有害,如margin(int l,int t,int r,int b...),很可能不小心弄错顺序, 而程序仍可编译运行,然而的到错误的结果,缩短参数列表的方法:a. 把方法分分解成多个方法;;b. 创建辅助类;c. 使用建造者模式(builder模式);
2. 对于参数类型,要优先使用接口而不是类,例如,我们经常使用的集合类,应优先使用Map做参数而不是HashMap,优先使用List而不是ArrayList;
3. 对于boolean参数,要优先使用两个元素的枚举类型,更具有易读性,方便编写;

慎用重载

对于重载方法的选择是静态的,对于重写/覆盖方法的选择是动态的,选择被覆盖的方法的版本是在运行时进行的,选择的依据是被调用方法所在对象的运行时类型;
例如下面代码中对问题:想用重载区分传入参数对实际类型,然而结果只是选择了引用声明的类型对应的重载方法:

一个安全而保守的策略是:

1. 永远不要导出两个具有相同参数数目的重载方法(可以给方法起不同的名称而不是使用重载机制),对于可变参数(varargs)不要重载它。例如ObjectOutputStream类的write方法:writeBoolean (boolean) , writeInt(int), writeLong(long), 而不是使用重载;

2. 对于构造器则是应该进了使用静态工厂方法代替重载,或使用builder模式;

3. 如果几个重载方法的参数直接不存在任何关系,如read(int),read(List),read(String[]),当然是可以使用重载的;

4. 自动装箱引发的一个问题,下面程序中的remove,希望去除0,1,2;然而由于自动装箱对Integer对象和int值进行了转换,导致调用了remove不同对重载方法,所以得到了意料外对结果。

慎用可变参数

可变参数方法:可匹配不同长度的变量的方法,接收0或多个指定类型的参数,其机制是通过先创建一个数组, 数组的大小为调用位置所传递的参数数量,然后将参数值传到数组中,最后将数组传递给方法

可变参数为了printf和反射机制而设计,如printf(String format, Object ... args)

不必改造具有final数组参数的每个方法,只当确实是在数量不定的值上执行调用时才使用可变参数;

缺点:

1. 客户端调用这个方法时可能没有传递参数进去,编译时并不会失败,但可能会造成运行时错误,应进行显示的有效性检查,如args.length==0的情况。

2. 可变参数方法的每次调用都会导致进行一次数组分配和初始化

如果真的需要可变参数的灵活性,可以考虑下面重载的实现方案:

返回零长度的数组或集合,而不是null

若直接返回null,几乎每次用到该方法时都需要额外的代码来处理null的情况,一旦忘记处理就会出错;有人可能觉得返回null避免来分配数组或创建对象的开销,然而

1. 相对于一个可能导致运行时崩溃的定时炸弹,此时担心性能问题是不明智的,
2. 可以用一个私有静态的空数组进行共享,避免每次调用都创建新的对象

3. 可以使用java内置的空集合避免自己创建的开销:
Collections.emptyList(),Collections.emptyMap(),Collections.emptySet();

为所有导出的API元素编写文档注释

为了正确的编写API文档,必须在每个被导出的类,接口,构造器,方法和域声明之前增加一个文档注释,方便用javadoc导出api文档;

方法的文档注释应该简洁的描述出它和客户端之间的约定。

我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号”今阳说“接收我的最新文章

猜你喜欢

转载自blog.csdn.net/o118abcdef/article/details/112601612