EffectiveJava(Item: 1 to 12)

In the last five weeks. I was reading the “Effective Java”, which is a truly excellent book and I make some notes about it. I have been learning Java for nearly two years. However, I seldom think about structure my code or summarize my experience. “Effective Java” teach me a lot, such as how to structure my Java code with the customary and effective way to make programs work well, how to make my code more pleasant, elegant and graceful. In fact, I am not sure how much I have been use in my programs. Talk is cheap, I show you the code:

One: Creating and Destroying Objects
Item 1:Consider static factory method instead of constructors
why?
1).Static factory methods is that, unlike constructors, they have names.
2).Static factory methods is that,unlike constructors, they are not require to create a new object each time they’re invoked..
3).Static factory methods can return an object of any subtype of their return type.
4).Static method reduce the verbosity of creating parameterized type instances.
Attention:
1).The main disadvantage of providing only static factory methods is that classes without public or protected constructors cannot be subclassed.
2).Static factory method are not readily distinguishable from other static methods.

For example:

import java.util.*;
public class StaticFactoryMethods{

    public static<K,V> HashMap<K,V> newInstance(){

        return new HashMap<K,V>();
    }

    public static void main(String[] args){

        //Constructor style:
        //Map<String,List<String>> m=new HashMap<String,List<String>>();
        //StaticFactoryMethods style:
        StaticFactoryMethods hashMaps=new StaticFactoryMethods();
        Map<String,List<String>> m=hashMaps.newInstance();
    }
}

Item 2:Consider a builder when faced with many constructor parameters
when you faced a situation of that the constructor you created which including a lot parameters and some of that parameters are optioded. I would consider to use telescoping constructor pattern or JavaBean. But there is a very cool solution. It was builder pattern.
Show you the code directory first and then I would talk about it:

public class BuilderPattern{
    public static void main(String[] args){
        Car BMW=new Car.Builder(1,1,1,1).truck(1).
            drivenLicense(1).seatBelt(1).hood(1).build();
        System.out.println("BMW is a "+BMW.toString());
        Car jeep=new Car.Builder(1,1,1,1).truck(1).
            drivenLicense(1).build();
        System.out.println("jeep is a "+jeep.toString());
    }
}
class Car{
    private final int brake;
    private final int accelerator;
    private final int clutch;
    private final int gearshift;
    private final int truck;
    private final int drivenLicense;
    private final int seatBelt;
    private final int hood;

    static class Builder{
        //required parameters
        private final int brake;
        private final int accelerator;
        private final int clutch;
        private final int gearshift;
        //optional parameters
        private int truck=0;
        private int drivenLicense=0;
        private int seatBelt=0;
        private int hood=0;

        public Builder(int brake,int accelerator,
                int clutch,int gearshift){
            this.brake=brake;
            this.accelerator=accelerator;
            this.clutch=clutch;
            this.gearshift=gearshift;
        } 

        public Builder truck(int val){
            truck=val;
            return this;
        }
        public Builder drivenLicense(int val){
            drivenLicense=val;
            return this;
        }
        public Builder seatBelt(int val){
            seatBelt=val;
            return this;
        }
        public Builder hood(int val){
            hood=val;
            return this;
        }

        public Car build(){
            return new Car(this);
        }
    }

    private Car(Builder builder){
        brake =builder.brake;
        accelerator =builder.accelerator;
        clutch =builder.clutch;
        gearshift =builder.gearshift;
        truck =builder.truck;
        drivenLicense =builder.drivenLicense;
        seatBelt =builder.seatBelt;
        hood =builder.hood;
    }
    public String toString(){
        return "Car: [brake:"+brake+", accelerator:"+accelerator+
            ", clutch:"+clutch+", gearshift:"+gearshift+
            ", truck:"+truck+", drivenLicense:"+drivenLicense+
            ", seatBelt:"+seatBelt+", hood:"+hood+"]";
    }
}/*Output:
BMW is a Car: [brake:1, accelerator:1, clutch:1, gearshift:1, truck:1, drivenLicense:1, seatBelt:1, hood:1]
jeep is a Car: [brake:1, accelerator:1, clutch:1, gearshift:1, truck:1, drivenLicense:1, seatBelt:0, hood:0]
*///:~

