关于《effectivity Java》阅读笔记
第八章 – 通用的程序设计
关于局部变量的初始化
将局部变量最小化,可以增加代码的可读性和可维护性,并降低出错的可能性。
要使局部变量的作用域最小化,最好的做法就是在第一次使用它的时候进行声明。
如果变量在使用之前声明,会影响影响试图理解代码的读者,分散他们的注意力。耗费时间寻找变量声明的地方。几乎每个局部变量都应该包含一个初始化表达式,如果一个变量被一个方法初始化,而这个方法可能会抛出一个受检的异常,该变量就必须在try快内部进行初始化。
for循环的优劣
根据循环中循环变量的作用域和数目进行评价,因此 for循环优于while循环,foreach优于传统for。
下面是遍历的首先做法:
//适用与集合和数组
for(Element e: c){
doSomething(e);
}
在java 1.5版本之前的首先做法如下:
// 遍历集合
for(Iterator i = c.iterator(); i.hasNext();){
doSomething((Element) i.next());
}
// 遍历数组
for(int i = 0; i<a.length; i++){
doSomething(a[i]);
}
下面是另一种局部变量作用域最小化的循环做法:
// expensiveComputation()方法用于获取n的数量,这样做 局部变量i,n作用域只在for循环内。
for(int i = 0, n = expensiveComputation(); i <n ; i++){
doSomething(i);
}
有三种情况无法使用for-each循环
- 1.过滤 —- 如果需要遍历集合,并删除选定的元素,就需要使用显示的迭代器,以便可以调用它的remove方法
- 2.转换 —- 如果需要遍历列表或者数组,并替换它全部或者部分元素值,就需要列表迭代或者数组索引,以便设定元素的值
- 3.平行迭代 —- 如果需要并行的遍历多个集合,就需要显示的控制迭代器或者索引变量,以便所有的迭代器或者索引变量都可以得到同步前移。
第49条:基本类型优于装箱基本类型
java 1.5版本增加了自动装箱和自动拆箱,他们之间主要有三个区别:
- 基本类型只有值,装箱基本类型则具有与他们的值不同的同一性,换句话说,俩个装箱基本类型可以具有相同的值和不同的同一性。
- 基本类型只有功能完备的值,而每个装箱基本类型除了他对应基本类型的所有功能值以外,还有一个非功能值: null。
- 基本类型通常比装箱基本类型更节省时间和空间。
考虑下面这个程序有什么问题:
public static void main(String[] args){
Long sun = 0L;
for(long i = 0; i<100; i++){
sum += i;
}
System.out.println(sum);
}
这段代码运行起来要比预想的慢很多,因为它不小心把局部变量sum声明为装箱基本类型Long。而不是基本类型long,这样程序编译起来没有错误或者警告,变量被反复的装箱和拆箱,导致明显的性能下降。
字符串的使用
如果其他类型更适合,要尽量避免使用字符串,字符串经常被错误的用来替代基本类型、枚举类型、聚集类型。
字符串连接操作符( + )适用于: 产生单独的一行输出,或者构造一个字符串来表示一个较小的、大小固定的对象。但是如果是连接n个字符串,频繁的使用字符串连接符,需要n的平方级的时间。这是因为字符串不可变,当俩个字符串连接在一起时,他们的内容都要被拷贝。
考虑下面这段代码:
public String statement(){
String result = "";
for(int i=0; i< numItems(); i++){
result += lineForItem(i); //String concatenation
}
return result;
}
如果项目数量巨大,这个方法的时间就难以估算。为了获得可以接受的性能,请使用StringBuilder代替String。(Java 1.5发行版本中增加了非同步StringBuilder类,代替现在过时的StringBuffer类)。
public String statement(){
StringBuilder b = new StringBuilder(numItems()*LINE_WIDTH);
for(int i = 0;i<numItems();i++){
b.append(lineForItem(i));
}
return b.toString();
}
第二种做法比第一张大约快85倍左右。