《Effective Java》知识点(8)--通用编程

57. 将局部变量的作用域最小化

       将局部变量的作用域最小化,可以增强代码的可读性和可维护性,并降低出错的可能性。

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

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

       for循环优先于while循环。for循环更能避免“剪切-粘贴”错误;更简短,可读性更好。

58. for-each循环优先于传统的for循环

       与传统的for循环相比,for-each循环在简洁性、灵活性以及出错预防性方面都占有绝对优势,并且没有性能惩罚的问题。多重循环时,for循环容易出错。

       无法使用for-each的三种情况:

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

   b. 如果需要遍历列表或者数组,并取代它的部分或者全部元素值,就需要用迭代器或数组索引。

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

59. 了解和使用类库

       使用标准类库的好处: 

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

   b. 不必浪费时间在底层细节,而把时间花在应用程序上。

   c. 它们的性能会随着时间推移而不断提高。

   d. 它们会随着时间的推移而增加新的功能。

   e. 可以使自己的代码融入主流。

每个程序员都应该熟悉java.lang、java.util、java.io及其子包中的内容。 

优先在类库查找所需功能,如果类库找不到,下一个选择应该是在高级的第三方类库去寻找,如Guava类库。如果都找不到,最后才是选择自己实现这些功能。

60. 如果需要精确的答案,请避免使用float和double

     float和double类型尤其不适合用于货币计算。请优先使用BigDecimal,如果性能是关键,可以使用int或long。如果数值不超过9位十进制数,使用int;如果不超过18位,使用long;如果可能超过18位,还是用BigDecimal。

61. 基本类型优先于装箱基本类型

      基本类型(int,double,boolean)比装箱基本类型(Integer,Double,Boolean)更加简单、快速,应优先使用。

61.1 基本类型和装箱类型的区别:

  a. 基本类型只有值,而装箱类型具有与它们的值不同的同一性。

  b. 基本类型只有函数值,而装箱类型除了函数值,还有个null。

  c. 基本类型通常比装箱类型更节省时间和空间

61.2 什么时候用装箱类型

   a. 作为集合中的元素、键和值

   b. 在参数化类型和方法中,必须用装箱类型作类型参数

   c. 在进行反射的方法调用时

61.3 使用装箱注意事项

    a. 对装箱类型运用==操作符通常是错误的,因为比较的是对象而不是值

    b. 当在一项操作中混用基本类型和装箱类型是,装箱类型会自动拆箱,可能抛出空指针异常

    c. 当基本类型转装箱时,会导致资源消耗和不必要的对象创建

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

       字符串不适合代替基本类型。

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

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

       字符串不适合代替能力表(capabilities),如授权访问中作key。 

63. 了解字符串连接的性能

63.1 不要使用字符串连接操作符来合并多个字符串(需要n的平方级的时间)

63.2 使用StringBuilder的append方法来连接字符串

63.3 使用字符数组,或者每次只处理一个字符串,而不是将它们组合起来

64. 通过接口引用对象

       如果有合适的接口类型存在,那么对于参数、返回值、变量和域来说,就都应该使用接口类型进行声明。养成用接口作为类型的习惯,程序将会更加灵活。如果没有合适的接口,就用类层次结构中提供了必要功能的最小的具体类来引用对象。

       不存在适当接口类型的情形:

   a. 值类(如String,BigInteger)经常是final的,且很少有对应的接口。

   b. 对象属于一个框架,而框架的基本类型是类,不是接口。一般用基类(抽象类)引用对象。

   c. 类实现了接口,但它提供了接口不存在的额外方法。 这种类只能引用它的实例。

65. 接口优先于反射机制

       核心反射机制(core reflection facility),java.lang.reflect包,提供了“通过程序来访问任意类”的能力。反射机制允许一个类使用另一个类,即使当前者被编译的时候,后者还根本不存在。如果编写的程序必须要与编译时未知的类一起工作,如有可能应该仅仅用反射机制来实例化对象,而访问对象时则使用编译时已知的某个接口或者超类。

       反射机制的代价:

   a. 损失了编译时类型检查的优势,包括异常检查。可能运行时失败。

   b. 执行反射访问所需的代码非常笨拙和冗长,阅读困难。

   c. 性能损失。 反射方法调用比普通方法调用慢许多。

66. 谨慎地使用本地方法

      所谓本地方法是指用本地编程语言(如C或C++)来编写的方法。JNI允许Java程序调用本地方法。使用本地方法来访问特定于平台的机制是合法的,但是几乎没有必要。

      使用本地方法来提高性能的做法不值得提倡。

      使用本地方法的一些缺陷:

  a. 程序可能受内存毁坏错误的影响,因为本地语言不是安全的。

  b. 程序不可自由移植,因为本地语言是平台相关的。

  c. 程序更难调试

  d. 还可能降低性能,因为内存回收不是自动的,并且进入和退出本地代码需要相关开销。

  e. 需要“胶合代码”的本地方法编写起来单调乏味,难于阅读。

67. 谨慎地进行优化

      优化的弊大于利,特别是不成熟的优化。

      不要为了性能而牺牲合理的结构。努力编写好的程序而不是快的程序。

       必须在设计过程中考虑性能问题,而不是系统完成之后要努力避免那些限制性能的设计决策。最主要的组件是API、交互层协议以及永久数据格式。要考虑API设计决策的性能后果。

       在每次试图做优化之前和之后,要对性能进行测量。如果将要在多个JVM实现和多种硬件平台上运行程序,则需要在每个Java实现和平台上测量优化效果。

       系统构建完后应该测量性能。如果不够快,则可以在性能分析器的帮助下,找到问题的根源,然后设法优化系统中相关的部分。第一个步骤是检查所选择的算法:再多的低层优化也无法弥补算法的选择不当。必要时重复这个过程。

68. 遵守普遍接受的命名惯例

      命名惯例分两大类:字面的和语法的。

标识符类型字面惯例示例
包或者模块名称应该是层次状的,用句号分割每个部分。每个部分是小写字母,偶有数字。org.junit.jupiter.api
类或者接口(包括枚举和注解)一个或多个单词,每个单词的首字母大写Stream,HttpClient
方法或者域第一个字母小写remove,groupingBy
常量域字母都小写,每个单词间用下划线MIN_VALUE
局部变量允许缩写,单个字符和短字符序列,取决于上下文环境i,houseNum
类型参数单个大写字母

T:  任意类型

E:  集合的元素类型

K和V: 映射的键和值

X:  异常

R:  函数的返回类型

T、U、V、T1、T2、T3: 任何类型的序列

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

标识符类型语法惯例示例
可实例化的类(包括枚举)名词或名词短语Thread
不可实例化的工具类复数名词Collectors
接口名词或形容词Collection,Runnable,Accessible
注解名词、动词、介词、形容词Inject,Singleton
执行动作的方法动词或动词短语append
返回boolean的方法is开头isDigit
设置对象属性的方法set开头setAttribute
获取对象属性的方法get开头getAttribute
转换对象类型的实例方法toTypetoString,toArray
返回视图的方法asTypeasList
返回与被调用对象同值的方法typeValueintValue
静态工厂

from,of,valueOf,

instance,getInstance,newInstance,

getType,newType

       不要盲目遵从惯例,请使用大家公认的做法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值