![](https://img-blog.csdnimg.cn/20201014180756738.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
Effective Java
bingooh
这个作者很懒,什么都没留下…
展开
-
2.1 使用静态工厂方法替代构造函数
使用静态工厂方法(static factory method)优点: 1.与构造函数相比,静态工厂方法具有更有意义的名称public Boolean(String string) {}//getBoolean()比new Boolean()名称上更有意义public static boolean getBoolean(String string) {} 2.静态...原创 2013-07-30 12:30:02 · 260 阅读 · 0 评论 -
2.2 使用builder替代多参数构造函数
如果构造函数参数超过4个,可以考虑使用builder创建对象。 如下,MultiConstructorShoe提供了多个构造函数,以避免使用包含最多参数的构造函数: package com.bingo.practice.effective.two.two;public class MultiConstructorShoe { //鞋的名称 private Str...原创 2013-07-30 15:29:43 · 180 阅读 · 0 评论 -
2.3 使用单例
以下单例模式利用JVM的类加载机制保证单例对象的线程安全和初始化(在第一次类被加载时,会初始化INSTANCE属性,进而创建单例对象)public class SingletonOne { //在类加载后立即初始化 public static final SingletonOne INSTANCE=new SingletonOne(); private SingletonO...原创 2013-07-31 11:41:36 · 46 阅读 · 0 评论 -
2.4 禁止创建工具类实例
使用以下方式不仅可以禁止创建工具类的实例,还可以禁止继承工具类注:工具类指仅包含静态方法的类,如java.util.Collectionspublic class MyUtil { private MyUtil(){ throw new IllegalAccessError(); }} 使用final可禁止类被继承,使用abstract可禁止创建类的实例(仍可...原创 2013-07-31 13:42:13 · 138 阅读 · 0 评论 -
2.5 避免创建不必要的对象
1.避免使用new String("hello")创建不必要的字符串对象(在Java里,字符串实现为常量,以上方式将创建不必要的字符串对象)。以下测试: private String temp; @BeforeClass public void init(){ //初始化创建hello字符串对象,避免影响后面测试 this.temp="hello"; } ...原创 2013-07-31 14:44:51 · 90 阅读 · 0 评论 -
2.6 移除过时的对象引用
如下代码(以下代码来自Effective Java一书):public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; public Stack() { elements = n...原创 2013-07-31 15:51:03 · 97 阅读 · 0 评论 -
2.7 不要使用finalize()
不使用的理由:1.不能确定finalize()什么时候被执行2.不能保证finalize()一定会被执行3.使用finalize()严重影响性能4.如果执行finalize()抛出异常,异常被忽略(不会有任何提示),此方法立刻终止执行,导致对象状态不一致 在以下情况可以谨慎使用:1.如InputStream,如果编程者忘记调用close(),可以在finalize()...原创 2013-07-31 16:13:49 · 108 阅读 · 0 评论 -
3.8 覆盖equals()时遵守一般规范
Object的equals()使用“==”进行比较。即如果2个对象具有相同的内存地址,那么这2个对象相同。 以下情况不需要覆盖equals():1.类的每个实例本来就是唯一的,如Thread类 2.不关心类的实例逻辑上是否相等(logical equality),如一般不关心两个Random对象是否产生相同的随机数序列 3.父类的equals()适用于子类,则子类不...原创 2013-08-06 09:55:05 · 72 阅读 · 0 评论 -
3.9 在覆盖equals()后,总是覆盖hashCode()
Set,Map等类会首先调用对象的hashCode(),根据返回的hash值比较对象是否相同(一般情况下可提高性能)。如果两个对象返回的hash值相同,则再调用对象的equals()进行比较。 以下类覆盖了equals(),使用phoneNumber比较对象是否相同:package com.bingo.practice.effective.three.nine;public ...原创 2013-08-06 10:53:34 · 65 阅读 · 0 评论 -
3.10-3.11 toString()、clone()
总是覆盖toString()以返回用户可读的信息,注意的地方:1.提供getter方法以单独获取toString()返回的数据,避免使用者解析toString()以获取数据 2.如果toString()返回的格式化的字符串,那么需提供注释说明,同时提供静态格式化方法 clone方法容易导致错误,一般不建议使用此方法,而是提供相应的构造函数或者静态工厂方法用于对象复制 ...原创 2013-08-06 11:55:41 · 59 阅读 · 0 评论 -
3.12 考虑实现Comparable接口
TreeMap,TreeSet,Arrays,Collections可能调用实现了Comparable接口的对象的compareTo()进行自然排序。实现compareTo()与实现equals()基本原则类似,不同点包括: 1.如果传入的比较对象的类型与当前对象不同,应抛出ClassCastException 2.如果x.compareTo(y)==0,那么应该x.equals...原创 2013-08-06 14:21:53 · 94 阅读 · 0 评论 -
4.13 最小化类和成员的可访问性
封装是OOP的特征之一,最小化类和成员的可访问性可提高封装度 JAVA的可访问性修饰符包括:private: 仅能本类访问package-private:默认(default)可访问范围,同一包类可访问protected: 同一包类和子类可访问public: 任何类都可访问注:顶级(top-l...原创 2013-08-06 16:20:44 · 67 阅读 · 0 评论 -
4.14 public类应使用accessor方法替代public属性
对本小节持保留意见 基本原则:1.如果一个类需要被其它包的类访问,那么应提供accessor方法(getter/setter) 2.package-private,private的类无需提供accessor方法 3.可直接使用public final的属性...原创 2013-08-07 09:21:30 · 103 阅读 · 0 评论 -
4.15 最小化类的可变性
Java里包含很多不可变的类,如String,Boolean,Integer,这些类的优点包括:1.简单2.线程安全3.可作为Map的key或集合元素 创建不可变类的基本原则包括:1.不提供任何可修改对象状态的方法,如setter方法2.不能继承3.使用final修饰所有属性4.使用private修饰所有属性5.不要引用任何可被外部修改的可变的对象(可引用...原创 2013-08-07 10:12:08 · 91 阅读 · 0 评论 -
4.16 优先使用Composition替代继承
使用继承可能破坏类的封装性,可能的问题包括:1.子类必须知道父类的内部实现才能正确的进行覆盖,如以下父类: public class Container { private List<Object> elements=new ArrayList<Object>(); public boolean add(Object e){ return ...原创 2013-08-07 11:27:12 · 86 阅读 · 0 评论 -
4.17 不要继承没有良好设计和文档说明的类
1.如果类的构造函数或可被覆盖的方法(使用public/protected修饰),调用了另一个可被覆盖的方法,那么必须使用文档说明前者是如何调用后者的,甚至可说明前者的具体内部实现。如4.16小节,应使用文档说明addAll()是如何调用add()方法的注:一般方法的注射只应该说明此方法做什么(what),而不应该说明如何做(how) 2.父类可能提供protected的钩子(ho...原创 2013-08-07 14:48:22 · 62 阅读 · 0 评论 -
4.18-4.19 使用接口
与使用抽象类相比,使用接口的优点包括:1.类更容易声明执行新的接口 2.接口更容易定义mixin,如同一个类可以实现Comparable、Iterable接口。在排序时,此类可视为Comparable类型,在迭代时,此类可视为Iterable类型 3.接口允许定义非层次化的类型框架,如一个人可以同时为歌手和作曲家,那么可让Person类同时实现Singer和SongWrite...原创 2013-08-07 15:54:44 · 66 阅读 · 0 评论 -
4.20 使用分层的多个类替代标签类
本小节请直接参考原文,基本上我还从未遇到类似标签类的写法 标签类:class TagFigure { enum Shape { RECTANGLE, CIRCLE }; // Tag field - the shape of this figure final Shape shape; // These fields are used only if ...原创 2013-08-08 08:56:58 · 73 阅读 · 0 评论 -
4.21 使用函数式对象实现策略模式
在JavaScript里,可以直接传递函数引用(被传递的函数可视为类型为Function的对象),如下:function sayHello(){ alert("hello, world!");}<input type="button" onclick="sayHello()"/ 在Java里,目前应该还不可以这样传递。但是可以使用函数式对象实现类似功能。函数...原创 2013-08-08 09:50:59 · 225 阅读 · 0 评论 -
4.22 嵌套类
嵌套类包括:1.静态成员嵌套类:可视为外部类的静态方法,可访问外部类的静态属性和方法。 2.成员嵌套类:可视为外部类的成员方法,可访问外部类的所有成员属性和方法。成员嵌套类的对象一定会和外部类的对象关联,如下两者将关联在一起(成员嵌套类可通过Outer.this访问所关联的外部类对象): Outer.Inner inner=new Outer().new Inner();...原创 2013-08-08 10:51:21 · 131 阅读 · 0 评论 -
5.23 使用泛型替代原始类型
JDK5引入了泛型,在新代码里应优先使用泛型替代原始类型(raw type) 泛型相关术语:List<E>generic type泛型Eformal type parameter形式参数List<String>parameterized type参数化类型Stringactual type parame...原创 2013-08-08 14:29:29 · 127 阅读 · 0 评论 -
5.24 消除未检查的警告
以下代码在编译时将给出一个未检查的警告(unchecked warning)://警告信息提示ArrayList应使用泛型List<String> list=new ArrayList(); 任何一个未检查的警告在运行时都可能导致抛出ClassCastException,因此应该尽量消除警告信息,如上代码应修改为:List<String> list=n...原创 2013-08-08 14:44:40 · 100 阅读 · 0 评论 -
5.25 优先使用List代替Array
List<E>与Array的区别:1.如果Child是Parent的子类,那么Child[]是Parent[]的子类型,而List<Child>与List<Parent>没有继承关系 2.Array在运行时检查存放在同一个数组里的元素必须是同一类型,List<E>是在编译时检查元素类型,在运行时泛型类型被擦除 以下代码说明以上...原创 2013-08-09 09:09:32 · 84 阅读 · 0 评论 -
5.26-5.29 使用泛型
以下类使用了泛型:public class Container <E>{ private List<E> elements=new ArrayList<E>(); public void addAll(List<E> list){ elements.addAll(list); } public void re...原创 2013-08-09 09:09:41 · 73 阅读 · 0 评论 -
6.30 使用枚举类代替常量
JDK5开始支持枚举功能,以下枚举类: public enum State { ON,OFF;} 枚举类State不能继承其它类,也不能被其它类继承,并且不能使用new创建State类型的对象。其实State可视为java.lang.Enum的子类,其中每一个枚举常量可视为State类型的实例,以下代码仅供理解: public class State {...原创 2013-08-09 11:53:34 · 169 阅读 · 0 评论 -
6.31 使用实例属性代替ordinal()
枚举类的ordinal()用于返回枚举量的序数,根据API说明,此方法仅应该被EnumSet,EnumMap使用。所以不要使用如下代码:public enum State { ON,OFF; public int numberOfState(){ //never do this; return ordinal()+1; }}可以使用成员属性存储序列号,修...原创 2013-08-09 14:11:54 · 124 阅读 · 0 评论 -
6.32 使用EnumSet代替bit属性设置
假设Text类是一个UI控件,此控件可以设置各种样式(Style)。一般情况下会使用int类型的常量定义各种样式,以便可以进行bit运算,如下:public class Text { //样式定义 public static final int STYLE_BOLD=1<<0;//1 public static final int STYLE_ITALIC=1<...原创 2013-08-09 14:37:26 · 158 阅读 · 0 评论 -
6.33 使用EnumMap替代使用枚举量的ordinal做索引
假设有如下类Food(食物),枚举类Type定义Food的类型:public class Food { public enum Type{FRUIT,VEGETABLE} private final Type type; private final String name; public Food(String name,Type type){ this....原创 2013-08-12 09:18:38 · 129 阅读 · 0 评论 -
6.34 使用接口模仿枚举类继承
枚举类不能继承其它类,但是枚举类可以继承接口,如下接口:public interface Operation { double apply(double x,double y);} BaseOperation、ExtendedOperation实现了此接口:public enum BaseOperation implements Operation { PLUS("+...原创 2013-08-12 09:56:30 · 112 阅读 · 0 评论 -
6.35 使用Annotation替代命名模式
一般测试框架类,如JUnit,TestNG都可以通过设置指定具有某些名称的方法为测试方法,如以test开头的方法为测试方法,这样做的缺点包括:1.如果方法名称拼写错误,不会有任何提示。如误拼为tsetHello(),测试时此方法不会被执行,但是也不会有任何错误提示 2.可能误执行其他方法,如testSafety()可能是业务方法,但因为符合测试方法的命名模式(以test开头的方法)...原创 2013-08-12 10:39:59 · 110 阅读 · 0 评论 -
6.36-6.37 使用Annotation
基本原则:1.总是使用@Override标记被覆盖的方法,@Override可以在编译时检查是否正确的覆盖方法,以便及时发现错误。如果你的类是非抽象的,并且继承了抽象类或实现了接口,仍然建议使用@Override注释 2.标记(marker)接口指不包含任何方法的接口,如Serializable,Set。如果需要限制方法的参数类型,或者减小接口范围(如Set接口继承Collectio...原创 2013-08-12 11:06:59 · 63 阅读 · 0 评论 -
7.38 验证输入参数
基本原则:1.尽可能早的校验输入参数的有效性,如在方法的第一行代码进行校验,以尽早的发现错误。 2.对于公共方法,如果校验失败应抛出异常,对于私有方法,建议使用assert关键字进行校验。在编译源码时,必须添加-ea参数,assert校验逻辑才能生效(对使用assert持保留意见) 3.使用注释详细说明方法的输入参数的有效性,以及如果校验失败,对应抛出的异常类型 ...原创 2013-08-13 14:03:35 · 161 阅读 · 0 评论 -
7.39 必要时使用保护性复制(defensive copy)
以下Period类用于表示两个日期之间的间隔: import java.util.Date;public class Period { private Date start; private Date end; public Period(Date start,Date end){ if(start.compareTo(end)>0) thr...原创 2013-08-13 15:10:31 · 152 阅读 · 0 评论 -
7.40 谨慎设计方法签名
基本原则:1.谨慎选择方法名称,应使用简单,一致的方法名称,可参考JAVA API相关方法 2.不要提供过多的方便方法,特别是对接口方法。如果不清楚此方法是否能带来便利,则不提供 3.避免使用过长的方法参数列表,解决方法包括:(1)把长参数列表的方法分为多个短参数的方法(2)创建帮助类用于传入多个参数,如下 public Person(String name,St...原创 2013-08-13 15:49:35 · 93 阅读 · 0 评论 -
7.41 谨慎使用方法重载(overloading)
以下类对不同的集合类型分类,classify()方法被重载: public class CollectionClassifier { public static String classify(Set<?> s){ return "Set"; } public static String classify(Collection<?> c)...原创 2013-08-13 17:05:12 · 139 阅读 · 0 评论 -
7.42 谨慎的使用变长参数
JDK5支持方法使用变长参数,如下: public void sayHello(String...names){ //变长参数names可视为数组 System.out.println(names.length); for(String name:names) System.out.println("Hello,"+name); } Arra...原创 2013-08-14 09:59:53 · 101 阅读 · 0 评论 -
7.43 返回空数组或集合代替null
返回空数组或集合代替null可以避免调用者检查返回值是否为null,进而可提高开发效率。 可以每次返回同一个空数组,以避免造成性能影响,如下: public class StringContainer { private List<String> list=new ArrayList<String>(); private static fin...原创 2013-08-14 10:27:12 · 242 阅读 · 0 评论 -
7.44 注释所有API元素
常用的注释标签包括:@param注释方法参数@param paramName@return注释方法返回值@return@throws注释方法可能抛出的异常@throws NullPointerException@code添加代码注释说明,常和<pre>一起使用<pre>{@code index<0}&...原创 2013-08-14 11:19:02 · 99 阅读 · 0 评论 -
8.45 最小化局部变量的可访问性
最小化局部变量的可访问性可以减小发生错误的几率,局部对象占用的内存可以及时GC。基本原则包括:1.仅在第一次使用时声明局部变量 2.声明局部变量时尽可能进行初始化 3.优先使用for循环代替while循环。以下代码局部变量i在整个sayHello()方法里都是可访问的: Collection<String> c=new ArrayList<String...原创 2013-08-14 11:52:49 · 71 阅读 · 0 评论 -
8.46 优先使用for-each循环代替for循环
使用for-each循环更简洁,进而减少错误,对比如下: Collection<String> parents=new ArrayList<String>(); Collection<String> childs=new ArrayList<String>(); for(Iterator<String> p=p...原创 2013-08-14 14:40:16 · 172 阅读 · 0 评论