[Java study notes] Effective Java (Third Edition) Chapter 2 Creating and destroying objects

 

1 Section: static factory method in place of the constructor

For a class, the method of obtaining one example, is a common traditional constructor.

  Public class provides a static factory method (static factory method), it is only a static method returns the instance of the class.

  Example: Boolean packing type, base type boolean value converted into a Boolean object reference

public static Boolean valueOf(boolean b) {  
    return b ? Boolean.TRUE : Boolean.FALSE;  
}  

Different static factory method and constructors advantages :

  The first big advantage: the name. Easier to use, easier to read to understand.

  The second big advantage: they do not have to call every time a new object is created.

  The third major advantage: they can return any sub-type of the object type.

  For example Java Collections Framework is a set of tools to achieve the interface 45, can not be modified to provide a set of synchronous collection and so on. Almost all is through static factory method derived in a non-instantiated class (java.util.Collections) in.

  The fourth major advantage: All of the returned object class may change over each call, depending on the parameter value of the static factory method.

  Fifth advantage: class method returns the object belongs, in the preparation of the class containing the static factory method may not be present.

 

Static factory methods constitute the framework for the service provider (Service Provider Framework) basis. Such as JDBC (Java Database Connectivity) API.

Static factory method shortcomings :

  First: If the class does not contain a common or protected constructor can not be subclassed.

  Second: Programmer's hard to find them. In the API documentation does not explicitly identify it.

 

Some conventional static factory method name:

 from:

Date d = Date.from(instant);  

of:

Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);  

valueOf:

BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);  

instance或getInstance:

StackWaler luke = StackWaler.getInstance(options);  

create或newInstance:

Object newArray = Array.newInstance(classObject, arrayLen);  

getType:

FileStore fs = Files.getFileStore(path);  

newType:

BufferReader br = Files.newBufferReader(path);  

type (getType and newType simplified version):

List<Complaint> litany = Collections.list(legacyLitany);  

Summary, static factory methods and constructors have a total of usefulness, need to understand their own strengths. Static factory method is often more appropriate, and therefore avoid the first reaction to provide a public constructor, rather than considering a static factory method.

 

2 Section: To consider the use of a plurality of builder constructor arguments encountered

  Static factories and constructors have a common limitation: all is not well expand into a large number of optional parameters.

  The first embodiment (general solution): overlap constructor (telescoping constructor) mode:

    Providing a first constructor only essential parameters, the second configuration has an optional parameter, the third structure has two optional parameters, and so on, the last constructor contains all optional parameters.

    Disadvantages: overlapping configuration mode possible, but when there are many parameters difficult to write code is difficult to read.

 

  The second option: JavaBeans model:

    First call a no-argument constructor to create the object, and then call setter methods to set each of the required parameters and optional parameters for each.

   Disadvantage: during construction, JavaBeans may be in an inconsistent state. (Thread-safe) Another point is that this model can not be made immutable class.

  Third option: the builder (builder) mode:

   example:

   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 {
        // 必须属性
        private final int servingSize;
        private final int servings;
        // 可选属性
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder setCalories(int calories) {
            this.calories = calories;
            return this;
        }

        public Builder setFat(int fat) {
            this.fat = fat;
            return this;
        }

        public Builder setSodium(int sodium) {
            this.sodium = sodium;
            return this;
        }

        public Builder setCarbohydrate(int carbohydrate) {
            this.carbohydrate = carbohydrate;
            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;
}

  Use Code:

NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35).carbohydrate(27).build();

Builder mode easy to write and read.

Builder mode also applies to the class hierarchy. Example: abstract class Pizza, two subclasses, a NyPizza represents classic New York style pizza, a pizza Calzone represents filling the built-in half-moon. (Code omitted)

 Use Code:

NyPizza pizza = new NyPizza.Builder(SMALL).addTopping(SAUSAGE).addToping(ONION).build();
Calzone calzone = new Calzone.Builder().addTopping(HAM).sauceInside().build();

Summary: If the class constructor or static plant having a plurality of parameters, Builder model is a good choice, especially when the majority of parameters are optional.

 

3rd bar: private constructor or enumerations enforce singleton attribute

Singleton (Singleton) is a class instantiated only once. Generally used to represent a stateless objects, such as functions, or essentially only the components of the system.

