一、将局部变量的作用域最小化

     本条目与前面(使类和成员的可访问能力最小化)本质上是类似的。将局部变量的作用域最小化,可以增加代码的可读性和可维护性,并降低出错的可能性。

使一个局部变量的作用域最小化,最有力的技术是在第一次使用它的地方声明。

几乎每一个局部变量的声明都应该包含一个初始化表达式。

在循环中经常要用到最小化变量作用域这一个规则。for循环使你可以声明循环变量(loop varialbe),它们的作用域被限定在正好需要的范围值内(这个范围包括循环体,以及循环体之前的初始化、测试、更新部分)。因此,如果在循环终止之后循环变量的内容不再被需要的话,则for循环优于while循环。
例如,下面是一种对集合进行迭代的首选做法:

for(Iterator i = c.iterator();i.hasNext();){
doSomething(i.next());
}

对比while循环,以及一个错误:

Iterator i = c.iterator();
while(i.hasNext()){
doSomething(i.next());
}
... Iterator i2 = c2.iterator();
while(i.hasNext()){ //BUG!
doSomethingElse(i2.next());
}

如果类似的”剪切-粘贴“错误发生在前面for循环的用法中,则结果代码根本不能通过编译。

for循环比while循环的另外一个优势,使用for循环要少一行代码,有助于把方法装入到大小固定的编辑器窗口中,从而增强可读性。

二、了解和使用库

1、通过使用标准库,你可以充分利用这些编写标准库的专家知识,以及在你之前其他人的使用经验。

2、使用标准库,它们的性能会不断提高,而无需你做任何努力。

3、标准库也会随着时间而增加新的功能。

4、使用标准库,会使自己的代码融入主流。

三、如果要求精确的答案,请避免使用float和double

float和double类型的主要设计目标是为了科学计算和工程计算。它们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而没哟提供完全精确的结果,所以不应该被用于要求精确结果的场合。float和double类型对于货币计算尤为不合适。因为要让一个float或者double精确地表达0.1(或者10的任何其他负数次方值)是不可能的。

例如,假设你的口袋中有$1.03,花掉了42之后还剩下多少钱呢?下面是一个很简单的程序片段,企图回答这个问题:

System.out.println(1.03-.42);

不幸的是,它的输出结果是0.6000000000001.

要解决这个问题正确的方法是使用BigDecimal、int或者long进行货币计算。然而,使用BigDecimal有两个缺点:与使用原语运算类型相比,这样做很不方便,而且更慢。

总而言之,对于有些要求精确答案的计算任务,请不要使用float或者double。如果你希望系统来处理十进制小数点,并且不介意因为不使用原语类型而带来的不便,那么请使用BigDecimal.使用BigDecimal还有一个额外的好处,它允许你完全控制舍入:当一个操作涉及到舍入的时候,它让你从8种舍入模式中选择其一。如果你正在进行商务计算,并且要求特别的舍入行为,那么使用BigDecimal是非常方便的。

如果性能非常关键,并且你又不介意自己处理十进制小数点,而且所涉及的数值又不太大,那么可以使用int或者long(采用更小的单位,如上面采用美分)。如果数值范围没有超过9位十进制数字,则你可以使用int;如果不超过18位数字,则可以使用long。如果数值范围超过了18位数字,你就必须使用BigDecimal。

四、如果其他类型更适合,则尽量避免使用字符串

字符串被用来表示文本,它在这方面也确实做得很好。因为字符串很常用,并且java也支持的很好,所以自然地就会有这样一种倾向:即使在不适合于使用字符串的场合,人们往往也会 使用字符串。

字符串不适合代替其他的值类型。

字符串不适合代替枚举类型。

字符串不适合代替聚集类型。

字符串也不适合代替能力表(capabilities)。

五、了解字符串连接的性能

字符串连接操作符(+,string concatenation operator)是把多个字符串合并为一个字符串的便利途径。为连接n个字符串而重复地使用字符串连接操作符,要求n的平方级的时间。这是由于字符串是非可变的而导致的不幸结果。当两个字符串被连接的时候,它们的内容都要被拷贝。

为了获得可接受的性能,请使用StringBuffer替代String,用来存储构造过程中的账单声明:

public String statement(){
StringBuffer s = new StringBuffer(numItems()*LINE_WIDTH);
for(int i=0;i<numItems();i++)
s.append(lineForItem(i));
return s.toString();
}

+做法的开销随项目数量呈平方级增加,StringBuffer做法是线性增加,所以,项目越大,性能的差别会越显著。

原则很简单:不要使用字符串连接操作符来合并多个字符串,除非性能无关紧要。相反,应该使用StringBuffer的append方法,或者采用其他的方案,比如使用字符数组,或者每次只处理一个字符串,而不是将它们组合起来。

六、通过接口引用对象

例如,Vector是List接口的一个实现,在声明变量的时候应该养成这样的习惯:

//Good -uses interface as type
List subscribers = new Vector(); //而不是这样声明:
//Bad -uses class as type!
Vector subscribers = new Vector();

如果你养成了使用接口作为类型的习惯,那么你的程序将会更加灵活。

