Article Author: Tyan
Blog: noahsnail.com Chapter 2 Creating and destroying Objects
This chapter concerns creating and destroying Objects:when and you to create them, where and how to avoid creating, H ow to ensure they are destroyed in a timely manner, and you to manage the any cleanup the actions that must precede their destruct Ion.
This chapter is about creating and destroying objects: when and how to create them, how to avoid creating them, how to ensure that they are destroyed in time, how to manage any cleanup operations, and that the cleanup must precede the object being destroyed. Item 1:consider Static factory methods instead of constructors Item 1: Consider using a static factory method instead of a constructor
The normal way for a class to allow a client to obtain a instance of itself are to provide a public constructor. There is another technique that should being a part of every programmer ' s toolkit. A class can provide a public static factory method, which is simply a static method that returns a instance of the class. Here's a simple example from Boolean (the boxed primitive class for the primitive type Boolean). This is translates a Boolean primitive value into a Boolean object reference:
A class that allows a customer to obtain an instance of itself is usually provided by providing a public constructor. There is another technology that should be part of every programmer's toolbox. A class can provide a public static factory Method,static factory method is a simple static way that returns an instance of a class. This has a simple example from a Boolean (the encapsulated class of the base type Boolean). This method converts a Boolean value to a reference to a Boolean object:
public static Boolean valueof (Boolean b) {return
B? Boolean.TRUE:Boolean.FALSE;
}
Note This a static factory method isn't the same as the factory method mode from design Patterns [Gamma95, p. 107]. The static factory method described in this item has no direct equivalent in design Patterns.
Note that static factory methods are different from the factory method in design patterns. The static factory method described in this entry is not equivalent to the factory method in design mode.
A class can provide its clients with the static factory methods instead of, or in addition to, constructors. Providing a static factory method instead of the a public constructor has both advantages and disadvantages.
A class can provide its customers with static factory methods to replace constructors, or provide a static factory method in addition to constructors. Providing static factory methods instead of public constructors has both advantages and disadvantages.
One advantage of static factory methods is that, unlike constructors, they have. If the parameters to a constructor don't, in and of themselves, describe the object being returned, a static factory with A well-chosen name is easier to use and the resulting client code easier to read. For example, the constructor BigInteger (int, int, Random), which returns a BigInteger this is probably prime, would have B Een better expressed as a static factory method named Biginteger.probableprime. (This is eventually added in the 1.4 release.)
The first advantage of static factory methods, compared to constructors, is that they have names. if the parameters of the constructor themselves do not describe the returned object, a static factory with the appropriate name is easier to use, and the resulting client code is easier to read. For example, the constructor BigInteger (int, int, Random) returns a BigInteger, the BigInteger may be a prime number, and it is better to use a static factory method named Biginteger.probableprime. (This method was eventually introduced in version 1.4.) )
A class can have only a single constructor with a given signature. Programmers have been known to get around this restriction by providing two constructors whose parameter lists In the order of their parameter types. This is a really bad idea. The user of such an API would never be able to remember which constructor is which and'll end up calling the wrong one by Mistake. People reading code that uses these constructors won't be know what the code does without referring to the class Documenta tion.
A class can have only one constructor with the specified signature. Programmers know how to circumvent this limitation: by providing two constructors, they differ only in the order of the parameter list types. This is really a bad idea. Users who use this API can never remember which constructor is which, and the wrong constructor is called unintentionally. People who use these constructors do not know what the code will do if they do not have a reference document for the class when they read the code.
Because they have names, static factory methods don ' t share the restriction discussed in the previous. In cases where a class seems to require multiple constructors with the same signature, replace the constructors with Stati C Factory methods and carefully chosen names to highlight their.
Because static factory methods have names, they do not have the kind of restriction that is discussed in the previous paragraph. When a class seems to require multiple constructors with the same signature, use static factory methods instead of constructors to highlight their differences by carefully selecting the name of the factory method.
a second advantage of static factory methods is that, unlike constructors, they are not required to create A new OBJEC T each time they ' re invoked. This is allows immutable classes (Item) to use preconstructed instances, or to cache instances as they ' re constructed, and Dispense them repeatedly to avoid creating unnecessary the duplicate. The Boolean.valueof (Boolean) method illustrates this technique:it never creates an object. This technique was similar to the Flyweight pattern [Gamma95, p. 195]. It can greatly improve performance if equivalent objects are requested often, especially if they are to create.
The second advantage of static factory methods, compared to constructors, is that it does not require a new object to be created each time when a static factory method is invoked. This allows immutable classes (Item 15) to use prebuilt instances, or cache constructed instances, to avoid creating unnecessary duplicate objects by repeatedly distributing them. The Boolean.valueof (Boolean) method illustrates this technique: it never creates an object. This technique is similar to the flyweight model [Gamma95, p. 195]. If you frequently request the same object, it can greatly improve performance, especially if the cost of creating objects is more expensive.
The ability of static factory methods to return the same object from repeated invocations allows classes to maintain stric T control over what instances exist. Classes that does this are said to be instance-controlled. There are several reasons to write instance-controlled classes. Instance control allows a class to guarantee, it is a singleton (item 3) or Noninstantiable (item 4). Also, it allows a immutable class (Item) to make the guarantee that no two equal instances Exist:a.equals (b) if and O nly if a==b. If A class makes this guarantee, then it clients can use the = = operator instead of the Equals (Object) method, which result in improved performance. Enum types (Item) provide this guarantee.
Static factory methods can return the same objects from repeated invocations, and at any time can make the class tightly control the existing instances. These classes are called control instances. There are some reasons to write control instance classes. Instance control allows a class to guarantee that it is a singleton (item 3) or not instantiated (item 4). It also allows a invariant class (Item 15) to guarantee that there are no two equal instances: A.equals (b) When and only if the a==b. If a class guarantees this, its clients can use the = = operator instead of the Equals (Object) method, which can lead to performance improvements. The enum type (Item 30) guarantees this.
A Third advantage of static factory methods is that, unlike constructors, they can return an object of any, subtype of Their return type. This gives your great flexibility in choosing the class of the returned object.
The third advantage of static factory methods, compared to constructors, is that they can return objects of any subtype of their return type. This makes it much more flexible to choose the class that returns the object.
One application of this flexibility are that the API can return objects without making their public. Hiding implementation classes in this fashion leads to a very compact API. This is technique lends itself to interface-based frameworks (Item) where interfaces provide the return natural for STA Tic Factory methods. Interfaces can ' t have static methods, so by convention, static factory methods to a interface named Type are put in a No Ninstantiable Class (Item 4) named Types.
One application of flexibility is that APIs can return objects without having to make their classes public. Hiding the implementation class in this way will have a more concise API. This technique applies to an interface based framework (Item 18), which provides a natural return type for static factory methods. An interface cannot have a static method, so by convention, the static factory method of an interface named type is placed in a class that is not instantiated (Item 4) named types.
For example, the Java collections Framework has thirty-two convenience implementations of its collection interfaces, Provi Ding unmodifiable collections, synchronized collections, and the like. Nearly all of this implementations are exported via static factory methods in one Noninstantiable class (Java.util.Collec tions). The classes of the returned objects are all nonpublic.
For example, the Java Collection Framework has a convenient implementation of 32 set interfaces, providing a set of immutable, synchronized collections, and so on. Almost all of these implementations are exported through a static factory method in a class that is not instantiated (java.util.Collections). The class that returns the object is not public.
The collections Framework API is very smaller than it would have been had it exported thirty-two public separate, One for each convenience implementation. It is not just the bulk of the API this is reduced, but the conceptual weight. The user knows that "returned object has precisely the API specified by its interface and so there are no need to read Addi tional class documentation for the implementation classes. Furthermore, using such a static factory method requires the client to refer to the returned object by its interface rathe R than its implementation class, which is generally good practice (Item 52).
The Set framework API is smaller than the 32 separate public classes it derives, each of which corresponds to a class. It's not just a decrease in the number of APIs, or a conceptual reduction. The user knows that the returned object contains the exact API specified by the interface and therefore does not need to read the documentation for the additional implementation class. In addition, using such a static factory method requires that the client use an interface reference to the object returned instead of its implementation class, which is usually the best practice (Item 52).
Not only can the class of an object returned by a public static factory method is nonpublic, but the class can vary from I Nvocation to invocation depending on the values of the parameters to the static factory. Any class this is a subtype of the declared return type is permissible. The class of the returned object can also vary from release to release for enhanced software maintainability and Performan Ce.
Not only the public static factory method returns the object's class can be non-public, and this class can also change as the parameter values entered when the static factory is invoked. Any subclass of the declared return value type is acceptable. To enhance software maintainability and performance, classes that return value objects can also change as the release version changes.
The Class Java.util.EnumSet (Item), introduced in release 1.5, has no public constructors, only static factories. They return one of two implementations, depending on the size of the underlying enum type:if it has sixty-four or fewer E Lements, as most enum types do, the static factories return a Regularenumset instance, which be backed by a single long; If the enum type has sixty-five or elements, the factories return a Jumboenumset instance and backed by a long array.
Class Java.util.EnumSet (Item 32) is introduced in version 1.5, and it has no public constructors, only static factory methods. Depending on the size of the enumeration type, the static factory method returns one of the two implementations, the category of the enumeration type: if there are 64 or fewer elements in the enumeration type, as with most enumerated types, the static factory returns a Regularenumset instance, supported by a single long If there are 65 elements or more in the enumeration type, the static factory method returns a Jumboenumset instance supported by long[].
The existence of these two implementation classes are invisible to clients. If Regularenumset ceased to an offer performance advantages for small enum types, it could is eliminated from future E with no ill effects. Similarly, a future release could add a third or fourth implementation of the If it enumset proved for beneficial. Clients neither know nor care about the class of the object they get back to the factory; They care only, it is some subclass of Enumset.
The two existing implementation classes are not visible to the client. If Regularenumset does not provide a performance advantage for a smaller number of enumerated types, removing it in future releases will not affect anything. Similarly, if the new Enumset implementation has a greater performance advantage, adding a third or fourth implementation of Enumset in a future release will have no impact. The client does not know or cares about the classes they are getting from the factory method; they only care that it is a subclass of Enumset.
The class of the object returned by a static factory method need not even exist at the time the class containing the Metho D is written. Such flexible static factory methods form the basis of service provider frameworks, Such as the Java Database connectivity API (JDBC). A service provider framework is a system in which multiple service providers implement a service, and the system makes the Implementations available to it clients, decoupling them from the implementations.
When writing the class that the static factory method belongs to, the class returned by the static factory method may not have to exist. This flexible static factory approach forms the basis for the service provider framework, such as the Java Database Link API (JDBC). The service provider framework is a system in which multiple service providers implement a service, and the system provides multiple implementations of services to the client, decoupling the client from the service.
There are three essential components of a service provider Framework:a service interface, which providers; A provider registration API, which the system uses to register implementations, giving clients access to them; and a service access API, which clients use to obtain a instance of the service. The service access API typically allows but does not require the client to specify the criteria for some a choosing. In the absence of such a specification, the API returns a instance of a default implementation. The service access API is the "flexible static Factory" which forms the basis of the service provider framework.
The service provider framework has three basic components: a service interface, a provider implementation, a provider registration API, a system for registering implementations, enabling clients to access them, and a service access API that clients use to get service instances. The Service access API usually allows, but does not require, clients to specify some rules for selecting providers. When not specified, the API returns a default implementation instance. The Service access API is a "flexible static factory" that forms the basis of a service provider framework.
An optional fourth component of the A service provider framework is a service provider interface, which providers implement to Create instances of their service implementation. In the absence's a service provider interface, implementations are registered by class name and instantiated reflectively (Item 53). In the case of JDBC, Connection plays the "part of the" service interface, Drivermanager.registerdriver is the provider Regi Stration API, Drivermanager.getconnection is the service access API, and Driver is the service provider interface.
The fourth optional component of the service provider framework is the service provider interface, which is implemented by the service provider to create an instance of the service implementation. In the absence of a service provider interface, the service implementation is registered through the class name and is instantiated by reflection (Item 53). In the case of JDBC, connection is the service interface, Drivermanager.registerdriver is the provider registration Api,drivermanager.getconnection service Access Api,driver is the service provider interface.
There are numerous variants of the service provider framework pattern. For example, the service access API can return a richer service interface than the one required of the provider, using the Adapter pattern [Gamma95, p. 139]. Here are a simple implementation with a service provider interface and a default provider:
There are many variants of the service provider framework pattern. For example, the service Access API can return a richer service interface than the provider needs by using the adapter pattern [Gamma95, p. 139]. The following is a simple implementation and default provider for the service Provider interface:
Service provider framework sketch//service Interface public interface Service {...//service-s Pecific methods go to//Service Provider Interface public interface Provider {Service Newservic
E (); }//Noninstantiable class for service registration and access public class services {private Services () {}//Prevents instantiation (Item 4)//Maps service names to services private static final map<st
Ring, provider> providers = new concurrenthashmap<string, provider> ();
public static final String default_provider_name = "<def>"; Provider registration API public static void Registerdefaultprovider (Provider p) {Registerprovider
(Default_provider_name, p);
public static void Registerprovider (String name, Provider p) {providers.put (name, p); }//Service access API public statIC Service newinstance () {return newinstance (default_provider_name);
The public static Service newinstance (String name) {Provider p = providers.get (name); if (p = = null) throw new IllegalArgumentException ("No provider registered with Name:
"+ name);
return P.newservice (); }
}
A Fourth advantage of static factory methods is that they reduce the verbosity of creating parameterized type instance S. Unfortunately, you must specify the type parameters if you invoke the constructor of a parameterized class even If they ' re obvious from the context. This typically requires your to provide the type parameters twice in quick succession:
the fourth advantage of static factory methods is that they reduce the verbosity of creating instances of parameterized types. Unfortunately, when you call the constructor of a parameterized class, you must specify the type parameters, even if they are very obvious in the context. This usually requires you to provide a two-time type parameter immediately:
Map<string, list<string>> m =
new hashmap<string, list<string>> ();
This redundant specification quickly becomes painful as the length and complexity of the type parameters increase. With a static factories, however, the compiler can figure out of the type parameters for you. This is known as type inference. For example, suppose which HashMap provided this static factory:
As the length and complexity of type parameters increase, this lengthy explanation quickly becomes painful. But using a static factory, the compiler can find the type parameters for you. This is called type derivation. For example, suppose HashMap is provided by this static factory:
public static <k, v> hashmap<k, v> newinstance () {return
new hashmap<k, v> ();
}
Then you could replace the wordy declaration above with this succinct alternative:
You can replace the lengthy statement above with the following concise form:
Map<string, list<string>> m = hashmap.newinstance ();
Someday the language may perform this sort of type inference on constructor invocations as-as-method invocations, but As of release 1.6, it does not.
One day, the Java language may have a type deduction similar to a method call on a constructor call, but it has not been available until release 1.6.
Unfortunately, the standard collection implementations such as HashMap do not have factory, methods as a release 1.6, but You can put the methods in your own utility class. More importantly, your can provide such static factories in your own parameterized.
Unfortunately, but until release 1.6, standard set implementations such as HashMap do not have factory methods, but you can put these methods into your own tool-like force. More importantly, you can provide such a static factory in your own parameterized class.
The main disadvantage of providing only static factory methods is this classes without public or protected constructors CA Nnot be subclassed. The same is true to nonpublic classes returned by public static factories. For example, it are impossible to subclass any of the convenience implementation the classes Framework. Arguably this can is a blessing in disguise, as it encourages programmers to use composition instead of inheritance (Item 16).
The disadvantage of providing only static factory methods is that classes without public or protected constructors cannot be subclasses. The same is true of non-public classes returned by public static factories. For example, it is not possible to subclass these convenience implementation classes in the collection framework. This can be said to be a blessing in disguise because it encourages programmers to use combinations instead of inheritance (Item 16).
A second disadvantage of the ' static factory methods is ' that they are ' not readily ' distinguishable from the other static methods. They do not stand out in API documentation in the way that constructors does, so it can is difficult to figure out Stantiate A class that provides static factory methods instead of constructors. The Javadoc tool may someday draw attention to static factory methods. In the meantime, your can reduce this disadvantage by drawing attention to static factories in class or interface comments, And by adhering to common naming conventions. Here are some common names for static factory methods:
Valueof-returns an instance that has, loosely speaking, the same value as its parameters. Such static factories are effectively type-conversion methods.
Of-a Concise alternative to valueof, popularized by Enumset (Item 32).
Getinstance-returns an instance it described by the parameters but cannot was said to have the same value. In the case of a singleton, getinstance takes no parameters and returns the sole instance.
Newinstance-like getinstance, except that newinstance guarantees this each instance returned be distinct from all others .
Gettype-like getinstance, but used when the factory was in a different class. Type indicates the type of object returned by the factory method.
Newtype-like newinstance, but used when the factory was in a different class. Type indicates the type of object returned by the factory method.
The second disadvantage of static factory methods is that they cannot be easily differentiated from other static methods. They cannot be clearly identified in the API document as a constructor, so it is difficult to figure out how to instantiate a class that provides a static factory method instead of a constructor. The Javadoc tool may one day focus on static factory methods. At the same time, you can reduce this disadvantage by paying attention to static factories in class or interface annotations and following common naming conventions. Here are some common names for static factory methods:
Valueof-is not strictly speaking, returns an instance that is the same as its parameter value. This static factory is a valid type conversion method.
A concise alternative to of-valueof, which is popular through Enumset (Item 32).
Getinstance-returns an instance that is described by a parameter, but cannot be said to be the same value. In a single case, getinstance has no parameters and returns a unique instance.
newinstance-in addition to newinstance guarantee that each returned instance is different from other instances, the other is similar to getinstance,
Gettype-is similar to getinstance when static factory methods are used in different classes. Type represents the object type returned by the static factory method.
Newtype-is similar to newinstance when static factory methods are used in different classes. Type represents the object type returned by the static factory method.
In summary, static factory methods and public constructors both have their uses, and it pays to understand their Merits. Often static factories are preferable, so avoid the reflex to provide public constructors without-a-static Factories.
In short, static factory methods and public constructors have their effects, and it is worthwhile to understand their comparative advantages. Static factories are often more appropriate, so avoid the habitual provision of public constructors without first considering static factories.