《Effective Java》学习笔记 —— 枚举、注解与方法
Java的枚举、注解与方法...
第30条 用枚举代替int常量
第31条 用实例域代替序数
可以考虑定义一个final int 代替枚举中的 ordinal() 方法。
第32条 用EnumSet代替位域(bit field)
如果底层的枚举类型不超过64个,则整个 EnumSet 就是用单个 long 来表示,因此性能上比得上位域的性能。
第33条 用EnumMap代替序数索引
第34条 用接口模拟可伸缩的枚举
定义一个接口,然后根据需要,采用不同的枚举,枚举都实现相同的接口,在应用中采用接口作形参。这种模式虽然可以模拟可扩展的枚举类型,但在使用上与原先的枚举类型相比会有很多限制,比如无法使用EnumMap等。
第35条 注解优先于命名模式
就单元测试而言,现在Java一般都用junit和jmockit的注解,命名模式在标注测试方法上对于编译器而言没有用武之地了。但一般测试方法都还是习惯以test开头。
第36条 坚持使用Override注解
第37条 用标记接口)定义类型
* 标记接口(maker interface)是没有包含方法声明的接口,例如Serializable
以下为“方法”章节部分:
第38条 检查参数的有效性
特别是来自不可信域的参数。
第39条 必要时进行保护性拷贝
反例:
1 public Period(Date start, Date end) { 2 this.start = start; 3 this.end = end; 4 }
正例:
1 public Period(Date start, Date end) { 2 this.start = new Date(start.getTime()); 3 this.end = new Date(end.getTime()); 4 }
第40条 谨慎设计方法签名
* 方法的名称应当始终遵循标准的命名习惯。
* 不要过于追求提供便利的方法。
* 避免过长的参数列表。
第41条 慎用重载
* 对于重载方法(overloaded method)的选择是静态的,而对于被覆盖的方法(overridden method)的选择则是动态的。
对于下面的例子,其实在未运行时已经确定了实际调用的方法。
1 import java.util.*; 2 import java.util.concurrent.DelayQueue; 3 4 /** 5 * @author https://www.cnblogs.com/laishenghao/ 6 * @date 2018/10/13 7 */ 8 public class BadOverload { 9 10 public String getType(List<?> list) { 11 return "List"; 12 } 13 14 public String getType(Set<?> set) { 15 return "Set"; 16 } 17 18 public String getType(Collection<?> collection) { 19 return "Unknown"; 20 } 21 22 public static void main(String[] args) { 23 24 Collection<?>[] collections = { 25 new ArrayList<>(), 26 new HashSet<>(), 27 new DelayQueue<>() 28 }; 29 30 BadOverload badOverload = new BadOverload(); 31 for (Collection<?> item : collections) { 32 System.out.println(badOverload.getType(item)); // all print "Unknown" 33 } 34 } 35 36 }
* 比较保守的做法:尽量不要导出具有相同类型参数数目的重载方法,或至少有一个完全不同类型的入参。
一个反例:Set 与 List 的 remove 方法造成的混淆:
Set只有一个remove方法,而List有两个:
boolean remove(Object o);
E remove(int index);
1 public static void main(String[] args) { 2 Set<Integer> set = new TreeSet<>(); 3 List<Integer> list = new ArrayList<>(); 4 5 // construct same data 6 for (int i = -3; i < 3; i++) { 7 set.add(i); 8 list.add(i); 9 } 10 11 // try to remove the non-negative numbers 12 for (int i = 0; i < 3; i++) { 13 set.remove(i); 14 list.remove(i); 15 } 16 17 // result: [-3, -2, -1] [-2, 0, 2] 18 System.out.println(set + " " + list); 19 }
第42条 慎用可变参数
* 检查参数的个数或在前面多写一个相同类型的参数。
1 static int min(int first, int... remainingArgs) { 2 int min = first; 3 for (int i : remainingArgs) { 4 if (i < min) { 5 min = i; 6 } 7 } 8 return min; 9 }
第43条 返回零长度的数组或者集合,而不是null
书中推荐返回固定的静态零长度数组或集合。对于固定的返回值,我认为应该视情况而定,如果是后台返回给前台,在没有元素的情况下,返回Collections.emptySet()等是合理的;但如果是在本模块下进行操作,这种不可变的集合就不太适用了,特别是需要对集合做进一步修改的时候。
第44条 为所有导出的API元素编写文档注释
本文地址: https://www.cnblogs.com/laishenghao/p/effective_java_note_enums_annotations_methods.html