本章继续讨论一些编程过程中应该注意的问题和细节
下面是本条的要点: - 局部变量应该在第一次使用的地方声明,有些人认为应该在代码块的开头处声明,这是C语言带过来的坏习惯,如果代码块很长,会造成阅读者糟糕的体验。 - 局部变量声明应该尽量带着初始化表达式,除非你还不知道初始化值要赋什么值 - 循环可以为我们带来作用域最小化的好处,因此,如果循环结束就不需要局部变量的内容,for循环优先于while循环使用 - for循环也会比while循环更简洁,bug可能性更低,它的局部变量作用域明显,不像while语句没有声明局部变量的地方 - 使用传统的for循环时,在两个;
符号中间的条件语句不能有计算过程,否则,每次循环都要执行这个过程,造成性能的巨大浪费,将上下限值计算好放在初始化语句中才是明智之举
下面是本条要点: - 还用说吗,for-each语句带来无与伦比的简洁性 - for-each语句没有性能上的损失,甚至某些时候能更快 - for-each语句可以遍历任何实现了Iterable
接口的类,带来更多的便利性
可惜,下面这些场景无法使用for-each语句: - 需要调用remove来安全的删除数组的某个元素,这个时候只能使用迭代器来实现 - 需要动态地修改数组中的元素,需要获取index值的情况下 - 一些需要多个数组并行地遍历时
这条没什么好说的,书中用Random类作为例子,告诉读者: 不要遇到什么事情都想着自己去实现,自己搞一套,去熟悉最新的JAVA类库支持哪些功能,以及善加利用前人的经验凝结成的心血之作,也是优秀的程序员必须掌握的技巧。
这一点很多人都知道,不必详细介绍。 总之这两种浮点数计算是计算机的通病,是涉及底层处理器架构方面的,只要计算机使用二进制,可能永远也无法摆脱这种缺陷,它们都是近似计算,而不是精确计算。 在进行科学计算和工程计算时,只要在容忍的精度范围内准确就够了。但是,涉及金钱
方面的计算,货币计算,你绝对不能使用这两种类型!! 典型的替代方案是使用int
、long
、BigDecimal
来解决问题。注意BigDecimal
是有性能损失的,但是它有一些舍入模式很方便。
原因有以下几点: - 基本类型只有值,装箱基本类型虽然也有值,但是本质上是个对象,基本类型用==
运算符不会出错,装箱基本类型用==
运算符基本上都会出错,因为这会比较两者的引用而非值 - 装箱基本类型有额外的值NULL
,这和基本类型不一样,基本类型永远不会有NULL,因此有些时候你会遇到莫名其妙的NPE(NullPointerException)错误。当然了,对象的域建议使用装箱基本类型,这样可以避免初始化的时候自动为基本类型赋上毫无意义的初始值,而装箱基本类型用NULL
作为初始值,更容易在早期暴露问题 - 基本类型更快,更节省空间。如果有一个循环里面,你恰好使用到了装箱基本类型,有可能会导致频繁地自动拆装箱操作,严重降低性能。
很多程序员习惯什么东西都用字符串来代替,书中主张,如果一个东西本质上是什么,在程序中就应该是什么。 你不应该用”1“来代替数字1,也不应该用”true“来代替boolean值true,枚举类型也不可以用字符串代替,使用更加适当的数据类型,尽量避免字面量以及字符串的使用,这会使你的程序更加安全不易出错,有时候也会更快速。
字符串连接符+
是非常方便的操作符,可以将多个东西连接到一起。 但是,字符串在JAVA环境中是不可变的,所有的字符串都放在一个字符串池中被全局共用,当你拼接字符串的时候,实际上是创建了一个新的字符串,复制两个旧的字符串的内容。 如果只有短短几个拼接,那么性能还是可以接受的。 但是如果放在循环体中,性能的损失是平方级增加的。 这个时候你应该用StringBuilder
来完成字符串拼接,这个类速度在大量拼接场景快50倍以上。 另外,别忘了在使用连接符连接其他类型和字符串时,其他类型还有转化成字符串的开销。
这条在我看来就是多余的,通过接口引用对象而不是直接用类来引用对象有什么好处? 想想为什么会有接口这种东西就明白了。
这条说起来也很通俗:当你能直接使用接口或者类的时候,就不要使用反射机制去做事情。 反射机制是给框架的开发者用的,一般应用程序的开发者不应该用到反射机制。 反射机制有以下缺点: - 丧失了编译时的错误检查,取而代之的是一堆受检的运行时检查 - 由于上面的原因和其他原因,使用反射的代码冗长而且容易出错 - 反射性能会变差,2倍到50倍的性能下降,你不会想要的,只有万不得已的时候,才应该用反射