If you choose telescoping constructor pattern to write the above codes, it is hard to write client code when there are many parameters, and harder still to read it. Of course, if you use a JavaBean to express the ‘Car’ class, it might be in an inconsistent state partway through its construction. But Builder pattern can avoid such of problems. Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if most of those parameters are optional. Client code is mush easier to read and write with builders. Also look like flexible and the code is absolute cool. But, remember that Builder pattern should be used only if there are enough parameters.

Item 3:Enforce the singleton property with a private constructor or an enum type
I don’t very understand what does that mean. Just simply thought that if you want to make a class to be singleton, you can use a private constructor or an enum type.
For example:

public class SingletonByPrivateConstructor{
    public static void main(String[] args){
        System.out.println(Water.WaterINSTANCE.toString());
        System.out.println(Food.getFoodInstance().toString());
        System.out.println(Meat.FISH);
    }
}
//private constaructor
class Water{
    private String name;
    public static final Water WaterINSTANCE =new Water("water");
    private Water(String name){this.name=name;}
    public String toString(){return name;}
}
class Food{
    private String name;
    private static final Food FoodINSTANCE =new Food("food");
    private Food(String name){this.name=name;}
    public static Food getFoodInstance(){return FoodINSTANCE;}
    public String toString(){return name;}
}
//enum type
enum Meat{
    FISH;
}/*Output:
water
food
FISH
*///:~

Item 4:Enforce noninstantiability with a private constructor
That’s very easy to understand. A class can be made noninstantiability by including a private constructor. It’s also better to throw an exception in that constructor, for it provides insurance in case the constructor is accidentally invoked from within the class. It guarantees that the class will never be instantiated under any circumstances.
For example:

public class NoNinstantiability{
    public static void main(String[] args){
        Instantiability ins=new Instantiability();
    }
}
class Instantiability{
    private Instantiability(){
        System.out.println("You cannot access me!");
        throw new RuntimeException();
    }
}/*Output:
NoNinstantiability.java:3: 错误: Instantiability()可以在Instantiability中访问private
        Instantiability ins=new Instantiability();
                                    ^
                                    1 个错误
*///:~

Item 5:Avoid creating unnecessary objects
The point is reuse an object instead of always create an object. As you can see from the example:

public class CreatingObject{
    public static void main(String[] args){
        int j=100000000;
        long pre=System.currentTimeMillis();
        createNewObject(j);
        long post=System.currentTimeMillis(); 
        System.out.println("createNewObject-->"+(post-pre)+"ms");
        long Ipre=System.currentTimeMillis();
        didnotCreateNewObject(j);
        long Ipost=System.currentTimeMillis();
        System.out.println("didnotCreateNewObject-->"+(Ipost-Ipre)+"ms");
    }

    public static void createNewObject(int j){
        for(int i=0;i<j;i++){
            String s=new String("aaa");
        }
     }
     public static void didnotCreateNewObject(int j){
        for(int i=0;i<j;i++){
            String s="bbb";
        }
    }
}/*Output:
createNewObject-->18ms
didnotCreateNewObject-->1ms
*///:~

In my machine, it take 18ms to run the createNewObject method while only take 1 ms to run the didnotCreateNewObject method, which is about 18 times faster. So don’t create unnecessary objects . There is a point you need to pay attention, which is always make the mistake in programming—the autoboxing. Remember the lesson: prefer primitives to boxed primitives, and watch out for unintentional autoboxing. Here’s the prove:

public class AutoBoxing{
    public static void main(String[] args){
        long pre=System.currentTimeMillis();
        boxedPrimitives();
        long post=System.currentTimeMillis(); 
        System.out.println("boxedPrimitives-->"+(post-pre)+"ms");
        long Ipre=System.currentTimeMillis();
        primitives();
        long Ipost=System.currentTimeMillis();
        System.out.println("primitives-->"+(Ipost-Ipre)+"ms");  
    }
    public static void boxedPrimitives(){
        Long sum=0L;
        for(Long i=0L;i<10000000L;i++){
            sum+=1;
        }
    }
    public static void primitives(){
        Long sum=0L;
        for(long i=0L;i<10000000L;i++){
            sum+=1;
        }
    }
}/*Output:
boxedPrimitives-->219ms
primitives-->141ms
*///:~

Item 6: Eliminate obsolete object reference
Java is a garbage-collected language. It can easily lead to the impression that you don’t have to think about memory management, but the fact is that this isn’t not true. If a stack grows and shrinks, the objects that were popped off the stack will not be garbage collected, even if the program using the stack has no more references to them. For example:

import java.util.*;
public class StackMemoryLeak{
    private Object[] elements;
    private int size=0;
    private static final int DEFAULT_INITIAL_CAPACITY=16;

    public StackMemoryLeak(){
        elements=new Object[DEFAULT_INITIAL_CAPACITY];
    }

    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)
            elements=Arrays.copyOf(elements, 2*size+1);
    }
}
   The pop method will lead memory leak.
   To solve this problem is very simple: null out references once they become obsolete. The corrected version of the pop like this:
    public Object pop(){
        if(size==0)
            throw new EmptyStackException();
        Object result= elements[--size];
        elements[size]=null;
         return result;
    }

But, you should keep in mind that nulling out object references should be the exception rather than the norm. Generally speaking, whenever a class manages its own memory, the programmer should be alert for memory leaks. Whenever an element is freed, any object reference contained in the element should be null out. Besides array, there are two situation you need to take care, which are caches, listener and callbacks for API.

Item 7: Avoid finalizers
Finalizers are unpredictable, often dangerous, and generally unneccessary. Their use can cause erratic behavior, poor performance, and portability problems.
1).Not only does the language specification provide no guarantee that finalizers will get executed promptly; it provides no guarantee that they’ll get executed at all;
2).If an uncaught exception is thrown during finalizers, the exception is ignored, and finalization of that object terminates. Uncaught exception can leave object in a corrupt state;
So what should you do instead of of writing a finalizer for a class whose objects encapsulate resources that require termination, such as files or threads? Just provide an explicit termination method. Explicit termination methods are typically used in combination with the try-finally construct to ensure termination. This is very common in coding. for example, I show you the code of loading drive:

 ...
 static{
        try{
            pp=new Properties();
             fis=DBUtil.class.getClassLoader().getResourceAsStream("com/hsp/utils/dbinfo.properties");
            pp.load(fis);
            url=pp.getProperty("url");
            username=pp.getProperty("username");
            driver=pp.getProperty("driver");
            password=pp.getProperty("password");
            Class.forName(driver);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try{
                fis.close();
            }catch(Exception e){
                e.printStackTrace();
            }
            fis=null; 
        }
    }
  …

However, there are two legitimate uses for finalizers:
1).Acting as a “safety net” in case the owner of an object forgets to call its explicit termination method;
2).Concerning object with native peers;
And you need to note that ”finalizer chaining” is not performed automatically. If a class has a finalizer and a subclass overrides it, the subclass finalizer must invoke the superclass finalizer manually or use finalizer guardian.

