Valid Java, inclutivejava
Valid Item-consider replacing the constructor with the static factory method. We have two common methods to obtain an instance of a class:
- Public Constructor
- Provides static factory method)
Static factory methods have the following advantages over public constructors.
Advantage 1. The name of the static factory method, so the returned instance is more accurate than the constructor.
For example, the BigInteger. probablePrime method is as follows:
public static BigInteger probablePrime(int bitLength, Random rnd) { if (bitLength < 2) throw new ArithmeticException("bitLength < 2"); // The cutoff of 95 was chosen empirically for best performance return (bitLength < SMALL_PRIME_THRESHOLD ? smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) : largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));}
By the way, it also posts the largePrime method that it calls:
private static BigInteger largePrime(int bitLength, int certainty, Random rnd) { BigInteger p; p = new BigInteger(bitLength, rnd).setBit(bitLength-1); p.mag[p.mag.length-1] &= 0xfffffffe; // Use a sieve length likely to contain the next prime number int searchLen = (bitLength / 20) * 64; BitSieve searchSieve = new BitSieve(p, searchLen); BigInteger candidate = searchSieve.retrieve(p, certainty, rnd); while ((candidate == null) || (candidate.bitLength() != bitLength)) { p = p.add(BigInteger.valueOf(2*searchLen)); if (p.bitLength() != bitLength) p = new BigInteger(bitLength, rnd).setBit(bitLength-1); p.mag[p.mag.length-1] &= 0xfffffffe; searchSieve = new BitSieve(p, searchLen); candidate = searchSieve.retrieve(p, certainty, rnd); } return candidate;}
Although smallPrime and largePrime finally return instances through the public constructor.
However, if you just use the constructor to reload the characteristics of this instance, it is difficult to remember when to call the constructor.
It is more intuitive to provide a name to describe the instance.
Advantage 2.The static factory method does not need to create a new object every time. We can control the instance.
In this way, we can cache the created instance for reuse, especially when the object creation cost is high.
For example, Boolean. valueOf:
public static final Boolean TRUE = new Boolean(true);public static final Boolean FALSE = new Boolean(false);public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE);}
Advantage 3.The static factory method can return the child type objects of the original return type.
This reflects the flexibility of static factory methods,
Take EnumSet as an example:
/** * Creates an empty enum set with the specified element type. * * @param elementType the class object of the element type for this enum * set * @throws NullPointerException if <tt>elementType</tt> is null */public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) { Enum[] universe = getUniverse(elementType); if (universe == null) throw new ClassCastException(elementType + " not an enum"); if (universe.length <= 64) return new RegularEnumSet<>(elementType, universe); else return new JumboEnumSet<>(elementType, universe);}
RegularEnumSet and JumboEnumSet are subclasses of EnumSet, and no public constructor is provided.
Advantage 4.The static factory method is more concise when creating parameterized (generic) instances.
For example:
public static <K, V> HashMap<K, V> newInstance() { return new HashMap<K, V>();}
In this way, you can:
Map<String,List<Integer>> n = newInstance();
Instead
Map<String,List<Integer>> m = new HashMap<String,List<Integer>>();
This has become meaningless since Java 7. In fact, Josh Bloch also mentioned this in the book-Java will execute this type derivation in constructors and method calls in the future.
Let's talk about the shortcomings of the static factory method.
- If the class does not include the public or protected constructor, it cannot be divided into categories.
So what I mentioned aboveThe static factory method can return the child type objects of the original return type.Not exactly.
Although we can solve this problem through composition, the two classes are notIs-Link.
- The essence of static factory method is static method, which does not have a special standard.
We cannot specifically mark a static factory method in the API documentation (maybe we can add a standard annotation ?).
When I want to find a method from the API to instantiate a class, it is not intuitive enough for the constructor.
Although there is no special standard, we can also make up for it with the standard name.
Such as valueOf, getInstance, newInstance, newType...