热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【转】effectivejava笔记4

from:http:blog.csdn.netilibabaarchive200905214207511.aspxNO.26谨慎使用重载一个常见的问题是:

from:http://blog.csdn.net/ilibaba/archive/2009/05/21/4207511.aspx

NO. 26 谨慎使用重载

一个常见的问题是:

public static String classify(Set s)

{ return “set”;}

public static String classify(List l)

{return “list”;}

public static String classify(Collection c)

{return “unknown collection”;}

public static void main(String[] args)

{ Collection[] tests=new Collection[]{

    new HashSet(), new ArrayList(), new HashMap.values()};

for(int i=0;i

程序结果是print出三个unknown collection。因为classify被重载了,到底调用哪个重载函数叔编译时刻决定的,因为编译时,大家的参数类型都是Collection。

避免方法重载机制的混淆。永远不要导出两个具有相同参数数目的重载方法,是一个安全而保守的策略。

至少应该保证,当传递同样的参数时,所有的重载方法行为一致。

NO.27 返回零长度的数组而不是null
    如果返回null,对于每次调用到该方法的时候都需要做null判断,否则很容易抛出空指针异常,推荐返回一个零长度的数组,在通常情况下,这样的做法对性能几乎没有影响。


NO.28 为所有导出的API元素编写文档注释
需要增加注释的地方:类、接口、构造函数、方法和域声明,

方法注释的内容:

调用该方法的前提条件;
调用后的后续处理(如捕获异常);
副作用(如方法启动线程后带来的安全性);
参数@param Describe;
返回@return Describe;
异常@throws  if.....;

注意:注释中可以适用

等HTML标签&#xff0c;但>,<等标签需要转义。


NO.29 讲局部变量的作用域最小化
在第一次适用局部变量的地方声明他&#xff1b;&#xff08;不要过早地声明它&#xff09;
要防止局部变量在“使用它的块”之外声明&#xff0c;这样会防止局部变量被意外使用&#xff1b;
几乎每一个局部变量的需要初始化&#xff0c;如果没有足够的信息来对一个变量进行有意义的初始化&#xff0c;那就推迟这个声明&#xff0c;直到可以初始化为止&#xff1b;
其他的方法&#xff0c;例如&#xff0c;把一个变量多的方法分成两个&#xff0c;每次操作一个方法&#xff0c;减少变量之间的干扰。


NO.30 了解和使用库
    不要从头发明轮子&#xff0c;如果你要做的事情是很常见的&#xff0c;就去查下有没有这样的实现类&#xff0c;如果有&#xff0c;则使用它&#xff0c;这样会降低你实现相应功能的投入和代码的出错率。


NO.31 如果要求精确的答案&#xff0c;请避免使用 float和 double
      float和double不适合表示货币&#xff0c;在平时的使用中应该避免。

例如&#xff1a;System.out.println(1.00-9*.10); //会输出0.09999999999999998

如果希望系统来处理十进制的小数点&#xff0c;可以使用 BigDecimal。如果不考虑小数的处理&#xff0c;数值范围没有超过9位的则可以用int来处理&#xff0c;如果不超过18位的&#xff0c;则可以用long来处理&#xff0c;超过18位的就必须用 BigDecimal处理。


NO.32 如果其他类型更适合&#xff0c;则尽量避免使用字符串
    如果可以使用更加合适的数据类型&#xff0c;或者可以编写更加恰当的数据类型&#xff08;如 DO、 POJO、枚举等&#xff09;&#xff0c;那么应该避免使用字符串来表示对象&#xff0c;若使用不当&#xff0c;字符串比其他类型更加笨拙&#xff0c;缺乏灵活性。


NO.33 了解字符串连接的性能
    为连接 N个字符串而重复得地使用“ &#43;”连接&#xff0c;要消耗N的平方级别的时间。为了获得更高的性能&#xff0c;请使用 StringBuffer代替 String。


NO.34 通过接口引用对象
    应该优先使用接口而不是类来引用对象&#xff0c;如果有合适的接口存在&#xff0c;那么对参数的返回值、变量和域的声明都应该使用接口类型&#xff0c;如 Vector是List接口的实现&#xff0c;在声明时应该如下&#xff1a;

    List subscribers &#61; new Vector();  

    //而不是

    Vector subscribers &#61; new Vector(); 

例外的情况&#xff1a;

① 当没有合适的接口存在&#xff0c;可以用类而不是接口来引用一个对象&#xff0c;如&#xff1a; String、 Integer&#xff1b;

② 当一个对象是基本类型的类&#xff0c;而不是接口时&#xff0c;应该用相关的基类引用这个对象&#xff0c;如&#xff1a; java.util.TimerTask;

③ 当一个类实现了一个接口&#xff0c;但它提供了接口中不存在的额外方法&#xff0c;如果程序依赖于这些额外的方法&#xff0c;那么这样的类应该只被用来引用它的实例&#xff0c;永远不应该被用作参数类型。


NO.35 接口优先于映像机制&#xff08;反射机制&#xff09;
    反射机制是 Java一项强大的功能&#xff0c;给定一个class实例&#xff0c;你可以获得constructor、method和field实例。对于一些特定复杂的程序设计中非常必要&#xff08;如现在很流行的 spring框架&#xff09;&#xff0c;但在并非必须使用反射机制时&#xff0c;尽量避免使用反射&#xff0c;原因如下&#xff1a;
     ① 它在编译时不会进行类型检查&#xff1b;
     ② 实现代码冗长乏味&#xff0c;不易阅读&#xff1b;
     ③ 性能与一般的方法调用相比&#xff0c;要低下很多&#xff1b;
    如果一个程序必须要与编译时未知的类一起工作&#xff0c;那么最好是用反射实例化对象&#xff0c;而访问对象时使用编译时刻已知的某个接口或者父类。


NO.36 谨慎地使用本地方法
    尽量使用 Java自身提供的方法来代替本地方法&#xff08;如用 Java提供的新功能来代替以前只有 C语言能实现个的功能&#xff09;&#xff0c;这样可以使系统变得更加安全&#xff0c;系统可移植性更高&#xff0c;也使代码变得更加容易阅读&#xff0c;如果一定要使用本地方法&#xff0c;请加强测试&#xff0c;并尽可能的少用。


NO.37 谨慎地进行优化
    努力写好的程序而不是快的程序&#xff0c;程序要体现信息隐藏的原则&#xff0c;性能问题应该是设计阶段就考虑&#xff0c;要避免那些限制性能的设计决定&#xff0c;如&#xff1a;应该用复合模式的公有类使用继承&#xff0c;则该类的性能永久的受其父类性能的影响&#xff0c;为了获得好的性能而对 API进行修改并非是一个好的做法&#xff0c;通常&#xff0c;这些做法对性能并没什么多大的影响&#xff0c;如果一个系统有了清晰、简明、结构良好的实现&#xff0c;请谨慎对其进行优化&#xff0c;因为 80%的性能问题存在于 20%的代码中&#xff0c;找出影响性能的代码才是问题的关键&#xff0c;可以借助一些性能分析的工具。

 

第38条&#xff1a;遵守普遍接受的命名惯例
java的命名惯例分为两大类&#xff1a;字面的和语法的。 字面命名惯例涉及包、类、接口、方法和域。     包的名字是层次结构的&#xff0c;用句号分隔第一部分。每一部分的长度不要超过8&#xff0c;由小写字母和数字组成&#xff08;数字少见用&#xff09;&#xff0c;鼓励使用有意义的缩写。除了java和javax外&#xff0c;一般以域名做开头&#xff0c;顺序是顶级域名放在最前面。     类和接口的名字应至少1至多个单词&#xff0c;每个单词的首字母大写&#xff08;驼峰试)&#xff0c;尽量避免缩写。

方法和域的名字与类和接口的名字遵守相同的字面惯例&#xff0c;只是第一个首字母要小写常量域要全部字母都大写&#xff0c;词之间通过下划线区分。

语法命名惯例比字面惯例更灵活。

  1. 类通常用一个名词或名词短语&#xff0c;接口或者与类相同&#xff0c;或者以"-able"或"-ible"结尾的形容词。
  2. 执行某个动作的方法&#xff0c;常用一个动词或动词短语&#xff0c;
  3. 对于返回boolean类型的方法&#xff0c;名字常以“is"开头后加一个名词或形容词或短语&#xff0c;
  4. 如果返回的不是boolean&#xff0c;则常用一个名词/短语&#xff0c;或以"get"开头的动词短语。
  5. 如果一方法所在的类是一个Bean&#xff0c;则强制要求以get开头。
  6. 如果类包含对属性操作&#xff0c;常用setAttribute或getAttribute格式命名。

转换对象类型的方法&#xff0c;

  1. 如果返回不同类型的独立的对象&#xff0c;则称为toType
  2. 如果返回一个视图&#xff0c;则用asType,
  3. 如果返回与被调用对象同值的原语类型&#xff0c;称为typeValue
  4. 静态工厂的方法&#xff0c;常用valueOf或getInstance.

 

NO.39 只针对不正常的条件才使用异常

异常只应该被用于不正常的条件&#xff0c;它们永远不应被用于正常的控制流。

下面是一个用异常作遍历结束条件的滥用异常的例子&#xff1a;

  1. //horrible abuse of exceptions. Don&#39;t ever do this!
  2. try{ 
  3. int i&#61;0; 
  4. while(true)a[i&#43;&#43;].f(); 
  5. }catch(ArrayIndexOutOfBoundsException e){ 
  6.   ... 

其错有三&#xff1a;

1、创建、抛出和捕获异常的开销是很昂贵的。因为它的初衷是用于不正常的情形&#xff0c;少有jvm会它进行性能优化。

2、把代码放在try-catch中会阻止jvm实现本来可能要执行的某些特定的优化。

3、有些现代的jvm对循环进行优化&#xff0c;不会出现冗余的检查。

完全可以使用标准的实现方式&#xff1a;

  1. for(int i&#61;0;i
  2.     a[i].f(); 

这条原则也适用于API设计。一个设计良好的API不应该强迫它的客户为了正常的控制流而使用异常。如果类中有一个”状态相关”的方法&#xff0c;即只有 特定的条件下可被调用的方法&#xff0c;则这个类也应有一个单独的“状态测试”方法&#xff0c;以为调用这个状态相关方法前的检查。如Collection类的next方法和 hasNext方法。

  1. for(Iterator i&#61;collection.iterator();i.hasNext();){ 
  2.     Foo foo&#61;(Foo)i.next(); 
  3.     ... 
  4. }  

 

第40条&#xff1a;对于可恢复的条件使用被检查的异常&#xff0c;对于程序错误使用运行时异常
    java提供了三种可抛出的异常&#xff1a;被检查的异常&#xff08;checked Exception&#xff09;、运行时异常&#xff08;run-time Exception&#xff09;和错误(error)。 如果期望调用者在调用时出现的异常能够恢复&#xff0c;则应该使用被检查的异常&#xff0c;通过抛出一个被检查的异常&#xff0c;强迫调用者在catch中处理该异常&#xff0c;或者将异常传播到外面。
对于一个方法声明要抛出的每一个被检查的异常&#xff0c;它是对API用户的一种潜在指示&#xff1a;与异常相关联的条件是调用这次个方法的一种可能结果。
两种未被检查的可抛出结构&#xff1a;运行时异常和错误&#xff0c;在行为上相同的&#xff0c;它们都不需要、也不应该被捕获的抛出物。你所实现的所有未被检查的抛出结构都应是 RuntimeException的子类。定义一个非Exception、RuntimeException或Error子类的抛出物是可行的&#xff0c;但从行为 意义上它等同于普通的被检查异常&#xff08;即Exception子类而非RuntimeException子类&#xff09;.
异常是个完全意义上的对象&#xff0c;在其上可以定义任意的方法。因被检查的异常往往指示了可恢复的条件&#xff0c;所以可通过定义方法&#xff0c;使调用者可获得一些有助于恢复的信息。具体可参见“Java异常的分类”http://blog.csdn.net/ilibaba/archive/2009/03/07/3965359.aspx


NO.41 避免不必要地使用被检查的异常
    与返回代码不同&#xff0c;被检查的异常强迫程序处理例外的情况&#xff0c;从而大大地提高了程序的可靠性。而过分地使用被检查的异常&#xff0c;则增加了不可忽视的负担。如果正 确地使用API并不能阻止这种异常条件的产生&#xff0c;并且一旦产生了异常&#xff0c;使用API的程序可以采取有用的动作&#xff0c;那么这种负担被认为是正当的。

  1. try{ 
  2.    ... 
  3. }catch(TheCheckedException e){ 
  4.    e.printStackTree(); 
  5.    System.exit(1); 

如果使用API的程序员无法做得比这更好&#xff0c;那么未被检查的异常可能更为合适。在实践中&#xff0c;catch几乎总有断言失败的特征。
“把被检查的异常变成未被检查的异常”的一种技术是&#xff0c;把这个要抛出异常的方法分成两个方法&#xff0c;第一个方法返回一个boolean以指明是否要抛出异常&#xff0c;另一个执行真正的功能&#xff0c;如果条件不满足就抛异常。如下&#xff1a;

//Invocation with checked exception

  1. try{ 
  2.    obj.action(args); 
  3. }catch(TheCheckedException e){ 
  4. //Handle exception condition

转换为&#xff1a;

  1. //Invocation with state-testing method and unchecked exception
  2. if(obj.actionPermitted(args)){ 
  3.    obj.action(args)); 
  4. }else{ 
  5. //handle exception condition

当然这种转换并不总是合适的&#xff0c;例如一对象将在缺少外部同步的情况下被并发访问&#xff0c;或者可被外界改变状态&#xff0c;那么这种转换将是不合适的。

 

NO.42 尽量使用标准的异常
Java平台库中讫今为止最常被重用的异常如下&#xff1a;
IllegalArgumentException 参数值不合适
IllegalStateException 对于这个方法调用而言&#xff0c;对象的状态不合适(如初始化不恰当)
NullPointerException 在null被禁止的情况下参数值为null
IndexOutOfBoundsException 下标越界
ConcurrentModificationException 在禁止并发修改的情况下&#xff0c;对象检测到并发修改
UnsupportedOperationException 对象不支持客户请求的方法
其它的异常也可以使用&#xff0c;只要确保抛出异常的条件与文档要求一致即可。


NO.43 抛出的异常要适合于相应的抽象
高层的实现&#xff0c;应该捕获低层的异常&#xff0c;同时抛出一个可以按照高层抽象进行解释的异常&#xff0c;这种做法叫做异常转译(exception translation)。即如&#xff1a;

  1. //exception translation!
  2. try{ 
  3. //use lowlevel abstraction to do our bidding
  4.   ... 
  5. }catch(LowerLevelException e){ 
  6. throw new HigherLevelException(...); 

低层的异常被高层的异常保存起来&#xff0c;且高层的异常提供一个公有的访问方法来获得低层的异常&#xff0c;这种做叫做异常链接(exception chaining)。

  1. //Exception chaining.
  2. try{ 
  3. //use lower-level abstraction to do our bindding
  4.   ... 
  5. }catch(LowerLevelException e){ 
  6. throw new HigherLevelException(e); 

异常链的实现非常简单&#xff0c;在1.4及以后版本中&#xff0c;可以通过Throwable来获得支持。

  1. //Exception chaining in release 1.4 or later
  2. HigherLevelException(Throwable t){ 
  3. super(t); 

处理来自低层的异常&#xff0c;
最好的做法是&#xff0c;在调用低层方法之前通过一些检查等手段来确保它们会成功执行&#xff1b;
其次的做法是&#xff0c;让高层处理这些异常&#xff0c;从而将高层方法的调用者与低层的问题隔离开&#xff1b;
一般的做法是使用异常转译&#xff1b;
如果低层方法的异常对高层也是合适的&#xff0c;则将其从低层传到高层。


NO.44 每个方法抛出的异常都要有文档
      总是要单独地声明被检查的异常&#xff0c;并且利用javadoc的&#64;throws标记&#xff0c;准确地记录下每个异常被抛出的条件。
      使用javadoc的&#64;throws标签积累下一个方法可能会抛出的每个未被检查的异常&#xff0c;但是不要使用throws关键字将未被检查的异常包含在方法的声明中。
      如果一个类中的许多方法出于同样的原因而抛出同一个异常&#xff0c;那么在该类的文档注释中对这个异常做文档&#xff0c;而不是为每个方法单独写一个文档。


NO.45 在细节消息中包含失败 - 捕获信息
为了捕获失败&#xff0c;异常信息应该尽可能多的包含有意义的参数和域的值&#xff0c;如&#xff1a;IndexOutOfBoundsException应该包括上界、下界以及实际的下标。


NO.46 努力使失败保持原子性
      一个失败的方法调用应该使对象保持“它在被调用之前的状态”&#xff0c;方法如下&#xff1a;
① 使用非可变对象&#xff1b;
② 在可变对象上的操作&#xff0c;应在执行前检查参数的有效性&#xff1b;
③ 写一段恢复代码&#xff0c;在执行失败的情况下&#xff0c;回滚到操作开始之前的状态&#xff08;不常用&#xff09;&#xff1b;
④ 在对象的一份临时拷贝上执行操作&#xff0c;当完成之后&#xff0c;再把临时拷贝中的结果复制给原来的对象&#xff0c;如Collections.sort在执行排序之前&#xff0c;先把它的输入转储到一个数组中&#xff0c;这样既能降低内循环的开销&#xff0c;又能保证在排序失败的时候&#xff0c;输入列表将保持原样。


NO.47 不要忽略异常
      除非有特殊的需求&#xff08;如动画中的多帧图像播放&#xff09;&#xff0c;否则不要吃掉异常&#xff0c;至少在catch块中包含一条说明&#xff0c;用来解释为什么忽略这个异常。简单地将一个未被检查的异常传播到外界至少会使程序迅速地失败&#xff0c;从而保留了有助于调试该失败条件信息&#xff0c;比异常被忽略后的一个不可预测的时刻程序失败这种情况要强。

转:https://www.cnblogs.com/plmnko/archive/2010/10/20/1856359.html



推荐阅读
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
author-avatar
期待眺望未来_974
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有