Two: Methods Common to All Objects
Item 8:Obey the general contract when overriding equals
This item tell you what you should obey during overriding equals method. Look here:
x, y, z are not-null reference
1).Reflexive: x.equals(x) must return true;
2).Symmetric:x.equals(y) must return true if and only if y.equals(x) returns true;
3).Transitive:if x.equals(y) return true and y.equals(z) return true, then x.equals(z) must return true;
4).Consistent:if x.equals(y) consistently return true or false , provided no information used in equals comparisons on the objects is modified;
5).x.equals(null) must return false;
Here’s a recipe for a high-quality equals method:
1).Use the == operator to check if the argument is a reference to this object;
2).Use the instanceof operator to check if the argument has the correct type;
3).Cast the argument to the correct type;
4).For each “significant” field in the class, check if that field of the argument matches the corresponding field of this object;
5).When you are finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent?

Item 9: Always override hashCode when you override equals
Remember that you must override hashCode in every class that override equals because the key provision that is violated when you fail to override hashCode is the second one: equals objects must have equal hash codes. Override hashCode is more complicated than override equals. A good hash function tends to produce unequal hash codes for unequal objects. This is exactly what is meant by the third provision of the hashCode contract. Here are some point:
1).Store some contract nonzero value, say, 17, in an int variable called result.
2).For each significant field f in your object(each field taken into account by the equals method, that is), and make a compute.
I. If the field is a boolean, compute(f?1:0).
II. If the field is a byte, char, short, or int, compute(int) f.
III. If the field id a long, compute(int) ( f ^ (f >>>32)).
IV. If the field is a float, compute Float.floatToIntBits(f).
V. If the field is a double, compute Double.doubleToLongBits(f), and then hash the resulting long as in step III.
VI. If the field is an object reference and this class’s equals method compares the field by recursively invoking equals, recursively invoke hashCode on the field.
VII. If the field is an array, treat it as if each element were a separate field.
3).Combine the hash code c computed in step 2). into a result as follows:
result =31 * result + c;
4). when you are finished writing the hashCode method, ask yourself whenther equal instances have equal hash codes. Write unit tests to verify your intuition!

Item 10: Always override toString
While java.lang.Object provides an implementation of the toString method, the string that it returns is generally not what the user of your class wants to see. For example:

public class ToString {

    public static void main(String[] args){
                ToString ts=new ToString();
                        System.out.println(ts.toString());

    }

}/*Output:
ToString@51de8adb
*///~

All right, I don’t like the result, its boring. So keep in mime that when practical, the toString return all of the interesting information contained in the object. You can specifying the format that you want to see, such a unambiguous, human-readable representation of the object.
Here is a simple example about how to override equals which include overriding hashCode and toString:

import java.util.*;
public class EqualsHashCodeToString{

    public static void main(String[] args){

        Set<Bird> Birds=new HashSet<Bird>();
        Bird b1=new Bird(new DNA(1001),"lily");
        Bird b2=new Bird(new DNA(1001),"lily");
        Birds.add(b1);
        Birds.add(b2);
        for(Bird b : Birds){
            System.out.println(b.toString());
        }
    } 
}
class DNA{
    private int id;

    public int getId(){
        return this.id;
    }

    public void setId(int id){
        this.id=id;
    }

    public DNA(){}

    public DNA(int id){this.id=id;}

    //override equals
    public boolean equals(Object d){
        return d instanceof DNA &&
            id == ((DNA)d).id;
    }

    //override toString
    public String toString(){
        return "DNA id is "+id;
    }

    //override hashCode
    public int hashCode(){
        return 17*id;
    }
}

class Bird{
    private DNA dna;
    private String name;

    public DNA getDna(){
        return this.dna;
    }

    public void setDna(DNA dna){
        this.dna=dna;
    }

    public String getName(){
        return this.name;
    }

    public void setName(String name){
        this.name=name;
    }

    public Bird(){}

    public Bird(DNA dna,String name){
        this.dna=dna;
        this.name=name;
    } 

    //override equals
    public boolean equals(Object b){
        return b instanceof Bird &&
            name.equals(((Bird)b).name) &&
            dna == ((Bird)b).dna;
    }

    //override toString
    public String toString(){
        return "This bird is "+name+", "+dna;
    }

