Effective Java 通用程序设计笔记

  • 将局部变量作用域最小化。要将局部变量最小化最有力的方法是在第一次使用它的地方声明;每个局部变量声明都应该包含一个初始化表达式。

  • 对于集合的遍历,首选forEach的方式,其次当在循环终止之后不再需要循环变量的内容时,for循环要优于while循环,因为for循环可以将临时变量限制在最小的生存区中。

拓展:对于需要计算的值,如链表的长度,进行循环遍历时,最好使用一个变量来存储其大小,避免每次重复计算。如:

for(int i = 0,n = expensiveComputration();i<n;i++){

    doSometing();

}
  • for-each优先于传统的for循环。for-each方式产不会造成任何性能的损失,在某些情况下(程序员没有把边界填用变量保存起来,而导致重复计算),比起普通for循环,还有性能上的优势。

拓展:注意求一个枚举的两两组合方式,示例:投两次骰子的所有可能结果。以下代码并不能得出36条记录。正确的方式应该是先把外层循环的结果保存起来。

enum Face {

    ONE, TWO, THREE, FOUR, FIVE, SIX

};

...

Collection<Face> faces = Arrays.asList(Face.values());

        for (Iterator<Face> i = faces.iterator(); i.hasNext();) {

            for (Iterator<Face> j = faces.iterator(); j.hasNext();) {

                System.out.println(i.next() + " " + j.next()); // 这样写会有bug

            }

        }
  • 使用标准类库的好处有:可以避免浪费时间在与业务不相关的问题上;可以使代码更易读,更易维护;使用标准类库,它们的性能往往会随时间推移而不断提高。

示例:产生随机数最优的算法是Random.nextInt(int)

  • 如果需要精确答案,避免使用float和double。在货币计算上正确的办法是使用BigDecimal、int、long等进行运算。

拓展:使用BigDecimal有两个缺点,一是相较于基本运算,这样做很不方便。二是其运算速度很慢。

相较于使用int和long,BigDecimal有两个优点,一是可以完全控制舍入。二是如果数字超过了18位数字,就只能用BigDecimal

  • 基本类型优于装箱基本类型。

java类型系统由基本类型和引用类型两部分组成。

基本类型的装箱类有三个特点:基本类型装箱类表示的值相同,但不一定为同一个对象(引用的地址可能不同);基本类型都是有意义的值,装箱类的值可以为null,并且默认为null; 装箱类通常比基本类更耗时间和空间。

对于基本类型装箱类运行==操作符几乎总是错误的。

示例:

public class Unbelievable {

static Integer i;



public static void main(String[] args) {

if (i == 42) {

System.out.println("unbelievable");

}

}



}

以上小程序,并不是打印出unbelievalbe,而是抛出NullPointerException异常。原因是i是Integer,默认值是null

自动装箱和拆箱是耗性能的操作,考虑以下程序:

public void testsum() {

Long sum = 0l;

for (long i = 0; i < Integer.MAX_VALUE; i++) {

sum += i;

}

System.out.println(sum);

}

这个程序运行会非常慢。原因是不断在装箱和拆箱。

必须使用装箱类的场景:集合中的元素、键、值。参数的泛化。

总之,能用基本类型就不用基本类型的装箱类,使用了装箱类就不要使用==进行比较运算。

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

数据本应该是什么类型就应该使用该类型表示,而不能一味的使用字符串表示,如在网络中获取的数据往往是文本类型的,此时应该将其中内容转化成对象的类型,比如int,boolean等。在java中对字符串的查找、匹配、连接性能不如基本类型高。

  • 当心字符串连接的性能。

使加+运算符连接字符串,在单独输出一行,字符串较小单次操作中比较合适。但不适合大规模的场景。如果为连接n个字符串而重复使用字符串连接操作符,需要n的平方时间。这是由于字符串不可变的结果。

使用StringBuilder代替String应用于大规模连接场景。同时,如果事先知道需要的最大长度,可以在new StringBuilder(int),传进初始值大小参数,减少扩容开销

  • 通过接口引用对象。

如果有合适的接口类型,那么对于参数、返回值、变量和域来说,都应该使用接口类型进行声明。这样会使程序更加灵活。

值类,如String,Integer很少会用接口,通常都是final的

  • 接口优于反射机制

核心反射机制,java.lang.reflect提供了“程序来访问关于已装载的类的信息”的能力。给定一个Class实例,你可以获得构造器,方法和属性。Method.invoke()允许你调用任何类的任何对象上的任何方法。反射机制允许一个类使用另一个类,即使当前者被编译时后者根本不存在。也就是动态创建类和类的实例。

反射机制的代价是:

1)丧失了编译时类型检查的好处。如果程序企图用反射调用不存在的或不可访问的方法,会导致运行失败。

2)执行反射访问所需要的代码笨拙和冗长。

3)性能损失。反射方法调用比普通方法调用慢得多。

核心反射机制最初是为了基于组件的应用创建具而设计的。

有些应用如类浏览器、对象监视器、代码分析工具都需要应用到反射机制。在RPC系统中,反射机制也非常合适。

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

  • 谨慎使用本地方法

Java Native Interface(JNI),本地方法指应用系统本地编译语言编写的方法,调用本地方法,可以将结果返回到Java程序中。本地方法主要有三种用途:

1)提供“访问特定平台的机制”的能力,如访问注册表

2)提供访问遗留代码库的能力

3)提高系统的性能

使用本地方法来提高性能的做法不值得提倡,因为现在JVM优化已经相当好。本地语言不是安全的,与平台相关的,使用本地方法的程序是不可移植的;使用本地方法的应用程序调试非常困难。

  • 谨慎地进行优化。不要为了性能而牺牲合理的结构。

  • 遵守普遍接受的命名惯例。尽量避免缩写。常量使用大写字母,使用下划线分隔单词。

泛化参数类型通常由单个字母表示。一般有五种类型:T表示任意类型,E表示集合的元素类型,K和V表示映射的键和值类型,X表示异常。任何类型可以是T、U、V、或T1、T2、T3

值得一提的是,转换对象类型的方法、返回不同类型的独立对象的方法通常被称为toType,如toString和toArray,返回视图(视图的类型不同于接收对象的类型)的方法通常被称为asType,如asList。返回一个与被调用对象同值的基本类型方法,通常被称为typeValue,如intValue.静态工厂的常用名称为valueOf、of、getInstance、newInstance、getType和newType.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值