Effective Java
Rate it:
Open Preview
Read between August 14, 2018 - April 3, 2019
8%
Flag icon
Generally speaking, whenever a class manages its own memory, the programmer should be alert for memory leaks. Whenever an element is freed, any object references contained in the element should be nulled out.
Joe Soltzberg
Is there any way to improve this or make this better at a language level? I don't think so...
Robert
· Flag
Robert
What about Weak references?
9%
Flag icon
This finalizer can record a reference to the object in a static field, preventing it from being garbage collected. Once the malformed object has been recorded, it is a simple matter to invoke arbitrary methods on this object that should never have been allowed to exist in the first place. Throwing an exception from a constructor should be sufficient to prevent an object from coming into existence; in the presence of finalizers, it is not. Such attacks can have dire consequences. Final classes are immune to finalizer attacks because no one can write a malicious subclass of a final class. To ...more
Joe Soltzberg
It seems that all of these issues stem from a lack of 'guarantees'. Is this a problem that can be fixed more generally or is this 'unsolvable' to some extent?
9%
Flag icon
One detail worth mentioning is that the instance must keep track of whether it has been closed: the close method must record in a field that the object is no longer valid, and other methods must check this field and throw an IllegalStateException if they are called after the object has been closed.
Joe Soltzberg
Why is it like this? Seems like this could be a common error...
17%
Flag icon
A final approach to cloning complex mutable objects is to call super.clone, set all of the fields in the resulting object to their initial state, and then call higher-level methods to regenerate the state of the original object. In the case of our HashTable example, the buckets field would be initialized to a new bucket array, and the put(key, value) method (not shown) would be invoked for each key-value mapping in the hash table being cloned. This approach typically yields a simple, reasonably elegant clone method that does not run as quickly as one that directly manipulates the innards of ...more
17%
Flag icon
a constructor, a clone method must never invoke an overridable method on the clone under construction (Item 19).
19%
Flag icon
Prior editions of this book recommended that compareTo methods compare integral primitive fields using the relational operators < and >, and floating point primitive fields using the static methods Double.compare and Float.compare. In Java 7, static compare methods were added to all of Java’s boxed primitive classes. Use of the relational operators < and > in compareTo methods is verbose and error-prone and no longer recommended.
20%
Flag icon
In other words, it is not acceptable to make a class, interface, or member a part of a pack-age’s exported API to facilitate testing.
20%
Flag icon
Instance fields of public classes should rarely be public (Item 16). If an instance field is nonfinal or is a reference to a mutable object, then by making it public, you give up the ability to limit the values that can be stored in the field. This means you give up the ability to enforce invariants involving the field. Also, you give up the ability to take any action when the field is modified, so classes with public mutable fields are not generally thread-safe. Even if a field is final and refers to an immutable object, by making it public you give up the flexibility to switch to a new ...more
Joe Soltzberg
The last point is a good argument against 'no need to abstract until necessary' with respect to getters.
Brian
· Flag
Brian
oh, interesting. you're taking it further and saying not to reveal the underlying data at all until needed. good point. think about what of the representation needs to be exposed, and only provide acc…
20%
Flag icon
You can expose constants via public static final fields, assuming the constants form an integral part of the abstraction provided by the class. By convention, such fields have names consisting of capital letters, with words separated by underscores (Item 68). It is critical that these fields contain either primitive values or references to immutable objects (Item 17). a field containing a reference to a mutable object has all the disadvantages of a nonfinal field. While the reference cannot be modified, the referenced object can be modified—with disastrous results.
Joe Soltzberg
It would be nice if this was its own, independent language feature
Brian
· Flag
Brian
to make an object immutable by type declaration? must be built into the class itself, but perhaps there could be a base type that did this pretty easily by making the core data private and unreachable…
Joe Soltzberg
· Flag
Joe Soltzberg
Oh, I actually was just referring to exposing constants via public static final fields and making that a bit less verbose