Singleton will make it become the kind of client test becomes very difficult.

  Two common ways:

    1. Public final field: public static member is a final field:

  

// Singleton with public final field
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public void leaveTheBuilding() { ... }
}

   The advantages of the method:

  • API made it clear that this class is a singleton. Public static property is final, so it always contains the same object reference.
  • This method is very simple.

    2. Singleton with static factory public member is a static factory method:

// Singleton with static factory
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }
    public void leaveTheBuilding() { ... }
}

The advantages of the method:

  • It can easily be implemented into a non-singleton class, and the user need not change the code.
  • You can write a single generic embodiment factories.
  • The method can be used as a reference supplier, for example, Elvis :: instance equivalent to the Supplier <Elvis>.

In order to achieve Singleton class becomes serializable (Serializable), requires 2 points:

1. Declare Canada implements Serializable.

2. must declare all instance fields are transient (transient), and provides a method readResolve.

     Otherwise, every time you deserialize a serialized instance, will create a new instance.

// readResolve method to preserve singleton property
private Object readResolve() {
// Return the one true Elvis and let the garbage collector
// take care of the Elvis impersonator.
return INSTANCE;
}

Third Method: enumeration type declaration comprises a single element:

// Enum singleton - the preferred approach
public enum Elvis {
    INSTANCE;
    public void leaveTheBuilding() { ... }
}

 This method is similar in function to the public-domain approach, more concise. Serialization mechanism provided free of charge, absolutely prevent multiple instantiation.

   Summary: single-element enumerated type is often the best way to achieve the Singleton.

 

4 Section: strengthening ability can not be instantiated by a private constructor

  Sometimes you may need to write a class that contains only static methods and static fields. For example java.lang.Math or java.util.Arrays.

  Static method on the object as well as java.util.Collections way, it implements a particular interface, including factory method to organize.

  An abstract class is made by attempting to force the class is not instantiated class is not feasible.

  This class can be subclassed and the subclass may be instantiated.

  Only by allowing the class contains a private constructor, he can not be instantiated.

  Side Effects: such a class can be subclassed (not inherited). All constructors must be explicitly or implicitly invoke superclass (the superclass) constructor,

  And there is no subclass can access the superclass constructor can be called.

 

5 Section: priority resource dependency injection is introduced

  Many classes are dependent of one or more underlying resources. For example, the spelling checker need to rely on one or more dictionaries.

  Static tools and Singleton class does not need to refer to the class suited to low-level resources.

  It should be capable of supporting multiple instances of a class, each instance the use of resources (the dictionary in this example) specified by the client.

  The pattern condition is satisfied: When creating a new instance, the resource passed to the constructor. (A form of injection of dependency)

// Dependency injection provides flexibility and testability
public class SpellChecker {
    private final Lexicon dictionary;
    public SpellChecker(Lexicon dictionary)     {
        this.dictionary = Objects.requireNonNull(dictionary);
    }
    public boolean isValid(String word) { ... }
    public List<String> suggestions(String typo) { ... }
}

  In short, do not use static Singleton and Factory classes to implement depend on one or more underlying resource class, and the behavior of the resource will affect the behavior of the class, and do not directly use this class to create these resources.

  And speaking of these resources should be passed to the constructor or factory (or static factory, builder), to be created via them. That's dependency injection .

 

6 bar: avoid creating unnecessary objects

  Generally speaking, an object reuse the same function than to create a more appropriate target.

  Reuse faster and closer to the modern style of the code. If the object is immutable (immutable) (Item 17), it can always be reused.

  The first extra scene to create an object: String string:

String s = new String("bikini"); // DON'T DO THIS!

  This statement creates a new String instance each execution, and create these examples are unnecessary.

  If this usage occurs in cycles or method called frequently, it will create millions of unnecessary String instance.

  After the improvements:

String s = "bikini";

  The second object is created unnecessary scene: Regular expression:

  Write a method to determine whether a string is a valid Roman numeral:

// Performance can be greatly improved!

