第七章、方法

第三十八条、检查参数的有效性

  1. 如果传递无效的参数值给方法,这个方法在执行之前应该先对参数进行检查,那么它很快就会失败,并清楚地出现适当的异常。如果不做参数检查,则会出现很多不可控的错误。

  2. 对于公有的方法,要用Javadoc的@throws标签在文档中说违反参数值限制时会抛出的异常。通常为IllegalArgumentExceptionIndexOutOfBoundsException或者NullPointerException。一旦在文档中记录了对于方法参数的限制,并且记录了一旦违反这些限制将要抛出的异常,强加这些限制就是非常简单的事了。

     /**
      * @Param m the modulus,which must be positive
      * @return this mod m
      * @throws ArithmeticException if m is less than or equal to 0
      */
     public BigInteger mod(BigInteger m){
         if(m.signum() <= 0)
             throw new ArithmeticException("Moduus <=0" + m);
         ...
     }
    
  3. 对于未被导出的方法,作为包的创建者,你可以控制这个方法将在哪些情况下被调用,因此你可以,也应该确保只将有效的参数值传递进来。非公有的方法通常应该使用断言assertion来检查它们的参数。

     private static void sort(long[] a,int offset,int length){
         assert a != null;
         assert offset >= 0 && offset <= a.length;
         assert length >= 0 && length <= a.length - offset;
         ...
     }
    

    本质上来讲,这些断言是在声称被断言的条件将会为真,无论外围包的客户端如何使用它。不同于一般的有效性检查,断言如果失败,将会跑出AssertionError

  4. 对于有些参数,方法本身没有用到,却被保存起来供以后使用。构造器Constructor正是代表这一原则的特殊类型。检查构造器的参数有效性是非常重要的。

  5. 有一个很重要的例外:在有些情况下有效性的检查工作非常昂贵,或者根本是不切实际的,而且有效性的检查已隐含在计算过程中完成.

    例如:考虑一个为对象列表排序的方法:Collection.sort(List),列表中的所有对象都必须是可以互相比较的。这些是sort函数应该做的事情,因此提前检查的意义不大。然而,不加选择地使用这些方法将会导致失去失败原子型。
    有时候,某些计算会隐式地执行必要的有效性检查,如果检查不成功,会抛出错误的异常。这与文档中标明的这个方法将要抛出的异常不符,这种情况下,应该使用异常转译技术,将计算过程中抛出的异常转换成正确的异常。

  6. 总结:每当编写方法或者构造器的时候,应该先考虑它的参数有哪些限制。应该把这些限制写到文档中,并且在这个方法体的开头处,通过显式的检查来实施这些限制。养成这样的习惯是非常重要的。


第三十九条、必要时进行保护性拷贝

  1. 对于构造器的每个可变参数进行保护性拷贝是必要的。保护性拷贝是在检查参数有效性之前进行的,并且有效性检查是针对拷贝后的对象
    this.start = new Date(start.getTime());

  2. 针对访问方法提供了对其内部可变成员的访问能力,则需要修改访问方法,使之返回可变内部域的保护性拷贝即可。
    return new Date(start.getTime());

  3. 参数的保护性拷贝不仅仅针对不可变类:

    每当编写方法或者构造器时,如果它允许客户提供的对象进入到内部数据结构中,则有必要考虑一下,客户提供的对象是否有可能是可变的。如果是,就要考虑你的类是否能够容忍对象进入数据结构之后发生变化。如果答案是否定的,就必须对该对象进行保护性拷贝,并且让拷贝之后的对象而不是原始数据对象进入到数据结构中。
    在内部组件被返回给客户端之前,对它们进行保护性拷贝也是同样的道理。不管类是否是可变的,在把一个指向内部可变组件的引用返回给客户端之前,应该加倍认真考虑。【记住:长度非零的数组总是可变的,因此,把内部数组返回给客户端之前,应该总要进行保护性拷贝】

  4. 真正的启示在于:尽量使用不可变的对象作为对象内部的组件

  5. 如果拷贝的成本得到限制,并且类信任它的客户端不会不恰当地修改组件,就可以在文档中指明客户端的职责是不得修改受到影响的组件,以此来代替保护性拷贝。


第四十条、谨慎设计方法签名

