Effective Java学习笔记-通用程序设计
第45条:将局部变量的作用域最小化
1.在第一次使用变量时的地方声明;
2.几乎每个局部变量的声明都应该包含一个初始表达式;变量最好在try-catch里被初始化,不然一个变量被一个方法初始化时可能会抛出受检的异常(checked exception)。如果必须在try之前初始化,那么它必须是“无意义地初始化”,如:string s = null;
3.如果在终止循环之后不需要循环变量的内容,for循环优于while循环。(for循环比while循环还有个优势:更简洁,增强可读性)
第46条:for-each循环优于传统的for循环
1.对于多个集合进行嵌套迭代时,for-each循环优势更明显,使用传统for循环可能会发生NoSuchElementException
Class enum Face {ONE,TWO,THREE,FOUR,FIVE,SIX}
Collection<Face> faces = Arrays.asList(Face.Value())
for(Iterator<Face> i = faces.iterator();i.hasNext();)
for(Iterator<Face> j = faces.iterator();j.hasNext();)
System.out.println(i.next()+" "+j.next);
结果为:从ONE ONE到SIX SIX,6种组合
采用for-each:
for(Face i:Faces)
for(Face j:Faces)
System.out.println(i.next()+" "+j.next);
结果为:36种组合
2.for-each循环不仅可以遍历集合、数组和枚举,还可以遍历任何实现Iterable接口的对象。
3.无法使用for-each循环的情况:
过滤--如果需要遍历集合,并删除选定的元素;
转换--如果需要遍历集合,并取代部分或全部的元素值;
平行迭代--如果需要并行地遍历多个集合,如上面传统for循环的例子
第47条:了解和使用类库(最基本的:java.lang.*,java.util.*)
第48条:如果需要精确的答案,请避免使用float和double
1.float和double尤其不适合用于货币的计算,应使用BigDecimal,BigInteger;
2.BigDecimal有两个缺点:与使用基本运行类型相比很不方便,而且很慢;
3.如果性能非常关键,并且又不介意自己记录十进制小数点,而且涉及的数字又不太大,就可以使用int或者long;如果数字不超过9位可以是用哪个int;如果数字可能超过18位数字,就必须使用BigDecimal。
第50条:如果其他类型更适合,则尽量避免使用字符串
1.字符串不适合代替其他的值类型;如果不存在某个类型,就应该编写一个类型;
2.字符串不适合代替枚举类型;
3.字符串不适合代替聚集类型(一个实体有多个组件);因为这样做必须解析字符串,这个过程非常慢,也很繁琐,另外无法提供equals、toString或者compareTo方法。更好的做法是:简单地编写一个类来描述这个数据集,通常是一个私有的静态成员类(详见22条);
4.字符串也不适合代替能力表(capabilities)(有时候,字符串被用于对某种功能进行授权访问)
第51条:当心字符串连接性能
1.为连接n个字符串而重复使用字符串连接符(+),需要n的平方级时间。这是由于字符串不可变,当两个字符串被连接在一起时,他们的内容都要被拷贝;
2.可以使用StringBuilder替代String;
StringBuilder b = new StringBuilder(numItems()*LINE_WIDTH);
for(int i=0;i<numItems();i++){
b.append(lineForItem(i));
return b.toString();
}
3.StringBuilder类是非线程,StringBuffer是线程安全的
第52条:通用接口引用对象
1.优先使用接口而不是类来引用对象。如果有合适的接口类型存在,那么对参数、返回值、变量和域来说,就应该使用接口类型进行生命。只有当利用构造器创建某个对象的时候才真正需要引用这个对象的类;
List<Subscriber> subscribers = new ArrayList<Subscriber>();
2.如果没有合适的接口存在,完全可以用类而不是接口来引用对象,有三种情况:
1.具体类没有相关联的接口,例如:Random类;
2.对象属于基于类的框架,例如TimerTask抽象类;
3.类实现了接口,但它提供了接口中不存在的而外方法,例如:LinkedHashMap,如果程序依赖这些额外的方法,这种类就应该只被用来引用它的实例。
第53条:接口优先于反射机制
1.反射机制(reflection)允许一个类使用另一个类,即使当前者被编译的时候还根本不存在。然而这样做要付出代价:
1.丧失了编译时类型检查的好处;
2.执行反射访问所需要的代码非常笨拙和冗长;
3.性能损失。反射方法的调用比普通方法调用慢了许多。
反射功能只是在设计时被用到,普通应用程序运行时不应该以反射方式访问对象。
2.使用方法:
Method method = DefaultFullIndexer.class.getDeclaredMethod("removeAllIndex",
new Class[] {});
method.setAccessible(true); //true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java
语言访问检查。
method.invoke(defaultFullIndexer, new Object[] {});
3.反射机制的作用:对于有些程序,它们必须用到在编译时无法获取的类,但在编译时存在适当的接口或者超类,通过它们可以引用这个类。如果是这种情况,就可以以反射的方式创建实例,然后通过它们的接口或者超类,以正常的方式访问这些实例。如果适当的构造器不需要任何参数,那就不需要使用java.lang.reflect包,采用Class.newInstace方法就可以了;
第54条:谨慎地使用本地方法
1.本地方法主要有三个用途:访问特定于平台的机制(例如:访问注册表、文件锁)、提供访问遗留代码库的能力、通过本地语言编写应用程序中注重性能的部分以提高系统的性能;
2.java提供了一些:
1.4中增加java.util.prefs包,提供了注册表的功能;
1.6中增加了java.awt.SystemTray,提供了访问桌面系统托盘的能力;
3.使用本地方法的重要缺点:本地语言不是安全的;本地语言是与平台相关的。
第55条:谨慎地进行优化
不要因为性能而牺牲合理的结构。要努力编写好的程序而不是快的程序。
第56条:遵守普通接受的命名惯例