static boolean isRomanNumeral(String s) {

    return s.matches("^(?=.)M*(C[MD]|D?C{0,3})"

            + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

}

  This implementation problem is that it relies on String.matches method.

  Although String.matches is the easiest way to check whether a string and regular expression matching, but it is not suitable for re-use in the case of performance-critical.

  Because it is a positive expression created within a Pattern instance, and used only once, after the Pattern instance is garbage collection JVM.

  Create a Pattern instance is expensive because it requires regular expression compiled into finite state machine (finite state machine).

  To improve performance, the regular expression compiler is explicitly Pattern example a (non-variant) and cache it, reuse the same instance each call isRomanNumeral method:

// Reusing expensive object for improved performance
public class RomanNumerals {
    private static final Pattern ROMAN = Pattern.compile(
            "^(?=.)M*(C[MD]|D?C{0,3})"
            + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

    static boolean isRomanNumeral(String s) {
        return ROMAN.matcher(s).matches();
    }
}

  The third superfluous to create objects Scene: automatic packing (autoboxing)

  It allows the programmer to mix basic types and basic types of packaging, boxing and unboxing automatically as needed. Autoboxing blurred, but does not substantially eliminate the difference between the packing type and basic types.

// Hideously slow! Can you spot the object creation?

private static long sum() {
    Long sum = 0L;
    for (long i = 0; i <= Integer.MAX_VALUE; i++)
        sum += i;
    return sum;
}

  The result of this procedure is correct, but due to a wrong character, the results of running much slower than real.

  Long became a variable sum is declared but not long, which means that the program is constructed around 2 ^ 31 instances of unnecessary Long (Long to each type of sum variables increase a long type i).

  The type of variable sum instead of a Long long performance will be greatly improved. The lesson is clear: use Basic type instead of the basic types of packaging, but also pay attention to autoboxing unconscious.

  This entry should not be misunderstood to imply that created the object is expensive, you should avoid creating objects.

  Instead, create and recover small objects very cheap, the constructor will do very little work, especially in the modern JVM implementation. Create additional objects to enhance the program clarity, simplicity or functionality usually a good thing.

  On the contrary, by maintaining its own object pool to avoid creating objects is not a good practice, the object unless the pool is very heavyweight. Typical examples of the object using the pool is the correct database connection pool.

 

7   bar: the elimination of outdated references to objects

  Java language, when you run out of objects, they will be automatically recovered. It is easy to give you the impression that he was no longer need to consider what memory management, and it is not.

 

// Can you spot the "memory leak"?
public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        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];
    }

    /**
     * Ensure space for at least one more element, roughly
     * doubling the capacity each time the array needs to grow.
     */
    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}

  This program is no obvious error, but there is a potential problem - "memory leaks."

  Increased activity due to the increase of the garbage collector, or memory, the program's performance will decline. In extreme cases causes the program to fail (OutOfMemoryError) error.

 

  Program where a memory leak occurs?

  If a stack grow first, after contraction, then the pop-up from the stack object will not be garbage collected away, even though the program is no longer using a stack of references to these objects.

  This is because the internal stack to maintain the expiration of these references to objects (obsolete references). Expired reference is simply never again be dereference references.

  In the above code, any references outside of array "active portion (active portion)" are outdated. The movable portion is indexed by the subscript size smaller than those of the elements thereof.

  The solution to this problem is simple: once the object reference expired, simply clear these references (they will be set to null).

public Object pop() {
    if (size == 0)
        throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null; // Eliminate obsolete reference
    return result;
}

  Empty object references should be the exception rather than the norm. The best way to eliminate the outdated references is to allow a variable contains a reference to the end of its life cycle.

  Common memory leak scenario:

  1. As long as the class is to manage memory, the programmer should be alert to memory leaks . Once an element is released, any object that contains a reference element should be empty.

  2. Another common source of memory leaks is cached . Once the object reference into the cache, it is easy to forget it's there, and after it becomes irrelevant, still remain in the cache.

    One common solution, with representatives WeakHashMap cache, when the cache entry expires, they will be automatically deleted.

    Common solutions of the two, the cache entry should be removed from time to time useless. Clear the work can be done by a background thread (ScheduledThreadPoolExecutor).

  3. listeners and other callbacks. If you implement a API-- their client registered callback (callbacks), but does not explicitly revoke their registration.

    Unless some action to deal with, otherwise these callbacks will accumulate. One way to ensure the callback recovered waste is to store only a weak reference (weak references).

    For example, they are only stored in WeakHashMap key (key) in.

Guess you like

Origin www.cnblogs.com/fyql/p/11369712.html
Recommended