It would be nice if code was 'String constant VAR = "something"' instead of alw…
21%
Flag icon
Because the data fields of such classes are accessed directly, these classes do not offer the benefits of encapsulation (Item 15). You can’t change the representation without changing the API, you can’t enforce invariants, and you can’t take auxiliary action when a field is accessed.
22%
Flag icon
The major disadvantage of immutable classes is that they require a separate object for each distinct value.
Joe Soltzberg
Or more generally for each distinct set of values amongst all of its 'variable' fields. This could be used as a kind of 'upper memory bound' for immutable objects (depending on how many could/would be used and the distribution of the various values)
Brian
· Flag
Brian
y, would need to compute the worst case / probable case for memory consumption where combinatorics might blow up. but then again, what about String class? hard to be more wide open than that and it do…
Joe Soltzberg
· Flag
Joe Soltzberg
Very true. I think any kind of 'upper memory bound' like that would only really be useful as a theoretical concept
22%
Flag icon
The package-private mutable companion class approach works fine if you can accurately predict which complex operations clients will want to perform on your immutable class. If not, then your best bet is to provide a public mutable companion class. The main example of this approach in the Java platform libraries is the String class, whose mutable companion is StringBuilder (and its obsolete predecessor, StringBuffer).
Brian
· Flag
Brian
and then you restrict the operations available on the mutable companion class to just the manipulations needed, leaving the read operations to the immutable class? i remember using StringBuffer extens…
23%
Flag icon
Inheriting from ordinary concrete classes across package boundaries, however, is dangerous.
23%
Flag icon
Unlike method invocation, inheritance violates encapsulation [Snyder86]. In other words, a subclass depends on the implementation details of its superclass for its proper function. The superclass’s implementation may change from release to release, and if it does, the subclass may break, even though its code has not been touched. As a consequence, a subclass must evolve in tandem with its superclass, unless the superclass’s authors have designed and documented it specifically for the purpose of being extended.
23%
Flag icon
A related cause of fragility in subclasses is that their superclass can acquire new methods in subsequent releases. Suppose a program depends for its security on the fact that all elements inserted into some collection satisfy some predicate. This can be guaranteed by subclassing the collection and overriding each method capable of adding an element to ensure that the predicate is satisfied before adding the element. This works fine until a new method capable of inserting an element is added to the superclass in a subsequent release.
24%
Flag icon
If you are tempted to have a class B extend a class A, ask yourself the question: Is every B really an A? If you cannot truthfully answer yes to this question, B should not extend A. If the answer is no, it is often the case that B should contain a private instance of A and expose a different API: A is not an essential part of B, merely a detail of its implementation.
24%
Flag icon
First, the class must document precisely the effects of overriding any method. In other words, the class must document its self-use of overridable methods. For each public or protected method, the documentation must indicate which overridable methods the method invokes, in what sequence, and how the results of each invocation affect subsequent processing. (By overridable, we mean nonfinal and either public or protected.) More generally, a class must document any circumstances under which it might invoke an overridable method. For example, invocations might come from background threads or ...more
Joe Soltzberg
Sounds like trouble waiting to happen. Assuming that people will document is never a good assumption
24%
Flag icon
But doesn’t this violate the dictum that good API documentation should describe what a given method does and not how it does it? Yes, it does! This is an unfortunate consequence of the fact that inheritance violates encapsulation. To document a class so that it can be safely subclassed, you must describe implementation details that should otherwise be left unspecified.
25%
Flag icon
The best solution to this problem is to prohibit subclassing in classes that are not designed and documented to be safely subclassed. There are two ways to prohibit subclassing. The easier of the two is to declare the class final. The alternative is to make all the constructors private or package-private and to add public static factories in place of the constructors. This alternative, which provides the flexibility to use subclasses internally, is discussed in Item 17. Either approach is acceptable.
25%
Flag icon
If you feel that you must allow inheritance from such a class, one reasonable approach is to ensure that the class never invokes any of its overridable methods and to document this fact. In other words, eliminate the class’s self-use of overridable methods entirely. In doing so, you’ll create a class that is reasonably safe to subclass.
25%
Flag icon
You can eliminate a class’s self-use of overridable methods mechanically, without changing its behavior. Move the body of each overridable method to a private “helper method” and have each overridable method invoke its private helper method. Then replace each self-use of an overridable method with a direct invocation of the overridable method’s private helper method.
Joe Soltzberg
Build-in IDE tool?
25%
Flag icon
A major difference is that to implement the type defined by an abstract class, a class must be a subclass of the abstract class. Because Java permits only single inheritance, this restriction on abstract classes severely constrains their use as type definitions. Any class that defines all the required methods and obeys the general contract is permitted to implement an interface, regardless of where the class resides in the class hierarchy.
Joe Soltzberg
This use to be annoying sometimes before default methods...
26%
Flag icon
You don’t always need this level of flexibility, but when you do, interfaces are a lifesaver.
26%
Flag icon
Interfaces enable safe, powerful functionality enhancements via the wrapper class idiom (Item 18). If you use abstract classes to define types, you leave the programmer who wants to add functionality with no alternative but inheritance. The resulting classes are less powerful and more fragile than wrapper classes.
26%
Flag icon
there is an obvious implementation of an interface method in terms of other interface methods, consider providing implementation assistance to programmers in the form of a default method. For an example of this technique, see the removeIf method on page 104. If you provide default methods, be sure to document them for inheritance using the @implSpec Javadoc tag (Item 19).
26%
Flag icon
Writing a skeletal implementation is a relatively simple, if somewhat tedious, process. First, study the interface and decide which methods are the primitives in terms of which the others can be implemented. These primitives will be the abstract methods in your skeletal implementation. Next, provide default methods in the interface for all of the methods that can be implemented directly atop the primitives, but recall that you may not provide default methods for Object methods such as equals and hashCode. If the primitives and default methods cover the interface, you’re done, and have no need ...more
27%
Flag icon
A minor variant on the skeletal implementation is the simple implementation, exemplified by AbstractMap.SimpleEntry. A simple implementation is like a skeletal implementation in that it implements an interface and is designed for inheritance, but it differs in that it isn’t abstract: it is the simplest possible working implementation. You can use it as it stands or subclass it as circumstances warrant.
27%
Flag icon
The Apache SynchronizedCollection class is still being actively maintained, but as of this writing, it does not override the removeIf method. If this class is used in conjunction with Java 8, it will therefore inherit the default implementation of removeIf, which does not, indeed cannot, maintain the class’s fundamental promise: to automatically synchronize around each method invocation. The default implementation knows nothing about synchronization and has no access to the field that contains the locking object. If a client calls the removeIf method on a SynchronizedCollection instance in the ...more
Joe Soltzberg
Nice example
27%
Flag icon
In the presence of default methods, existing implementations of an interface may compile without error or warning but fail at runtime. While not terribly common, this problem is not an isolated incident either. A handful of the methods added to the collections interfaces in Java 8 are known to be susceptible, and a handful of existing implementations are known to be affected.
27%
Flag icon
the interface serves as a type that can be used to refer to instances of the class.
27%
Flag icon
Normally a utility class requires clients to qualify constant names with a class name, for example, PhysicalConstants.AVOGADROS_NUMBER. If you make heavy use of the constants exported by a utility class, you can avoid the need for qualifying the constants with the class name by making use of the static import facility:
Joe Soltzberg
Only keep the class name if it provides helpful context
Robert
· Flag
Robert
Personally, I'd make the recommendation the opposite way: only static import (remove the class name) if you're sure the context is not necessary for others.
28%
Flag icon
// Tagged class - vastly inferior to a class hierarchy! class Figure {     enum Shape { RECTANGLE, CIRCLE };
Joe Soltzberg
This is kind of conflicting with the classic Java Planet Enum example. A good mechanism for deciding whether to do an enum or use inheritance: 1. Does the list of values change? (planets don't change for example) 2. Are there too many arguments? (just 2 for planets, but maybe many more for other examples)
28%
Flag icon
Luckily, object-oriented languages such as Java offer a far better alternative for defining a single data type capable of representing objects of multiple flavors: subtyping. A tagged class is just a pallid imitation of a class hierarchy.
28%
Flag icon
To transform a tagged class into a class hierarchy, first define an abstract class containing an abstract method for each method in the tagged class whose behavior depends on the tag value. In the Figure class, there is only one such method, which is area. This abstract class is the root of the class hierarchy. If there are any methods whose behavior does not depend on the value of the tag, put them in this class. Similarly, if there are any data fields used by all the flavors, put them in this class. There are no such flavor-independent methods or fields in the Figure class. Next, define a ...more
28%
Flag icon
One common use of a static member class is as a public helper class, useful only in conjunction with its outer class.
28%
Flag icon
More seriously, it can result in the enclosing instance being retained when it would otherwise be eligible for garbage collection (Item 7). The resulting memory leak can be catastrophic. It is often difficult to detect because the reference is invisible.
28%
Flag icon
For example, consider a Map instance, which associates keys with values. Many Map implementations have an internal Entry object for each key-value pair in the map. While each entry is associated with a map, the methods on an entry (getKey, getValue, and setValue) do not need access to the map. Therefore, it would be wasteful to use a nonstatic member class to represent entries: a private static member class is best. If you accidentally omit the static modifier in the entry declaration, the map will still work, but each entry will contain a superfluous reference to the map, which wastes space ...more
Joe Soltzberg
Good example
30%
Flag icon
While you shouldn’t use raw types such as List, it is fine to use types that are parameterized to allow insertion of arbitrary objects, such as List<Object>. Just what is the difference between the raw type List and the parameterized type List<Object>? Loosely speaking, the former has opted out of the generic type system, while the latter has explicitly told the compiler that it is capable of holding objects of any type. While you can pass a List<String> to a parameter of type List, you can’t pass it to a parameter of type List<Object>. There are sub-typing rules for generics, and List<String> ...more
30%
Flag icon
This is the preferred way to use the instanceof operator with generic types: Click here to view code image // Legitimate use of raw type - instanceof operator if (o instanceof Set) {       // Raw type     Set<?> s = (Set<?>) o;    // Wildcard type     ... }
32%
Flag icon
To make this more concrete, consider the following code fragment: Click here to view code image // Why generic array creation is illegal - won't compile! List<String>[] stringLists = new List<String>[1];  // (1) List<Integer> intList = List.of(42);               // (2) Object[] objects = stringLists;                    // (3) objects[0] = intList;                              // (4) String s = stringLists[0].get(0);                  // (5)
34%
Flag icon
Although it is counterintuitive that List<String> is not a subtype of List<Object>, it really does make sense.
Joe Soltzberg
The key difference is the List<...> part
35%
Flag icon
For maximum flexibility, use wildcard types on input parameters that represent producers or
Joe Soltzberg
It also helps clarify the 'barebones' invariants of the object being operated on. So for example by doing <? extends Animals> instead of <Dog> or <Animal> helps clarify and codify that the method works on anything that has the properties of an Animal, not just a Dog or something like that
35%
Flag icon
PECS stands for producer-extends, consumer-super. In other words, if a parameterized type represents a T producer, use <? extends T>; if it represents a T consumer, use <? super T>. In our Stack example, pushAll’s src parameter produces E instances for use by the Stack, so the appropriate type for src is Iterable<? extends E>; popAll’s dst parameter consumes E instances from the Stack, so the appropriate type for dst is Collection<? super E>. The PECS mnemonic captures the fundamental principle that guides the use of wild-card types. Naftalin and Wadler call it the Get and Put Principle ...more
36%
Flag icon
// Explicit type parameter - required prior to Java 8 Set<Number> numbers = Union.<Number>union(integers, doubles);
36%
Flag icon
More generally, the wildcard is required to support types that do not implement Comparable (or Comparator) directly but extend a type that does.
36%
Flag icon
As a rule, if a type parameter appears only once in a method declaration, replace it with a wildcard. If it’s an unbounded type parameter, replace it with an unbounded wildcard; if it’s a bounded type parameter, replace it with a bounded wildcard.
36%
Flag icon
The swapHelper method knows that list is a List<E>. Therefore, it knows that any value it gets out of this list is of type E and that it’s safe to put any value of type E into the list. This slightly convoluted implementation of swap compiles cleanly.
Joe Soltzberg
Feels hacky...
36%
Flag icon
The purpose of varargs is to allow clients to pass a variable number of arguments to a method, but it is a leaky abstraction: when you invoke a varargs method, an array is created to hold the varargs parameters; that array, which should be an implementation detail, is visible. As a consequence, you get confusing compiler warnings when varargs parameters have generic or parameterized types.
Joe Soltzberg
:( why?
36%
Flag icon
If a method declares its varargs parameter to be of a non-reifiable type, the compiler generates a warning on the declaration.
Joe Soltzberg
This confused me a ton back in the day when I was writing a Database wrapper in Java
36%
Flag icon
it is unsafe to store a value in a generic varargs array parameter.
« Prev 1 3