若干API设计技巧:

  1. 谨慎地选择方法的名称:方法的名称应该遵循标准的命名习惯,易于理解,同一个包中风格一致;选择大众认可的名字。

  2. 不要过于追求提供便利的方法:每个方法都应该尽其所能,对于类和接口所支持的每个动作,都提供一个功能齐全的方法。避免方法太多。

  3. 避免过长的参数列表:目标是四个参数或更少。相同类型的长参数序列格外有害,API用户不仅无法记住参数的顺序,而且一旦弄错了顺序,编译不会报错。

    缩短长参数列表的方法:

    • 把方法分解成多个方法,每个方法需要这些参数的一个子集。
    • 创建辅助类用来保存参数的分组。这些辅助类一般是静态成员类。
    • 从对象构建到方法调用都采用Builder模式,如果方法中含有多个参数,尤其是当它们中有些是可选的时候,最好定义一个对象来表示所有参数,并允许客户端在这个对象上进行多次setter调用。一旦设置了需要的参数,客户端就调用对象的”执行“方法,它对参数进行有效性检查,并执行实际的计算。
    • 对于参数类型,优先使用接口而不是类。如果使用的类而不是接口,就限制了客户端只能传入特定的实现。
    • 对于boolean参数,要优先使用两个元素的枚举类型。它是代码更容易阅读和编写。

第四十一条、慎用重载

  1. 对于重载(overloaded method)方法的选择是静态的,而对于被覆盖(overridden method)的方法选择则是动态的。选择被覆盖的方法的正确版本是在运行时进行的,选择的依据是被调用方法所在对象的运行时类型。

  2. 因为覆盖机制是规范,而重载机制是例外,所以应该避免胡乱地使用重载机制:安全而保守的策略是永远不要导出两个具有相同参数数目的重载方法。只要当两个重载方法在同样的参数上被调用时,它们执行相同的功能,重载就不会带来危害。

        public boolean contentEquals(StringBuffer sb){
            return contentEquals((CharSequence) sb);
        }
    

第四十二条、慎用可变参数Varargs

  1. 可变参数方法接受0或者多个指定类型的参数。可变参数机制通过先创建一个数组,数组的大小为调用位置所传递的参数数量,然后将参数值传到数组中,最后将数组传递给方法。

  2. 当需要让方法带有不定数量的参数时,可变参数非常有效。

       static int sum(int... args){
           int sum = 0;
           for(int arg:args){
               sum += arg;
           }
           return sum;
       }
    
  3. 不宜过度使用,使用不当会产生混乱的结果。


第四十三条、返回零长度的数据或者集合,而不是null

  1. 对于一个返回null而不是零长度数组或者集合的方法,几乎每次处理该方法都需要曲折的处理方法,很容易出错。

  2. 零长度数组是不可变的,可以被自由共享。在下面的习惯用法中,零长度数组常量被传递给toArray方法,以指明所期盼的返回类型。

       private final List<Cheese> cheesesInStock = ...;
       private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
       public Cheese[] getCheeses(){
           return cheessInStock.toArray(EMPTY_CHEESE_ARRAY);
       }
    
  3. 集合值的方法也可以做成在每当需要返回空集合时都返回同一个不可变的空集合.Collections.emptySet,emptyListemptyMap方法正是所需要的。

  4. 总结:返回类型为数据或者是集合的方法没理由返回null而不是返回一个零长度的数组或者集合。

第四十四条、为所有导出的API元素编写文档注释

  1. Java环境中提供成为Javadoc的实用工具,利用特殊格式的文档注释doc comment,根据源代码自动生成API文档。
  2. 为了正确地编写API文档,必须在每个被导出类、接口、构造器、方法和域声明之前增加一个文档注释。
  3. 方法的文档注释应该简洁地描述它和客户端之间的约定。应该说明这个方法做了什么,而不是如何完成的。还需要列举出这个方法的所有前提条件和后置条件;还需要描述它的副作用(side effect):系统状态中可以观察到的变化。 @param@return以及抛出的异常(@throws
  4. 每个文档注释的第一句话成了该注释所属元素的概要描述。
  5. 总结:对于所有可导出的API元素来说,使用文档注释应该被看作是强制性的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容

  • 对象的创建与销毁 Item 1: 使用static工厂方法,而不是构造函数创建对象:仅仅是创建对象的方法,并非Fa...
    孙小磊阅读 1,954评论 0 3
  • 1.shabby--looking There is more to the shabby--looking th...
    减肥的女孩阅读 282评论 0 0
  • 我只有一颗心 在秋千上荡漾 望着远处的城墙 我辗转在巷子里 或者是胡同口儿 轻触石板处的沧桑 闻着老城香 抬头轻嗅...
    季晓蒿阅读 381评论 6 21
  • 语法 参数说明: format-string:为格式控制字符串 arguments:为参数列表。 实例: 展现 p...
    AsaGuo阅读 657评论 0 0
  • 总觉得不会活太久,所以对很多事情都无所谓。爱过恨过之后,风轻云淡,做好自己,过好自己的生活,凡是向内求,他人无关。
    二律背反_心璇阅读 154评论 0 0