如果没有合适的接口存在的话,那么,用类而不是接口引用一个对象,是完全合适的。

第一、值类(value class),比如String和BigInteger。记住,值类很少有多种实现。它们通常是完全合适的。更一般地,如果一个具体类没有相关联的接口,那么不管它是否表示一个值,你都没有别的选择,只有通过这个类来引用它的对象。
第二、对象属于一个框架,而框架的基本类型是类,不是接口。如果一个对象属于这样一个基于类的框架(class-based framework),那么应该用相关的基类(base class)来引用这个对象,而不是使用它的实现类。java.util.TimerTask类就属于这种情形。
第三、一个类实现了一个接口,但是它提供了接口中不存在的额外方法--例如LinkedList。如果程序依赖于这些额外的方法,那么这样的类应该只被用来引用它的实例:它永远也不应该被用作参数类型。

七、接口优先于映像机制

映像设施(reflection facility)java.lang.reflect提供了”通过程序访问关于已装载的类的信息“的能力。映射机制(reflection)允许一个类使用另一个类,即使当前者被编译的时候后者还根本不存在,然而,这种能力也需要付出代价:

  • 你损失了编译时类型检查的好处,也包括异常检查,如果一个程序企图用映射方式调用一个不存在的方法,或者一个不可访问的方法,那么在允许时它将会失败,除非你采取了特别的预防措施。
  • 要求执行映射访问的代码非常笨拙和冗长。编写这样的代码非常乏味,阅读这样的代码页很困难。
  • 性能损失。映射机制调用比普通方式调用慢2倍。

如果只是在很有限的情况下使用映像机制,那么虽然也会付出少许代价,但你可以获得许多好处。

八、谨慎地使用本地方法

Java Native Interface(JNI)允许Java应用可以调用本地方法(native method),所谓本地方法是指本地程序设计语言(比如C或者C++)来编写特殊方法。

从历史上看,本地方法主要有三种途径:

  • 它们提供了”访问于平台相关的设施“的能力,比如访问注册表(registry)和文件锁。
  • 它们也提供了访问老式代码库的能力,通过这些老式代码库进一步可以访问老式数据(legacy data)。
  • 应用程序可以使用本地语言,实现性能关键部分,以提供系统的性能。(随着高版本的出现,这个方法已经不提倡)

九、谨慎的进行优化

     优化的三条格言:

  •      很多计算上的过失都被归咎于效率原因(没有获得必要的效率),而不是其他的原因---甚至包括盲目地做傻事。
  • 不要去计较一些小的效率上的得失,在97%的情况下,不成熟的优化是一切问题的根源。
  • 在优化方面的两条规则:

A、规则1:不要做优化。

B、规则2:(仅针对专家)还是不要做优化---也就是说,在你还没有绝对清晰的未优化方案之前,请不要做优化。

十、遵守普遍接受的命名惯例

Java平台有一套建立得很好的命名惯例(naming convention),其中许多被包含在The java language specification中。不严格地讲,这些命名惯例分为两大类:字面的(typographical)和语法的(grammatical)。

字面命名惯例:
包的名字应该是层次状的,用句号分隔每一部分。每一部分包括小写字母和数字(很少使用数字)。如果你的包将在你的组织之外被使用,那么包的名字应该以你的组织的Internet域名作为开头,并且顶级域名放在前面,例如,edu.cmu、com.sun、gov.nsa。标准库和一些课选的库,其名字以java和javav作为开头,它们是这条规则的例外。
包名字的剩余部分应该包括一个或者多个描述该包的组成部分。通常不超过8个字符。鼓励使用有意义的缩写形式,例如,使用util而不是utilities,只取首字母的缩写形式也是可以接受的。如awt。
类和接口的名字应该包括一个或者多个单词,每个单词的首字母大写,缩写应该尽量避免,除非是一些首字母缩写和一些通用的缩写,如max和min等。

方法和域的名字与类和接口的名字遵循相同的字面惯例,只不过方法或者域名的名字第一个字母应该小写,如remove、ensureCapacity.

“常量域”的名称应该包含一个或者多个大写的单词,中间用下划线符号隔开。

局部变量名称的字面命名惯例与成员名称类似,只不过它也允许缩写。

类型参数名称通常由单个字母组成,这个字母通常是以下五种类型之一:T表示任意的类型,E表示集合的元素类型,K和V表示映射的键和值类型,X表示异常。

语法惯例:

语法命名惯例比字面惯例更灵活,也更有争议。

对于包而言,没有语法命名惯例。

类通常用一个名词或者名词短语命名。如Timer或者BufferedWriter

接口的命名与类相似,如,Collection。或者用一个以“-able”或“-ible”结尾的形容词来命名。如Runnable或Accessible。

由于注解类型有那么多用处,因此没有单独安排词类。

执行某个动作的方法通常用动词或者动词短语来命名。对于返回boolean值的方法,其名称往往以单词“is”开头,后面跟名词或名词短语,或者任何具有形容词功能的单词或短语。

如果方法返回被调用对象的一个非boolean的函数或者属性,它通常用名词、名词短语,或者以动词“get”开头的动词短语来命名。