    //override hashCode
    public int hashCode(){
        int result=17;
        result=37*result+dna.hashCode();
        result=37*result+name.hashCode();
        return result;
    }
}/*Output:
This bird is lily, DNA id is 1001
This bird is lily, DNA id is 1001
*///~

Trying to change the equals method return true and see what happened.

Item 11: Override clone judiciously
The Cloneable interface was intended as a mixin interface for objects to advertise that they permit cloning. But object’s clone method is protected. If you design a class for inheritance, be aware that if you choose not yo provide a well-behaved protected clone method, it will be impossible for subclasses to implements Cloneable. Considered its seldom to override clone, I would give a example to show how ta override clone method:

public class Clone{
    public static void main(String[] args) throws 
        CloneNotSupportedException{
        Human h1=new Human(21,"wayne");
        Human h2=(Human)h1.clone();
        System.out.println(h1==h2);
        System.out.println(h1.equals(h2));
        System.out.println(h1.getAge()==h2.getAge());
        System.out.println(h1.getName().equals(h2.getName()));
    }
}
class Human{
    private int age;
    private String name;

    public int getAge(){
        return this.age;
    }
    public void setAge(int age){
        this.age=age;
    }
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name=name;
    }

    public Human(){}

    public Human(int age,String name){
        this.age=age;
        this.name=name;
    }

    public boolean equals(Object h){
        return h instanceof Human &&
            this.age==((Human)h).age &&
            this.name.equals(((Human)h).name);
    }

    //override clone
    public Object clone() throws CloneNotSupportedException{
        Human h=new Human(this.age,this.name);
        return h;
    }
}/*Output:
false
true
true
true
*///~

Item 12: Consider implementing Comparable
CompareTo is the sort method in the Comparable interface. It is similar in character to Object’s equals method. Also have Reflexive, Symmetric, Transitive, Consistent, and not-null. Be aware of some interfaces such as Collection, Set, Map. The general contracts for these interfaces are defined in terms of the equals method, but sorted collections use the equality test imposed by compareTo in place of equals. For example:

import java.util.*;
class Individual implements Comparable<Individual>{
    private static long counter =0;
    private final long id=counter++;
    private String name;
    public Individual(String name){this.name=name;}
    public Individual(){}
    public String toString(){
        return getClass().getSimpleName()+
            (name==null? "" : "" +name);
    }
    public long id(){return id;}
    public boolean equals(Object o){
        return o instanceof Individual &&
            id==((Individual)o).id;
    }
    public int hashCode(){
        int result=17;
        if(name!=null)
            result=37*result+name.hashCode();
        result=37*result+(int)id;
        return result;
    }
    public int compareTo(Individual arg){
        String first=getClass().getSimpleName();
        String argFirst=arg.getClass().getSimpleName();
        int firstCompare=first.compareTo(argFirst);
        if(firstCompare!=0)
            return firstCompare;
        if(name !=null && arg.name!=null){
            int secondCompare=name.compareTo(arg.name);
            if(secondCompare!=0)
                return secondCompare;
        }
        return (arg.id<id ? -1 : (arg.id==id ? 0 :1));
    }
}
public class IndividualTest{
    public static void main(String[] args){
        Set<Individual> pets=new TreeSet<Individual>();
        Individual in1=new Individual("cat");
        Individual in2=new Individual("fish");
        Individual in3=new Individual("bird");
        Individual in4=new Individual("dog");
        Individual in5=new Individual("pig");
        Individual in6=new Individual("cow");
        Individual in7=new Individual("sheep");
        pets.add(in1);
        pets.add(in2);
        pets.add(in3);
        pets.add(in4);
        pets.add(in5);
        pets.add(in6);
        pets.add(in7);
        System.out.println(pets);
    }
}/*Output:
[Individualbird, Individualcat, Individualcow, Individualdog, Individualfish, Individualpig, Individualsheep]
*///:~
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值