Tips
"Effective Java, third Edition" an English version has been published, the second edition of this book presumably many people have read, known as one of the four major Java books, but the second edition of 2009 published, to now nearly 8 years, but with Java 6, 7, 8, and even 9 of the release, the Java language has undergone profound changes.
In the first time here translated into Chinese version. For everyone to learn to share.
Entry 1. Consider using static factory methods instead of construction methods
The traditional way for a class to allow clients to get their instances is to provide a public constructor method. There's actually another technology that should be part of every programmer's toolkit. A class can provide a public static factory method, which is simply a static method that returns an instance of a class. The following is a Boolean
simple example ( boolean
the basic type of wrapper class). This method boolean
converts the base type to an Boolean
object reference:
public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE;}
Note that the static factory method differs from the factory method pattern in design mode [GAMMA95]. The static factory method described in this article is not directly equivalent in design mode.
Classes can provide static factory methods to their clients, rather than public construction methods. Providing a static factory method rather than a public construction method has advantages and disadvantages.
One advantage of the static factory approach is that, unlike construction methods, they have names. a static factory with a well-chosen name is easier to use if the constructor's parameters themselves do not describe the object being returned, and the resulting client code is more readable. For example, a construction method that returns a possible prime number BigInteger
BigInteger(int,int,Random)
can be better represented as a BigInteger.probablePrime
static factory method named. (This method is added in Java 1.4.) )
A class can have only one construction method for a given signature. Programmers know that by providing two construction methods to address this limitation, the parameter lists of the two constructor methods differ only in the order of their parameter types. This is a very bad idea. Such an API user will never remember which construction method is and will eventually be called incorrectly. People who read code that uses these constructs can only know what the code does in the case of a reference to a class document.
Because they have names, static factory methods are not subject to the limitations discussed above. In cases where multiple construction methods with the same signature appear to be required in a class, replace the construction method with a static factory method, and carefully select the names to highlight their differences.
the second advantage of static factory methods is that, unlike construction methods, they do not need to create a new object each time they are called. This allows immutable classes (entry 17) to use pre-built instances, or cache instances at construction time, and repeatedly assign them to avoid creating unnecessary duplicate objects. boolean.valueof(boolean)
method illustrates this approach: it never creates an object. This technique is similar to flyweight mode [Gamma95]. If you frequently request equivalent objects, it can greatly improve performance, especially if they are very expensive to create.
The ability of a static factory method to return the same object from a repeating call allows the class to maintain strict control over the instances that exist at any time. The class to do this is known as instance Control (instance-controlled). There are many reasons to write instance control classes. Instance control allows a class to guarantee that it is a singleton (3) Item or not instantiated (entry 4). At the same time, it allows an immutable value class (entry 17) to guarantee that there are no two identical instances: when and a== b
only a.equals(b)
. This is the basis of the enjoy meta model [GAMMA95]. Enum
type (Entry 34) provides this guarantee.
the third advantage of static factory methods is that they can return objects of any subtype of their return type, unlike construction methods. This gives you a lot of flexibility when choosing which class to return the object to.
One application of this flexibility is that the API can return an object without exposing its class. Hiding the implementation class in this way makes the API very compact I. This technique applies to interface-based frameworks (entry 20), where interfaces provide a natural return type for static factory methods.
Prior to Java 8, interfaces could not have static methods. According to the Convention, a Type
static factory method named interface is placed in a non-instantiated partner Class (companion Class) (Entry 4) Types
class. For example, the Java Collection Framework has a 45-interface utility implementation that provides a non-modifiable collection, a synchronous collection, and so on. Almost all of these implementations are exported through a static factory method in a non-instance class ( java .util. collections
). The classes that return objects are non-public.
Collections
The framework API is much smaller than the 45 separate public classes it previously exported, and each class has a convenience class implementation. Not only is the majority of the API reduced, but it also includes conceptual weights: the number and difficulty of concepts that programmers must master in order to use the API. The programmer knows that the returned object has exactly the API specified by its interface, so there is no need to read additional class documents for the implementation class. In addition, using this static factory method requires the client to refer to the returned object through an interface rather than an implementation class, which is usually a good practice (entry 64).
Starting with Java 8, the restriction that an interface cannot contain static methods is canceled, so there is usually no reason to provide an interface class that cannot be instantiated for the interfaces. Many public static members should be placed on the interface itself. Note, however, that it is still necessary to put most of the implementation code for these static methods in a separate package private class. This is because Java 8 requires that static members of all interfaces be public. Java 9 allows private static methods, but static fields and static member classes still need to be exposed.
the fourth advantage of a static factory is that classes that return objects can vary depending on the input parameters. any subclass of the declared return type is allowed. Classes that return objects can also vary with each publication.
EnumSet
Class (Entry 36) has no public constructor method, only static factory. In the OPENJDK implementation, they return an instance of one of two subclasses based on the size of the underlying enumeration type: If most enum types have 64 or fewer elements, the static factory returns an RegularEnumSet
instance that returns a type, and long
if the enumeration type has 65 or more elements, The factory returns an JumboEnumSet
instance, returning an long
array of type.
The existence of these two implementation classes is not visible to the customer. If you RegularEnumSet
no longer provide performance benefits for small enumeration types, you can retire them in a future release without having any adverse effects. Similarly, a future version may add a EnumSet
third or fourth implementation if it proves beneficial to performance. Customers neither know nor care about the categories of objects they return from the factory; They only care about EnumSet
some of the subcategories it is.
the 5th advantage of a static factory is that when you write a class that contains the method, the class of the returned object does not need to exist. This flexible static factory approach forms the basis of the service provider framework, such as the Java Database Connection API (JDBC). The service provider framework is the system in which the provider implements the service, and the system makes the implementation available to the client, separating the client from the implementation.
There are three basic groups in the service provider framework: The service interface, which represents the implementation, the provider registration API, the provider used to register the implementation, and the service access API, which the client uses to obtain an instance of the service. The Service Access API allows customers to specify criteria for selecting implementations. In the absence of such a standard, the API returns an instance of the default implementation, or allows the customer to traverse through all the available implementations. The Service access API is a flexible, static factory that forms the basis of the service provider framework.
An optional fourth component of the service provider framework is a service provider interface that describes a factory object that generates an instance of the service interface. In the absence of a service provider interface, a reflection of the implementation must be instantiated (entry 65). In the case of JDBC, as Connection
part of the service interface, the DriverManager.registerDriver
provider registration API, the DriverManager.getConnection
service access API, Driver
is the service provider interface.
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 provides to the client. This is the bridging mode [GAMMA95]. The Dependency Injection Framework (entry 5) can be seen as a powerful service provider. Starting with Java 6, the platform contains a common service provider framework java.util.ServiceLoader
, so you don't need to, and generally should not, write it Yourself (item 59). JDBC is not used ServiceLoader
because the former is earlier than the latter.
the primary limitation of providing only static factory methods is that classes that do not have a public or protected construction method cannot be overridden. For example, in a Collections
framework it is not possible to subclass any of the convenient implementations of subclasses. It can be said that this could be a blessing in disguise, as it encourages programmers to use combinations rather than inheritance (entry 18), and is immutable type (entry 17).
the second disadvantage of the static factory approach is that it is difficult for programmers to find them. They are not as prominent in the API documentation as the construction method, so it is difficult to figure out how to instantiate a class that provides a static factory method instead of a constructor method. The Javadoc tool may one day cause attention to the static factory method. At the same time, this problem can be reduced by attracting attention to a static factory in a class or interface document and following a common naming convention. The following are common names for some static factory methods. The following list is not complete:
- The From--a type conversion method, which takes a single parameter and returns a corresponding instance of this type, for example:
Date d = Date.from(instant)
;
- of--an aggregation method, takes multiple parameters and returns instances of that type, and merges them together, for example:
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING)
;
- Valueof--from and to a more detailed alternative, such as:
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE)
;
- Instance or getinstance--returns an instance that is described by its argument (if any), but cannot say that it has the same value, for example:
StackWalker luke = StackWalker.getInstance(options)
;
- Create or newinstance--is similar to instance or getinstance except that the method guarantees that each call returns a new instance, for example:
Object newArray = Array.newInstance(classObject, arrayLen)
;
- gettype--is similar to getinstance, but is used in different classes in a factory method. Type is the kind of object returned by the factory method, for example:
FileStore fs = Files.getFileStore(path)
;
- newtype--is similar to newinstance, but is used in different classes in a factory method. Type is the kind of object returned by the factory method, for example:
BufferedReader br = Files.newBufferedReader(path)
;
- Type--gettype and Newtype Concise alternative ways, such as:
List<Complaint> litany = Collections.list(legacyLitany)
;
In summary, both static factory methods and public construction methods have their uses, and it is worthwhile to understand their relative merits. In general, a static factory is preferable, so avoid providing a public construction method without considering a static factory.
Effective Java Third edition--1. Consider using static factory methods instead of construction methods