Effective-JAVA
文章目录
- Effective-JAVA
- 2. CREATING AND DESTROYING OBJECTS`创建和销毁对象`
- 2. Use BUILDERS when faced with many constructors `当面对许多构造函数时用建设者`
- 3. Enforce the singleton property with a private constructor or an enum type `执行单属性与一个私有构造函数或枚举类型`
- 4. Enforce noninstantiability with a private constructor `执行noninstantiability私有构造函数`
- 5. Avoid creating objects `避免创建对象`
2. CREATING AND DESTROYING OBJECTS创建和销毁对象
1. Use STATIC FACTORY METHODS instead of constructors 用静态工厂方法代替构造函数
ADVANTAGES 优势
- Unlike constructors, they have names
不同于构造函数,他们有名字
- Unlike constructors, they are not requires to create a new object each time they’re invoked
与构造函数不同,他们不需要在每次调用时创建一个新的对象
- Unlike constructors, they can return an object of any subtype of their return type
不同于构造函数,他们可以返回一个原返回类型的子类型的对象
- They reduce verbosity of creating parameterized type instances
他们减少创建参数化类型实例的冗长
DISADVANTAGES 劣势
- If providing only static factory methods, classes without public or protected constructors cannot be subclassed (encourage to use composition instead inheritance).
如果只提供静态工厂方法,没有公共的或受保护的类构造函数不能从它派生出子类(鼓励使用组合而不是继承)。
- They are not readily distinguishable from other static methods (Some common names (each with a different pourpose) are: valueOf, of, getInstance, newInstance, getType and newType)
他们不容易区分从其他静态方法(一些常见的名字(pourpose各异):返回对象的值,,getInstance,newInstance,方法和newType)
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
2. Use BUILDERS when faced with many constructors 当面对许多构造函数时用建设者
Is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters. 是一个很好的选择在设计类的构造函数或静态工厂会有多少量的参数
Builder pattern simulates named optional parameters as in ADA and Python. 建造者模式模拟命名可选参数如ADA和Python。
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
//Required parameters
private final int servingSize:
private final int servings;
//Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder (int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories (int val) {
calories = val;
return this;
}
public Builder fat (int val) {
fat = val;
return this;
}
public Builder carbohydrate (int val) {
carbohydrate = val;
return this;
}
public Builder sodium (int val) {
sodium = val;
return this;
}
public NutritionFacts build(){
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder){
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
Calling the builder
NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();
3. Enforce the singleton property with a private constructor or an enum type 执行单属性与一个私有构造函数或枚举类型
There are different ways to create singletons: 有不同的方法来创建单例:
Public final field 静态字段
public class Elvis{
public static final Elvis INSTANCE = new Elvis();
private Elvis(){...}
...
public void singASong(){...}
}
One problem is that a privileged client can invoke the private constructor reflectively. Against this attack the constructor needs to be modified to send an exception if it is asked to create a second instance. 一个问题是,有特权的客户机可以反射调用私有构造函数。针对这种攻击,如果要求创建第二个实例构造函数需要发送修改异常。
**Singleton with static factory ** 单例模式与静态工厂
public class Elvis{
private static final Elvis INSTANCE = new Elvis();
private Elvis(){...}
public static Elvis getInstance(){ return INSTANCE; }
...
public void singASong(){...}
}
In this approach it can be change to a non singleton class without changing the class API. 在这种方法中它可以改变一个非单例类不改变类的API。
**Serialize a singleton ** 序列化一个单例
It is needed a readResolve method and declare all the fields transient in addition to the implements Serializable to maintain the singleton guarantee. 需要一个readResolve方法并宣布所有字段瞬态除了实现了Serializable保持独立的保证。
private Object readResolve(){
//Return the one true Elvis and let the garbage collector take care of the Elvis impersonator
return INSTANCE;
}
Enum Singleton, the preferred approach (JAVA 1.5) Enum Singleton,首选的方法(JAVA 1.5)
public enum Elvis(){
INSTANCE;
...
public void singASong(){...}
}
Equivalent to the public field, more concise, provides serialization machinery for free, and guarantee against multiple instantiation, even for reflection attacks and sophisticated serialization. It is the best way to implement a singleton. 相当于公共领域,更简洁,免费提供序列化机械,并保证对多个实例化,即使对于反射攻击和复杂的序列化。这是最好的方法来实现一个单例。
4. Enforce noninstantiability with a private constructor 执行noninstantiability私有构造函数
For classes that group static methods and static fields. 类的静态方法和静态字段。
Used for example to: 例如:使用
- Group related methods on primitive values or arrays.
组织相关的原始值或数组的方法。
- Group static methods, including factory methods, for objects that implement a particular interface.
静态方法,包括工厂方法,实现特定接口的对象。
- Group methods on a final class instead of extending the class.
组最后一个类,而不是扩展类上的方法。
Include a private constructor
public class UtilityClass{
// Suppress default constructor for noninstantiability
// (Add comment to clarify why the constructor is expressly provided)
private UtilityClass(){
throw new AssertionError();
}
...
}
5. Avoid creating objects 避免创建对象
REUSE IMMUTABLE OBJECTS 重复使用使用不变的对象
Don’t do this 不要这样做
String s = new String("stringette");
Every call creates a new String instance. The argument “stringette” is itself one. This call in a loop would create many of them. 每个调用创建一个新的字符串实例。参数“stringette”本身就是一个。这个调用在一个循环中会创造很多。
Do this 这样做
String s = "stringette";
This one uses a single String instance rather than creating a new one. 这一次使用一个字符串实例而不是创建一个新的。
**Use static factory methods in preference to constructors [ Item 1](# 1. Use STATIC FACTORY METHODS instead of constructors 用静态工厂方法代替构造函数)**
使用静态工厂方法优先于构造函数项1`
Boolean.valueOf(String); Is preferable to the constructor Boolean(String).
REUSE MUTABLE OBJECTS THAT WON’T BE MODIFIED 重用可变的对象不会被修改
Don’t do this
public class Person {
private final Date birthDate;
...
public boolean isBabyBoomer(){
// Unnecessary allocation of expensive object.
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;
}
}
isBabyBoomer creates a new Calendar,TimeZone and two Date instances each time is invoked. isBabyBoomer创建一个新的日历,时区和两个日期每次调用实例。
public class Person {
private final Date 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);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer(){
return birthDate.compareTo(BOOM_START) >= 0 &&birthDate.compareTo(BOOM_END)<0;
}
}
**Prefer primitives to boxed primitives, and watch out for unintentional autoboxing ** 喜欢原语盒装原语,提防意外自动装箱
//Slow program. Where is the object creation?
public static void main (String[] args){
Long sum = 0L;
for (long i = 0 ; i<= Integer.MAX_VALUE; i++){
sum+=i;
}
System.out.println(sum);
}
sum is declared as Long instead of long that means that the programs constructs
Long instances.
**Object pools are normally bad ideas ** 对象池通常坏主意
Unless objects in the pool are extremely heavyweight, like a database connections. 除非对象池中非常重量级的,像一个数据库连接。