Effective Java
Rate it:
Open Preview
Kindle Notes & Highlights
Read between June 5, 2018 - March 29, 2019
3%
Flag icon
One advantage of static factory methods is that, unlike constructors, they have names.
4%
Flag icon
A third advantage of static factory methods is that, unlike constructors, they can return an object of any subtype of their return type.
4%
Flag icon
A fourth advantage of static factories is that the class of the returned object can vary from call to call as a function of the input parameters.
4%
Flag icon
The EnumSet class (Item 36) has no public constructors, only static factories. In the OpenJDK implementation, they return an instance of one of two subclasses, depending on the size of the underlying enum type: if it has sixty-four or fewer elements, as most enum types do, the static factories return a RegularEnumSet instance, which is backed by a single long; if the enum type has sixty-five or more elements, the factories return a JumboEnumSet instance, backed by a long array. The existence of these two implementation classes is invisible to clients.
4%
Flag icon
The main limitation of providing only static factory methods is that classes without public or protected constructors cannot be subclassed. For example, it is impossible to subclass any of the convenience implementation classes in the Collections Framework.
4%
Flag icon
A second shortcoming of static factory methods is that they are hard for programmers to find. They do not stand out in API documentation in the way that constructors do, so it can be difficult to figure out how to instantiate a class that provides static factory methods instead of constructors. The Javadoc tool may someday draw attention to static factory methods.
4%
Flag icon
In the meantime, you can reduce this problem by drawing attention to static factories in class or interface documentation and by adhering to common naming conventions. Here are some common names for static factory methods. This list is far from exhaustive: • from—A type-conversion method that takes a single parameter and returns a corresponding instance of this type, for example: Date d = Date.from(instant); • of—An aggregation method that takes multiple parameters and returns an instance of this type that incorporates them, for example: Click here to view code image Set<Rank> faceCards = ...more
This highlight has been truncated due to consecutive passage length restrictions.
Brian
Good naming recommendations for common factory method patterns: • from(<obj to convert>) / valueOf • of(<list of objects to compose into obj>) • instance(<opts>) • create(<opts>) [alt. to instance that guarantees distinct instance from previous invocation, whereas instance may share singletons/oligarchs(?)] • get*Type*()/*type*(). [similar to instance, but for when factory method is in diff class from obj/interface returned] • new*Type*() [similar to create but for when factory method is in diff class from obj/interface returned]
5%
Flag icon
In short, the telescoping constructor pattern works, but it is hard to write client code when there are many parameters, and harder still to read it. The reader is left wondering what all those values mean and must carefully count parameters to find out. Long sequences of identically typed parameters can cause subtle bugs.
5%
Flag icon
a JavaBean may be in an inconsistent state partway through its construction. The class does not have the option of enforcing consistency merely by checking the validity of the constructor parameters.
Brian
(Javabean pattern is explicitly calling setters after simple constructor). On the other hand, the build() method at end of chain of builder pattern calls can ensure consistent/valid state and barf if not satisfied
5%
Flag icon
Instead of making the desired object directly, the client calls a constructor (or static factory) with all of the required parameters and gets a builder object. Then the client calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the client calls a parameterless build method to generate the object, which is typically immutable. The builder is typically a static member class (Item 24) of the class it builds.
7%
Flag icon
As a side effect, this idiom also prevents the class from being subclassed. All constructors must invoke a superclass constructor, explicitly or implicitly, and a subclass would have no accessible superclass constructor to invoke.
Brian
Hadn’t thought about that benefit of private constructor. But isn’t final class offering same thing?
9%
Flag icon
have your class implement AutoCloseable, and require its clients to invoke the close method on each instance when it is no longer needed, typically using try-with-resources to ensure termination even in the face of exceptions
9%
Flag icon
So what, if anything, are cleaners and finalizers good for? They have perhaps two legitimate uses. One is to act as a safety net in case the owner of a resource neglects to call its close method. While there’s no guarantee that the cleaner or finalizer will run promptly (or at all), it is better to free the resource late than never if the client fails to do so.
9%
Flag icon
A second legitimate use of cleaners concerns objects with native peers. A native peer is a native (non-Java) object to which a normal object delegates via native methods. Because a native peer is not a normal object, the garbage collector doesn’t know about it and can’t reclaim it when its Java peer is reclaimed.
9%
Flag icon
If clients surround all Room instantiations in try-with-resource blocks, automatic cleaning will never be required. This well-behaved client demonstrates that behavior: Click here to view code image public class Adult {     public static void main(String[] args) {         try (Room myRoom = new Room(7)) {             System.out.println("Goodbye");         }     } }
Brian
Try with resource is new to me. It invokes the close method because the Room class implements AutoClosable? And cleaner, by virtue of being registered, will get invoked at gc (maybe)?
Corey
· Flag
Corey
Yes. Try with resources is syntax sugar for:
Room myRoom = new Room();
try {
doStuff()....
} finally {
room.close();
}

Thats all there is to it.
12%
Flag icon
Also, this approach can cause infinite recursion: Suppose there are two subclasses of Point, say ColorPoint and SmellPoint, each with this sort of equals method. Then a call to myColorPoint.equals(mySmellPoint) will throw a StackOverflowError.
Brian
Feeling dense: why does this cause infinite recursion to have a class type check and fall back on parent equals() method? Oh is the key that it’s taking equals(Object o) and calling o.equals() in each subclass, so it’s ping-ponging back and forth between the two subclasses’ implementations?
12%
Flag icon
There is no way to extend an instantiable class and add a value component while preserving the equals contract, unless you’re willing to forgo the benefits of object-oriented abstraction.
12%
Flag icon
While there is no satisfactory way to extend an instantiable class and add a value component, there is a fine workaround: Follow the advice of Item 18, “Favor composition over inheritance.”
Corey liked this
12%
Flag icon
Instead of having ColorPoint extend Point, give ColorPoint a private Point field and a public view method (Item 6) that returns the point at the same position as this color point:
Brian
This example doesn’t actually use the ‘view’ method, asPoint() though....
13%
Flag icon
all objects must be unequal to null. While it is hard to imagine accidentally returning true in response to the invocation o.equals(null), it isn’t hard to imagine accidentally throwing a NullPointerException. The general contract prohibits this. Many classes have equals methods that guard against it with an explicit test for null:
13%
Flag icon
2. Use the instanceof operator to check if the argument has the correct type. If not, return false. Typically, the correct type is the class in which the method occurs. Occasionally, it is some interface implemented by this class.
13%
Flag icon
3. Cast the argument to the correct type. Because this cast was preceded by an instanceof test, it is guaranteed to succeed.
13%
Flag icon
If the type in Step 2 is an interface, you must access the argument’s fields via interface methods; if the type is a class, you may be able to access the fields directly, depending on their accessibility.
13%
Flag icon
When you are finished writing your equals method, ask yourself three questions: Is it symmetric? Is it transitive? Is it consistent? And don’t just ask yourself; write unit tests to check, unless you used AutoValue (page 49) to generate your equals method,
14%
Flag icon
Always override hashCode when you override equals (Item 11).
14%
Flag icon
b. Combine the hash code c computed in step 2.a into result as follows: result = 31 * result + c;
14%
Flag icon
When you are finished writing the hashCode method, ask yourself whether equal instances have equal hash codes. Write unit tests to verify your intuition (unless you used AutoValue to generate your equals and hashCode methods,
15%
Flag icon
The multiplication in step 2.b makes the result depend on the order of the fields, yielding a much better hash function if the class has multiple similar fields. For example, if the multiplication were omitted from a String hash function, all anagrams would have identical hash codes.
15%
Flag icon
The advantage of using a prime is less clear, but it is traditional. A nice property of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance on some architectures: 31 * i == (i << 5) - i. Modern VMs do this sort of optimization automatically.
15%
Flag icon
If you have a bona fide need for hash functions less likely to produce collisions, see Guava’s com.google.common.hash.Hashing
15%
Flag icon
Don’t provide a detailed specification for the value returned by hashCode, so clients can’t reasonably depend on it; this gives you the flexibility to change it. Many classes in the Java libraries, such as String and Integer, specify the exact value returned by their hashCode method as a function of the instance value. This is not a good idea
15%
Flag icon
providing a good toString implementation makes your class much more pleasant to use and makes systems using the class easier to debug.
15%
Flag icon
If you specify the format, it’s usually a good idea to provide a matching static factory or constructor so programmers can easily translate back and forth between the object and its string representation.
16%
Flag icon
Whether or not you specify the format, provide programmatic access to the information contained in the value returned by toString.
16%
Flag icon
Though the specification doesn’t say it, in practice, a class implementing Cloneable is expected to provide a properly functioning public clone method.
Brian
(Object has a protected clone() method that checks for Cloneable interface on its target—not a good pattern, by the way)
16%
Flag icon
note that immutable classes should never provide a clone method because it would merely encourage wasteful copying.
16%
Flag icon
} catch (CloneNotSupportedException e) {         throw new AssertionError();  // Can't happen     }
Brian
Why this exception substitution? Later explained: CloneNotSupportedException is a checked exception (AssertionError is not).
17%
Flag icon
the Cloneable architecture is incompatible with normal use of final fields referring to mutable objects, except in cases where the mutable objects may be safely shared between an object and its clone. In order to make a class cloneable, it may be necessary to remove final modifiers from some fields.
18%
Flag icon
If you extend a class that already implements Cloneable, you have little choice but to implement a well-behaved clone method. Otherwise, you are usually better off providing an alternative means of object copying. A better approach to object copying is to provide a copy constructor or copy factory.
19%
Flag icon
If you want to add a value component to a class that implements Comparable, don’t extend it; write an unrelated class containing an instance of the first class. Then provide a “view” method that returns the contained instance. This frees you to implement whatever compareTo method you like on the containing class, while allowing its client to view an instance of the containing class as an instance of the contained class when needed.
20%
Flag icon
For members of public classes, a huge increase in accessibility occurs when the access level goes from package-private to protected. A protected member is part of the class’s exported API and must be supported forever. Also, a protected member of an exported class represents a public commitment to an implementation detail (Item 19). The need for protected members should be relatively rare.
20%
Flag icon
Note that a nonzero-length array is always mutable, so it is wrong for a class to have a public static final array field, or an accessor that returns such a field. If a class has such a field or accessor, clients will be able to modify the contents of the array. This is a frequent source of security holes:
Brian
Oops, have committed this error before. Use immutable Collections (some examples https://www.baeldung.com/java-immutable-list) instead?
Robert
· Flag
Robert
This is often used as a workaround. If you have an anonymous inner class that needs to modify a value — say, an int — of its enclosing method (but values accessed by an inner class must be final) a fr…
21%
Flag icon
5. Ensure exclusive access to any mutable components. If your class has any fields that refer to mutable objects, ensure that clients of the class cannot obtain references to these objects. Never initialize such a field to a client-provided object reference or return the field from an accessor. Make defensive copies (Item 50) in constructors, accessors, and readObject methods (Item 88).
Brian
Key element to creating immutable classes
22%
Flag icon
Immutable objects are inherently thread-safe; they require no synchronization. They cannot be corrupted by multiple threads accessing them concurrently. This is far and away the easiest approach to achieve thread safety.
22%
Flag icon
Recall that to guarantee immutability, a class must not permit itself to be subclassed. This can be done by making the class final, but there is another, more flexible alternative. Instead of making an immutable class final, you can make all of its constructors private or package-private and add public static factories in place of the public constructors
22%
Flag icon
If you write a class whose security depends on the immutability of a BigInteger or BigDecimal argument from an untrusted client, you must check to see that the argument is a “real” BigInteger or BigDecimal, rather than an instance of an untrusted subclass. If it is the latter, you must defensively copy it under the assumption that it might be mutable
22%
Flag icon
If you choose to have your immutable class implement Serializable and it contains one or more fields that refer to mutable objects, you must provide an explicit readObject or readResolve method, or use the ObjectOutputStream.writeUnshared and ObjectInputStream.readUnshared methods, even if the default serialized form is acceptable. Otherwise an attacker could create a mutable instance of your class.
23%
Flag icon
Additionally, it isn’t always possible because some methods cannot be implemented without access to private fields inaccessible to the subclass.
Brian
Does composition address this problem though? Still sounds like unfortunate/poor design on part of parent class creator.
Robert
· Flag
Robert
Right, private methods often lock out extendability, composition and inheritance alike 😕.
23%
Flag icon
You might think that it is safe to extend a class if you merely add new methods and refrain from overriding existing methods. While this sort of extension is much safer, it is not without risk. If the superclass acquires a new method in a subsequent release and you have the bad luck to have given the subclass a method with the same signature and a different return type, your subclass will no longer compile [JLS, 8.4.8.3].
23%
Flag icon
This design is called composition because the existing class becomes a component of the new one. Each instance method in the new class invokes the corresponding method on the contained instance of the existing class and returns the results. This is known as forwarding, and the methods in the new class are known as forwarding methods. The resulting class will be rock solid, with no dependencies on the implementation details of the existing class.
Brian
It doesn’t exactly ‘solve’ the access to private members/methods problem. It forces you to reimplement them yourself, which you can then debate the merits of. Definitely can work when you’re augmenting a class. Harder when trying to change one small part of its existing behavior.
Robert
· Flag
Robert
Yea, re-implementing a couple private methods is the best you can hope for, but often you can't even do that because they're the only way to modify private state you need to modify (in which case you'…
« Prev 1