如果方法所在的类是个Bean,就要强制使用以“get”开头的形式。

转换对象类型的方法、返回不同类型的独立对象的方法,通常被称为toType,例如toString和toArray。返回视图的方法通常被称为asType,例如asList。返回一个与被调用对象同值的基本类型的方法,通常被称为typeValue,例如intValue。静态工厂的常用名称为valueOf、of、getInstance、netInstance、getType和NewType。

boolean类型的域的命名与boolean类型的访问方法很类似,但是省去了初始的“is”。其他类型的域通常用名词或者名词短语来命名。局部变量的语法惯例类似于域的语法惯例,但是更弱一些。

Effective java笔记5--通用程序设计的更多相关文章

  1. [Effective Java]第八章 通用程序设计

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  2. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  3. Effective java笔记(二),所有对象的通用方法

    Object类的所有非final方法(equals.hashCode.toString.clone.finalize)都要遵守通用约定(general contract),否则其它依赖于这些约定的类( ...

  4. effective java笔记之单例模式与序列化

    单例模式:"一个类有且仅有一个实例,并且自行实例化向整个系统提供." 单例模式实现方式有多种,例如懒汉模式(等用到时候再实例化),饿汉模式(类加载时就实例化)等,这里用饿汉模式方法 ...

  5. effective java笔记之java服务提供者框架

    博主是一名苦逼的大四实习生,现在java从业人员越来越多,面对的竞争越来越大,还没走出校园,就TM可能面临失业,而且对那些增删改查的业务毫无兴趣,于是决定提升自己,在实习期间的时间还是很充裕的,期间自 ...

  6. Effective java笔记(七),通用程序设计

    45.将局部变量的作用域最小化 将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性. Java允许在任何可以出现语句的地方声明变量(C语言中局部变量要在代码块开头声明),要使 ...

  7. Effective Java 读书笔记之七 通用程序设计

    一.将局部变量的作用域最小化 1.在第一次使用变量的地方声明 2.几乎每个变量的声明都应该包含一个初始化表达式:try-catch语句是一个例外 3.使方法小而集中是一个好的策略 二.for-each ...

  8. Effective java笔记6--异常

    充分发挥异常的优点,可以提高一个程序的可读性.可靠性和可维护性.如果使用不当的话,它们也会带来负面影响. 一.只针对不正常的条件才使用异常 先看一段代码: //Horrible abuse of ex ...

  9. effective java 笔记1--序言

    一.序言 程序设计的几条基本原则: 1.清晰性和简洁性最为重要,模块的用户永远也不应该被模块的行为所迷惑,所以写良好的注释是必需的. 2.模块要竟可能小,但也不能太小,好一个深奥的哲学问题. 3.代码 ...

随机推荐

  1. 教你使用UIWindow实现窗口的切换

    这两天写了一个手势解锁,该死的需求要求这个手势解锁页面各种出现,毕竟人家这个客户端酒20多个领导用用的,怕泄密就加了各种保密措施.先来看下需求:1.用户注册登录后跳转设置手势页面(必须设置).2.ap ...

  2. BufferedReader方法-----Scanner方法

    import java.io.*; import java.util.Scanner; public class C { public static void main(String []args) ...

  3. CentOS单用户模式下修改ROOT密码和grub加密

    Linux 系统处于正常状态时,服务器主机开机(或重新启动)后,能够由系统引导器程序自动引导 Linux 系统启动到多用户模式,并提供正常的网络服务.如果系统管理员需要进行系统维护或系统出现启动异常时 ...

  4. 管理IPv6网络连接

    以下操作建立在Linux功能-管理IPv4网络连接之上,请先完成该部分操作后进行以下测试. 1. 修改 net1,配置 IPv6 地址为 2001:X/64 ,网关为 2001:254 [root@d ...

  5. 1、Hibernate之生成SessionFactory源码追踪

    Hibernate的所有session都是由sessionFactory来生成的,那么,sessionFactory是怎么得来的呢?它与我们配置的xxx.cfg.xml文件以及xxx.hbm.xml文 ...

  6. 人脸识别算法准确率最终超过了人类 The Face Recognition Algorithm That Finally Outperforms Humans

    Everybody has had the experience of not recognising someone they know—changes in pose, illumination ...

  7. Java 异常 —— java.io.InvalidClassException: javax.xml.namespace.QName; local class incompatible

    项目中有个 WebService 接口,调试时使用 Main 方法运行,别人的机器上都能运行,就笔者的机器出问题.他们说是RP的问题…… 异常信息: java.io.InvalidClassExcep ...

  8. iPhone 已停用

    如果你的iPhone上出现了如下的显示,你可以参考苹果官网上的  iOS设备已停用 如果你看到了这篇文章,你比我幸运多了. 参考这一个条目,你也许就不会丢失里面的数据了. 可怜的我,出现这个问题时还没 ...

  9. HDU 4651 Partition(整数拆分)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4651 题意:给出n.求其整数拆分的方案数. i64 f[N]; void init(){    f[0 ...

  10. QQ发送邮件

    //下面开始写SendEmail函数 public void SendEmail(string Emailshoujian, string Emailbiaoti, string Emailzheng ...