- 浏览: 65339 次
- 性别:
- 来自: 北京
文章分类
最新评论
1. 考虑用静态工厂方法代替构造函数
静态工厂方法优点:具有名字;每次调用时,不要求必须创建新对象;可以返回对象。
实质就是静态方法,可以方便的调用。缺点是不能被实例化。
//定义静态方法 Public class StaticTest { public static String getResults(String name) { return name; } } //调用 String name = StaticTest.getResults("tingor");
服务提供框架: 有一个Properties文件,每个Key对应一个Class,框架用来注册一个类,然后实例化。
public abstract class Foo { private static Map implementations = null; private static synchronized void initMapIfNecessary() { if (implementations == null) implementations = new HashMap(); } public static Foo getInstance(String key) { initMapIfNecessary(); Class c = (Class) implementations.get(key); if (c == null) return new DefaultFoo(); try { return (Foo) c.newInstance(); } catch (Exception e) { return new DefaultFoo(); } } public static void main(String[] args) { System.out.println(getInstance("NonexistFoo")); } } public class DefaultFoo extends Foo {}
2. 使用私有构造函数强化Singleton属性
singleton只能被实例化一次,通常用来代表唯一性的系统组件。
方法一: 饥饿加载 - 性能稍微优先 public class Singleton() { public static final MySingleton instance = new MySingleton(); private Singleton() {} public static MySingleton getInstance() { return INSTANCE; } } 方法二: 懒加载 public class Singleton { private static Singleton instance = null; private Singleton() {} public synchronized static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 为了维护singleton性,在序列化的时候需要提供一个readResolve方法,以便对象在反序列化的时候,会创建一个新的实例 public class Singleton() { public static final Singleton instance = new MySingleton(); private MySingleton() {} private Object readResolve() throws ObjectStreamException { return INSTANCE; } }
3. 通过私有构造函数强化不可实例化的能力
不能实例化一个类,一般用于工具类的范围。
public class UtilityClass { private UtilityClass() {} }
4. 避免创建重复的对象
4.1 不要重复创建同一个对象
String s = new String("silly"); //Don't do this String s = "silly"; //should do this
4.2 把只需要创建一次的局部变量变成final静态域
//错误做法(每次isBabyBoomer被调用的时候,都会创建Calendar和TimeZone,以及两个Date实例) public class Person { private final Date birthDate; public Person(Date birthDate) { this.birthDate = birthDate; } public boolean isBabyBoomer() { Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); Date boomStart = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); Date boomEnd = gmtCal.getTime(); return birthDate.compareTo(boomStart) >=0 && birthDate.compareTo(boomEnd) < 0; } } //改进之后 public class Person { private final Date birthDate; public Person(Date birthDate) { this.birthDate = birthDate; } private static final Date BOOM_START; private static final Date BOOM_END; static { Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0); Date boomStart = gmtCal.getTime(); gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0); Date boomEnd = gmtCal.getTime(); } public boolean isBabyBoomer() { return birthDate.compareTo(boomStart) >=0 && birthDate.compareTo(boomEnd) < 0; } }
5. 消除过期的对象引用
如果对象一直不被回收,那么很容易引起OutOfMemoryError的错误。
//Stack中,先增长,然后收缩,那么从栈弹出的对象将不会被回收;另一个例子在缓存,解决的办法是使用WeakHashMap public class Stack { private Object[] elements; private int size = 0; public Stack(int initialCapacity) { this.elements = new Object[initialCapacity]; } public void push(Object e) { ensureCapacity(); elements[size++] = e; } public Object pop() { if (size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if (elements.length == size) { Object[] oldElements = elements; elements = new Object[2 * elements.length + 1]; System.arraycopy(oldElements, 0, elements, 0, size); } } } //pop方法修改版本 public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; //消除旧的引用 return result; }
6. 避免使用终结函数
6.1 终结函数并不能保证能够执行,如果非要使用,那么首要考虑显示终止方法
Foo foo = new Foo(...); try { //Do what mush be done with foo } finally { foo.terminate(); //foo自带的外在终止方法,还有例如数据库的关闭连接方法 }
6.2 如果一类有一个终结函数,并且一个子类改写了终结函数,那么子类的终结函数必须要调用父类的终结函数
protected void finalize() throws Throwable { try { //Finalize subclass state } finally { super.finalize(); } }
6.3 如果一个子类改写了超类的终结函数,但忘了手工调用超类的终结函数,那么使用终结函数守卫者(finalizer guardian)来实现其终结,注意该终结函数放在一个匿名的类中
public class Foo { private final Object finalizerGuardian = new Object() { protected void finalize() throws Throwable { //finalize outer Foo object } } }
7. 在改写equals的时候请遵守通用约定
当一个类有自己特有的逻辑相等原则,而超类也没有改写,则需要改写Object.equals
自反性:x.equals(x)一定为true
对称性:y.equals(x)返回true, x.equals(y)一定也为true
传递性:x.equals(y)为true,y.equals(z)为true,那么x.equals(z)一定为true
一致性:多次调用x.equals(y)要么一直返回true,要么一致返回false
非空性:非空x,x.equals(null)一定返回false
public boolean equals(Obejct otherObject) { if (this == otherObject) return true; //检测this与otherObject是否引用同一个对象 if (otherObject == null) return false; //检测otherObject是否为null if (getClass() != otherObject.getClass) return false; //比较this与otherObject是否属于同一个类 if (!otherObject instanceof thisClass) return false; //该方法可以替代上一行判断 Employee other = (Employee)otherObject; //将otherObject转换为相应的类型 return name.equals(other.name) && salary == other.salary; //对所有域进行比较 }
8. 改写equals时总是要改写hashCode
private volatile int hashCode = 0; //延迟初始化 public int hashCode() { if (hashCode == 0) { int result = 17; result = 37 * result + areaCode; } return hashCode; }
9. 总是要改写toString
主要用于输出的程序便于调试
public String toString() { return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]"; }
10. 谨慎地改写clone
对于该条目,我认为最好不使用clone方法。
11. 考虑实现Comparable接口
compareTo方法允许简单的相等比较,也允许执行顺序比较,一般用于Arrays等数据结构
Arrays.sort(a);
12. 使类和成员的可访问能力最小化
好的设计,应该隐藏内部数据和具体细节
13. 支持非可变性
例如: String,BigInteger都是非可变类
非可变类,实例不能被修改,遵循5条规则
不要提供修改对象的方法
保证没有子类改写的方法
使所有的域都是final
使所有的域都成为私有的
保证对于可变组件的互斥访问
非可变对象本质上是安全的,所以不要求同步,这样类定义为final,就可以被多个线程共享
14. 复合优先于继承
包装类即装饰器的使用
15. 要么专门为继承而设计,并给出文档说明,要么禁止继承
16. 接口优于接口类
17. 接口只是被用于定义类型
在接口中,最好不要定义常量
18. 优先考虑静态成员类
声明的成员类不要求访问外围实例,那么应该加入static修饰符
嵌套类: 静态成员类,非静态成员类,匿名类,局部类
19. 用类代替结构
20. 用类层次代替联合
21. 用类代替enum结构
在Java5中,又加入了enum这种结构
//类型安全枚举 public class Suit { private final String name; private Suit(String name) { this.name = name; } public String toString() { return name; } public static final Suit CLUBS = new Suit("clubs"); public static final Suit DIAMONDS = new Suit("diamonds"); public static final Suit HEARTS = new Suit("hearts"); public static final Suit SPADES = new Suit("spades"); }
22. 用类和接口来代替函数指针
23. 检查参数的有效性
应该在抛出空指针或者其他不可获知异常之前,进行参数检查
public BigInteger mod(BigInteger m) { if (m.signum() <= 0) throw new ArithmenticException("Modulus not positive"); }
24. 需要时使用保护性拷贝
//原始类 public final class Period { private final Date start; private final Date end; public Period(Date start, Date end) { if (start.compartTo(end) > 0) throw new IllegalArgumentException(start + " after " + end); this.start = start; this.end = end; } public Date start() { return start; } public Date end() { return end; } } //修改Date Date start = new Date(); Date end = new Date(); Period p = new Period(start, end); end.setYear(78); //已经修改了时间 //重构之后的类 public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (start.compartTo(end) > 0) throw new IllegalArgumentException(start + " after " + end); } public Date start() { return (Date)start.clone(); } public Date end() { return (Date)end.clone(); }
25. 谨慎设计方法的原型
谨慎选择方法的名字
不要过于追求提供便利的方法
避免长长的参数列表(一般为3个): 有两个方法来避免:把一个方法分解成多个方法;创建辅助类
对于参数类型,优先使用接口而不是类
谨慎使用函数对象
26. 谨慎使用重载
27. 返回零长度数组而不是null
28. 为所有导出的API元素编写文档注释
29. 将局部变量的作用域最小化
局部变量应该在第一次使用它的地方声明,而不要过早在前面声明
如果循环终止后循环变量不再需要,那么for循环应该优先于while循
30. 了解和使用库
java.lang,java.util,java.io
31. 如果要求精确的答案,请避免使用float和double
尤为不合适货币计算,可以考虑BigDecimal
32. 如果其他类型更合适,则尽量避免使用字符串
33. 了解字符串连接的性能
使用StringBuffer或者StringBuilder代替
34. 通过接口引用对象
List subscribers = new ArrayList();
如果没有接口,那么就用基类来引用
35. 接口优于反射机制
36. 谨慎地使用本地方法
37. 谨慎地进行优化
努力避免那些限制性能的设计决定,考虑你的API设计决定的性能后果
38. 遵守普遍接受的命名惯例
39. 只针对不正常的条件才使用异常
40. 对于可恢复的条件使用被检查的异常,对于程序错误使用运行时异常
41. 避免不必要地使用被检查的异常
42. 尽量使用标准的异常
IllegalArgumentException: 参数的值不合适
IllegalStateException: 对于这个方法调用而言,对象状态不合适
NullPointerException: 在null被禁止的情况下参数值为null
IndexOutOfBoundException: 下标越界
ConcurrentModificationException: 在禁止并发修改的情况下,对象检测到并发修改
UnsupportOerationException: 对象不支持客户请求的方法
43. 抛出的异常要适合于相应的抽象
可以把异常进行包装,转译成容易理解的异常
44. 每个方法抛出的异常都要有文档
45. 在细节消息中包含失败-捕获异常
可以在异常中加入失败的消息,关键字符
46. 努力使失败保持原子性
//在其他动作之前,就进行size检查 public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; //消除旧的引用 return result; }
47. 不要忽略异常
48. 对共享可变数据的同步访问
49. 避免过多的同步
50. 永远不要在循环的外面调用wait
一般使用notifyAll()
51. 不要依赖于线程调度器
52. 线程安全性的文档化
53. 避免使用线程组
54. 谨慎地实现Serializable
实现了Serializable的代价是,一旦一个类发布,改变这个类的实现的灵活性将降低
为了继承而设计的类和内部类应该很少实现Serializable
55. 考虑使用自定义的序列化形式
56. 保护性地编写readObject方法
57. 必要时提供一个readResolve
对于Singleton需要
发表评论
-
Agile Java
2009-09-21 13:48 12851. 代码就是设计 2. ... -
Java经典实例(第二版)
2009-06-01 16:33 39801. 获取环境变量 System.getenv(" ... -
Java线程(第三版)
2009-04-03 14:09 29921. Thread生命周期 // 创建Thread ext ... -
Java编程思想(第四版) - 第22章 图形化用户界面
2009-04-03 13:14 816GUI -
Java编程思想(第四版) - 第21章 并发
2009-04-03 11:43 1070并发 -
Java编程思想(第四版) - 第20章 注解
2009-04-03 11:43 789注解 -
Java编程思想(第四版) - 第19章 枚举类型
2009-04-03 11:42 873枚举 -
Java编程思想(第四版) - 第18章 Java I/O系统
2009-04-03 11:41 857IO -
Java编程思想(第四版) - 第17章 容器深入研究
2009-04-03 11:40 902容器 -
Java编程思想(第四版) - 第16章 数组
2009-04-03 11:40 789数组 -
Java编程思想(第四版) - 第15章 泛型
2009-04-03 11:39 689泛型 -
Java编程思想(第四版) - 第14章 类型信息
2009-04-03 11:38 996类型信息 -
Java编程思想(第四版) - 第13章 字符串
2009-04-03 11:37 767字符串 -
Java编程思想(第四版) - 第12章 通过异常处理错误
2009-04-03 11:36 766异常 -
Java编程思想(第四版) - 第11章 持有对象
2009-04-03 11:31 867持有对象 -
Java编程思想(第四版) - 第10章 内部类
2009-04-03 11:30 744内部类 -
Java编程思想(第四版) - 第9章 接口
2009-04-03 11:29 715接口 -
Java编程思想(第四版) - 第8章 多态
2009-04-03 11:29 675多态 -
Java编程思想(第四版) - 第7章 复用类
2009-04-03 11:28 709复用类 -
Java编程思想(第四版) - 第6章 访问权限控制
2009-04-03 11:26 8051. public protectd package priv ...
相关推荐
"Effective Java读书笔记" Effective Java是一本关于Java编程语言的经典书籍,本笔记主要总结了Java语言的发展历程、静态工厂方法的应用、构造器模式的使用等重要知识点。 一、Java语言的发展历程 Java语言的发展...
《Effective Java》是Java编程领域的一本经典著作,由Joshua Bloch撰写,该书的第三版继续提供了关于如何编写高效、优雅、可维护的Java代码的指导。以下是基于给出的目录和部分内容提取的一些关键知识点: ### 第一...
在编程领域,特别是Java开发中,"Effective Java"是一本非常经典的书籍,由Joshua Bloch撰写,书中提出了一系列最佳实践和设计原则,以帮助开发者编写出更高效、更安全的代码。根据提供的标题和描述,我们将探讨三个...
《Effective Java》是Java开发领域的经典著作,作者Joshua Bloch深入浅出地阐述了编写高效、健壮的Java代码的技巧和最佳实践。以下是对该书部分内容的详细解释: 1. **产生和销毁对象** - Item1:静态工厂方法相比...
"Effective Java 读书分享" 《Effective Java》读书分享.pptx 是一本 Java 编程语言指南,旨在帮助开发者编写高质量、可维护的 Java 代码。该书包含 90 个条目,每个条目讨论一条规则,涵盖了 Java 编程语言的...
Effective Java 3 学习记录 本学习记录主要介绍了 Effective Java 3 中的静态工厂方法和 Builder 模式两部分内容。 一、静态工厂方法 静态工厂方法是指返回类实例的命名规则,例如:from、of、valueOf、instance ...
《Effective Java》是一本经典Java编程指南,作者是Joshua Bloch,这本书深入探讨了如何编写高质量、高效、可维护的Java代码。以下是对压缩包中各章节主要知识点的详细阐述: 1. **第2章 创建和销毁对象** - 单例...
标题“effective-java.pdf”与描述“effective-java.pdf”表明本文档是关于Java编程实践的指南,且内容可能来自于一本名为《Effective Java》的书籍,该书是由Joshua Bloch编写,被广泛认为是Java编程的权威指南。...
《Effective Java》是Java开发领域的经典著作,由Joshua Bloch编写,旨在提供一系列实用的编程准则和最佳实践。这本书的第三版包含了大量更新,涵盖了Java语言和平台的新发展,如Java 8和Java 9的新特性。以下是对...
《Effective Java》是Java开发领域的一本经典著作,由Joshua Bloch撰写,书中提出了一系列编程最佳实践和设计模式,帮助开发者写出更高效、更可靠、更易于维护的Java代码。配套代码`effective-java-examples-master`...
我尽我最大的可能为大家提供了一个最佳实践 —— 《effective java》 第三版。我希望第三版继续满足需求,同时继承前两版的精神。 Small is beautiful, but simple ain’t easy 。 蓝领不是贬低的意思,主要是 ...
《Effective Java 第三版》是由Joshua Bloch所著的一本关于Java编程的书籍,旨在向Java开发者传授编写高效、健壮、可靠的Java代码的最佳实践。书中分为多个章节,每一章节都详细介绍了Java语言中的一个特定主题,并...
《Effective Java》是Java编程领域的一本经典著作,由Joshua Bloch撰写,第二版发布于2008年。这本书旨在提供实用的编程指导,帮助开发者写出更高效、更可维护的Java代码。以下是对书中核心知识点的详细解读: 1. *...
Effective Java 读书笔记 - 枚举与注解 本文总结了Effective Java 中关于枚举与注解的知识点,涵盖了枚举类型的优点、使用指南、避免使用 int 常量、使用 EnumSet 和 EnumMap 等。 枚举类型的优点 枚举类型提供了...
Effective Java 第 3 版 中英双语effective Java(第3版)各章节的中英文学习参考,希望对Java技术的提高有所帮助,欢迎通过issue或pr提出建议和修改意见。目录(Contents)第 2 章 创建和销毁对象(创建和气氛对象...