第8章 通用程序设计

第45条:将局部变量的作用域最小化


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

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


第46条:for—each循环优先于传统的for循环


for-each循环在简洁性和预防Bug方面有着传统的for循环无法比拟的优势,并且没有性能损失。应该尽可能地使用for-each循环。遗憾的是,有

三种常见的情况无法使用for-each循环:

1.过滤——如果需要遍历集合,并删除选定的元素,就需要使用显式的迭代器,以便可以调用它的remove方法。

2.转换——如果需要遍历列表或者数组,并取代它部分或者全部的元素值,就需要列表迭代器或者数组索引,以便设定元素的值。

3.平行迭代——如果需要并行地遍历多个集合,就需要显式地控制迭代器或者索引变量,以便所有迭代器或者索引变量都可以得到同步前移。


第47条:了解和使用类库


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

在每个重要的发行版本中,都会有许多新的特性被加入到类库中,所以与这些新特性保持同步是值得的。

总而言之,不要重新发明轮子。如果你要做的事情看起来是十分常见的,有可能类库中已经有某个类完成了这样的工作。如果确实是这样,就使用现成

的;如果还不清楚是否存在这样的类,就去查一查。一般而言,类库的代码可能比你自己编写的代码更好一些,并且会随着时间的推移而不断改进。这

并不是在影射你作为一个程序员的能力。从经济角度的分析表明:类库代码受到的关注远远超过大多数普通程序员在同样的功能上所能够给予的投入。


第48条:如果需要精确的答案,请避免使用float和double


float和double类型主要是为了科学计算和工程计算而设计的。它们执行二进制浮点运算(binary floating-point arithmetic),这是为了在广泛的数值范围上

提供较为精确的快速近似计算而精心设计的。然而,它们并没有提供完全精确的结果,所以不应该被用于需要精确结果的场合。float和double类型尤其不

适合于货币计算,因为要让一个float或者double精确地表示0.1是不可能的。

对于任何需要精确答案的计算任务,请不要使用float或者double。如果你想让系统来记录十进制小数点,并且不介意因为不使用基本类型而带来的不便,就

请使用BigDecimal。使用BigDecimal还有一些额外的好处,它允许你完全控制舍入,每当一个操作涉及舍入的时候,它允许你从8种舍入模式中选择其一。

如果你正通过法定要求的舍入行为进行业务计算,使用BigDecimal是非常方便的。如果性能非常关键,并且你又不介意自己记录十进制小数点,而且所涉

及的数值又不太大,就可以使用int或者long。如果数值范围没有超过9位十进制数字,就可以使用int;如果不超过18位数字,就可以使用long。如果数值

可能超过18位数字,就必须使用BigDecimal。


第49条:基本类型优先于装箱基本类型


Java有一个类型系统由两部分组成,包含基本类型和引用类型。每个基本类型都有一个对应的引用类型,称作装箱基本类型。

在基本类型和装箱基本类型之间有三个主要区别。第一,基本类型只有值,而装箱基本类型则具有与它们的值不同的同一性。换句话说,两个装箱基本类型

可以具有相同的值和不同的同一性。第二,基本类型只有功能完备的值,而每个装箱基本类型除了它对应基本类型的所有功能值之外,还有个非功能值:null。

最后一点区别是,基本类型通常比装箱基本类型更节省时间和空间。


那么什么时候应该使用装箱基本类型呢?它们有几个合理的用处。第一个是作为集合中的元素、键和值。你不能将基本类型放在集合中,因此必须使用装箱基本

类型。这是一种更通用的特例。在参数化类型中,必须使用装箱基本类型作为类型参数,因为Java不允许使用基本类型。最后,在进行反射的方法调用时,必须

使用装箱基本类型。


当可以选择的时候,基本类型要优先于装箱基本类型。基本类型更加简单,也更加快速。如果必须使用装箱基本类型,要特别小心!自动装箱减少了使用装箱

基本类型的繁琐性,但是并没有减少它的风险。当程序用==操作符比较两个装箱基本类型时,它做了个同一性比较,这几乎肯定不是你所希望的。当程序进行

涉及装箱和拆箱基本类型的混合类型计算时,它会进行拆箱,当程序进行拆箱时,会抛出NullPointerException异常。最后,当程序装箱了基本类型值时,

会导致高开销和不必要的对象创建。


第50条:如果其他类型更适合,则尽量避免使用字符串


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

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

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

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

如果可以使用更加合适的数据类型,或者可以编写更加适当的数据类型,就应该避免用字符串来表示对象。若使用不当,字符串会比其他的类型更加笨拙、

更不灵活、速度更慢,也更容易出错。经常被错误地用字符串来代替的类型包括基本类型、枚举类型和聚集类型。


第51条:当心字符串连接的性能


字符串连接操作符(+,string concatenation operator)是把多个字符串合并为一个字符串的便利途径。要想产生单独一行的输出,或者构造一个字符串来

表示一个较小的、大小固定的对象,使用连接操作符是非常合适的,但是它不适合运用在大规模的场景中。为连接n个字符串而重复地使用字符串连接操作

符,需要n的平方级的时间。

不要使用字符串连接操作符来合并多个字符串,除非性能无关紧要。相反,应该使用StringBuilder的append方法。另一种方法是,使用字符数组,或者每次

只处理一个字符串,而不是将它们组合起来。


第52条:通过接口引用对象


如果有合适的接口类型存在,那么对于参数、返回值、变量和域来说,就都应该使用接口类型进行声明。

如果没有合适的接口存在,完全可以用类而不是接口来引用对象。


第53条:接口优先于反射机制


核心反射机制(core reflection facility)java.lang.reflect,提供了“通过程序来访问关于已装载的类的信息”的能力。给定一个Class实例,你可以获得Constructor、

Method和Field实例,分别代表了该Class实例所表示的类的Constructor(构造器)、Method(方法)和Field(域)。这些对象提供了“通过程序来访问类的成员

名称、域类型、方法签名等信息”的能力。

普通应用程序在运行时不应该以反射方式访问对象。

反射机制是一种功能强大的机制,对于特定的复杂系统编程任务,它是非常必要的,但它也有一些缺点。如果你编写的程序必须要与编译时未知的类一起工作,

如有可能,就应该仅仅使用反射机制来实例化对象,而访问对象时则使用编译时已知的某个接口或者超类。


第54条:谨慎地使用本地方法


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

特殊方法。本地方法在本地语言中可以执行任意的计算任务,并返回到Java程序设计语言。


从历史上看,本地方法主要有三种用途。它们提供了“访问特定于平台的机制”的能力,比如访问注册表(registry)和文件锁(file lock)。它们还提供了访问

遗留代码库的能力,从而可以访问遗留数据(legacy data)。最后,本地方法可以通过本地语言,编写应用程序中注重性能的部分,以提高系统的性能。


第55条:谨慎地进行优化


不要费力去编写快速的程序——应该努力编写好的程序,速度自然会随之而来。在设计系统的时候,特别是在设计API、线路层协议和永久数据格式的时候,

一定要考虑性能的元素。当构建完系统之后,要测量它的性能。如果它足够快,你的任务就完成了。如果不够快,则可以在性能剖析器的帮助下,找到

问题的根源,然后设法优化系统中相关的部分。第一个步骤是检查所选择的算法:再多的底层优化也无法弥补算法的选择不当。必要时重复这个过程,

在每个改变之后都要测量性能,直到满意为止。


第56条:遵守普通接受的命名惯例


把标准的命名惯例当作一种内在的机制来看待,并且学着用它们作为第二特性。字面惯例是非常直接和明确的;语法惯例则更复杂,也更松散。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值