一、通用程序设计
目标:局部变量的处理、控制结构、类库的用法、各种数据类型的用法、反射机制(reflection)和本地方法(native method)的用法。
1、将局部变量的作用域最小化
(1)、在第一次使用变量的地方声明。
(2)、使方法小而集中。
2、for-each循环优先于传统的for循环
(1)、for-each循环简洁,可预防Bug。
(2)、不能使用for-each循环情况:过滤、转换、平行迭代。
3、了解和使用类库
(1)、通过使用标准类库,可以充分利用这些编写标准类库的专家的知识,以及在你之前的其他人的使用经验。
(2)、java.lang、java.util、java.io类库。
(3)、不要重新发明轮子,了解常用类库并使用类库,提高开发效率。
4、如果需要精确的答案,请避免使用float和double。
(1)、使用BigDecimal、int或者long进行货币计算。
5、基本类型优先于装箱基本类型(封装类型)
(1)、Java类型系统组成:基本类型(primitive),如int、double、boolean和引用类型(reference type),如String、List。
(2)、当在一项操作中混合使用基本类型和封装类型,封装类型就会自动拆箱。
(3)、在进行反射的方法调用时,必须使用装箱基本类型。
(4)、封装类型会导致高开销和不必要的对象创建。
6、如果其他类型更适合,则尽量避免使用字符串。
(1)、字符串不适合代替其他的值类型、枚举类型、聚集类型、能力表(capabilities)。
7、当心字符串连接的性能
(1)、为连接n个字符串而重复地使用字符串连接操作符,需要n的平方级的时间,这种场景不适合用+连接符。
(2)、可以使用StringBuilder代替+字符串连接。
(3)、StringBuilder:适用于单线程下大数据量的操作,线程不安全。
(4)、StringBuffer:适用于多线程下大数据量的操作,线程安全。
8、通过接口引用对象
(1)、如果有合适的接口类型存在,那么对于参数、返回值、变量和域,就都应该使用接口类型进行声明。只有当利用构造器创建某个对象的时候,才真正需要引用这个对象的类。
9、接口优先于反射机制
(1)、核心反射机制(core reflection facility)java.lang.reflect,提供了“通过程序来访问关于已装载的类的信息”的能力。
(2)、反射机制允许一个类使用另一个类,即使当前者被编译的时候后者还不存在。
(3)、反射的缺点
- 丧失了编译时类型检查的好处。
- 执行反射访问所需的代码非常笨拙和冗长。
- 性能损失。
(4)、如果编写的程序要与编译时未知的类一起工作,如有可能,就应该仅仅使用反射机制来实例化对象,而访问对象时则使用编译时已知的某个接口或者超类。
10、谨慎地使用本地方法
(1)、本地应用方法,是指用本地程序设计语言(如C或者C++)来编写的特殊方法。本地方法在本地语言中可以执行任意的计算任务,并返回到Java程序设计语言。
(2)、本地方法的用途。提供访问特定于平台的机制的能力,如注册表、文件锁。提供访问遗留代码库的能力,从而可以访问遗留数据。通过本地语言编写应用程序中注重性能的部分。
(3)、本地语言不是安全的,且使用了本地语言会造成不能移植。
11、谨慎地进行优化
(1)、不要优化。
(2)、不要因为性能而牺牲合理的结构,要努力编写好的程序而不是快的程序。(建议)
(3)、必须在设计过程中考虑到性能的问题。
12、遵守普遍接受的命名惯例
(1)、字面的(typographical)和语法的(grammatical)。
(2)、字面惯例
包 —— com.google.inject, org.joda.time.format
类或者接口 —— Timer, FutureTask, LinkedHashMap, HttpServlet
方法或者域 —— remove, ensureCapacity, getCrc
常量域 —— MIN_VALUE, NEGATIVE_INFINITY
局部变量 —— i, xref, houseNumber
类型参数 —— T, E, K, V, X, T1, T2
二、异常
目标:充分发挥异常的优点,可以提高程序的可读性、可靠性和可维护性。
1、只针对异常的情况使用异常
(1)、异常应该只用于异常的情况下,永远不应该用于正常的控制流。
2、对可恢复的情况使用受检异常,对编程错误使用运行时异常。
(1)、抛出结构(throwable):受检的异常(checked exception)、运行时异常(run-time exception)、错误(error)。
(2)、如果期望调用者能够适当地恢复,对于这种情况就应该使用受检的异常。
3、避免不必要地使用受检的异常
(1)、可以把受检的异常变成未受检的异常,即状态测试方法。
4、优先使用标准的异常
(1)、异常类越少,内存印迹(footprint)越小,装载这些类的时间开销越小。
(2)、常用的异常
算术异常类:ArithmeticExecption
空指针异常类:NullPointerException
类型强制转换异常:ClassCastException
数组负下标异常:NegativeArrayException
数组下标越界异常:ArrayIndexOutOfBoundsException
违背安全原则异常:SecturityException
文件已结束异常:EOFException
文件未找到异常:FileNotFoundException
字符串转换为数字异常:NumberFormatException
操作数据库异常:SQLException
输入输出异常:IOException
方法未找到异常:NoSuchMethodException
5、抛出与抽象相对应的异常
(1)、异常转译(exception translation),指更高层的实现应该捕获低层的异常,同时抛出可以按照高层抽象进行解释的异常。
(2)、异常链(exception chaining)。
6、每个方法抛出的异常都要有文档
(1)、描述好前提条件(precondition)、通用约定(general contract)
7、在细节消息中包含能捕获失败的信息
8、努力是失败保持原子性
(1)、失败原子性(failure atomic),失败的方法调用应该使对象保持在被调用之前状态。
9、不要忽略异常
(1)、警钟长鸣。