Effective Java
Rate it:
Open Preview
Kindle Notes & Highlights
Read between June 5, 2018 - March 29, 2019
24%
Flag icon
There are a number of obvious violations of this principle in the Java platform libraries. For example, a stack is not a vector, so Stack should not extend Vector.
Brian
Haven’t used stack so had no idea this was done. Wow. Though I admit there is definitely a period in my career when I would've considered this approach. But then again, I shouldn't have been writing the Java API then (nor even now, surely ;) ).
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.
Brian
Heh. The internal method calls in effect become part of the API: you guarantee forever which calls will be made when. I see his point, but feel this shouldn’t be needed, unless you’re trying to expose hooks that subclasses intentionally provide. But this feels more like an abstract class pattern than inheritance from concrete class.
24%
Flag icon
Designing for inheritance involves more than just documenting patterns of self-use. To allow programmers to write efficient subclasses without undue pain, a class may have to provide hooks into its internal workings in the form of judiciously chosen protected methods
Brian
I like seeing this done well. It can really make development within a larger framework very efficient when repetitive, annoying tasks are just taken care of for you. I see a lot of @nnotations trying to abstract this even further from the code, but prefer explicit abstract patent classes to provide this. It’s hard to know all of the needed hooks to create though and you may often revisit the hooks design over time. If you own all the code, no problem though, this ends up being small cost when amortized over years. But woah, if you’re building a framework for others, look out! :)
25%
Flag icon
The only way to test a class designed for inheritance is to write subclasses. If you omit a crucial protected member, trying to write a subclass will make the omission painfully obvious. Conversely, if several subclasses are written and none uses a protected member, you should probably make it private.
Brian
Thumbs up. But you might need to think more creatively, get more diverse ideas from others. Guaranteed someone will come up with a creative case that breaks your model.... Ah, right after this they say to create at least 3 subclasses and that at least one should be authored by someone else. Yes.
25%
Flag icon
Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.
Brian
Could this be detected at compile time somehow? At least for warning purposes?
Robert
· Flag
Robert
The answer is probably technically "yes," but it's too messy to practically be so (involves code analysis well beyond the compiler's role, I think). If we really want to ensure this would never happen…
25%
Flag icon
The Cloneable and Serializable interfaces present special difficulties when designing for inheritance. It is generally not a good idea for a class designed for inheritance to implement either of these interfaces because they place a substantial burden on programmers who extend the class.
25%
Flag icon
If you do decide to implement either Cloneable or Serializable in a class that is designed for inheritance, you should be aware that because the clone and readObject methods behave a lot like constructors, a similar restriction applies: neither clone nor readObject may invoke an overridable method, directly or indirectly. In the case of readObject, the overriding method will run before the subclass’s state has been deserialized.
26%
Flag icon
When 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).
Brian
How different really is interfaces with default implementations from multiple inheritance though? No state I guess, that’s a good point.
Robert
· Flag
Robert
A type of scenario that's come to mind during the past month which seems like a great candidate for default methods are callback interfaces with multiple methods. Sometimes such interfaces have, say, …
Brian
· Flag
Brian
Yes, the pattern where there are multiple callbacks and default is noop for each makes sense. I like it a lot. I guess I could conceive of a case in which you’d have two interfaces providing the callb…
Robert
· Flag
Robert
> I guess I could conceive of a case in which you’d have two interfaces providing the callback pattern on the same class, though it seems a little contrived.

It's pretty typical to do this in Android; …
26%
Flag icon
You can, however, combine the advantages of interfaces and abstract classes by providing an abstract skeletal implementation class to go with an interface.
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.
Brian
And then discourage but don’t disallow subclassing? Doesn’t that go against earlier dictum? :)
27%
Flag icon
In Java 8, the default method construct was added [JLS 9.4], with the intent of allowing the addition of methods to existing interfaces. But adding new methods to existing interfaces is fraught with risk.
Brian
This is not good motivation to introduce default implementations though, right? Perhaps better off adding new interfaces and dealing with that pain? I’ll bet some default implantation just throw not-implemented exceptions, right?
27%
Flag icon
you should export the constants with a noninstantiable utility class (Item 4).
Brian
I guess. I’ve used constants interfaces in the past (all devs we’re working together though, so I guess likelihood of confusion was minimized by proximity) without incident.
Robert
· Flag
Robert
I think constant interfaces seems fine as long as nobody is misusing them; and it usually turns out actually fine because it's rarely misused. But I guess the case being made here is reasonable: you m…
27%
Flag icon
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:
Brian
I don’t really like this static import thing. I think it assumes everyone is using an IDE, as it hides where things are coming from. One of the things o liked about java (especially when diving into unfamiliar codebase) was how explicit everything needs to be.
Robert
· Flag
Robert
On the spectrum of when to use static imports, I think I'm somewhat closer to the end you're on (I like the clarity, too). But there are some contexts where domain awareness is reasonably expected to …
28%
Flag icon
Item 23: Prefer class hierarchies to tagged classes Occasionally you may run across a class whose instances come in two or more flavors and contain a tag field indicating the flavor of the instance.
Brian
I don’t think I’ve ever been tempted to do this.
38%
Flag icon
// Typesafe heterogeneous container pattern - implementation public class Favorites {     private Map<Class<?>, Object> favorites = new HashMap<>();     public <T> void putFavorite(Class<T> type, T instance) {         favorites.put(Objects.requireNonNull(type), instance);     }     public <T> T getFavorite(Class<T> type) {         return type.cast(favorites.get(type));     } }
Brian
Do we need to ensure that type is not null here? type.cast() seems problematic in that case? But I’m guessing casting null to any (class) type goes fine, in the case the Set doesn’t have an entry for the given type? Too lazy to test right now. :(
38%
Flag icon
The class literal List<String>.class is a syntax error, and it’s a good thing, too. List<String> and List<Integer> share a single Class object, which is List.class. It would wreak havoc with the internals of a Favorites object if the “type literals” List<String>.class and List<Integer>.class were legal and returned the same object reference. There is no entirely satisfactory workaround for this limitation.
Brian
Naive: why can’t they be different class instances? Why do genetics all need to share the same class? C++ (messily, admittedly) treats each specific template class type as a separate class.
39%
Flag icon
A Class object used in this fashion is called a type token. You can also use a custom key type. For example, you could have a DatabaseRow type representing a database row (the container), and a generic type Column<T> as its key.
Brian
What would be the various key types? Column names somehow? Or each column is a different known type for type safety, but then how do you have two columns of same type?
40%
Flag icon
Luckily, there is a better way to associate a different behavior with each enum constant: declare an abstract apply method in the enum type, and override it with a concrete method for each constant in a constant-specific class body. Such methods are known as constant-specific method implementations:
Brian
Wait you can’t do this instance-level implementation with ordinary classes, right?
Robert
· Flag
Robert
What do you mean by this? These are essentially just shorthand for subsclasses with method implementations/overrides.
41%
Flag icon
What you really want is to be forced to choose an overtime pay strategy each time you add an enum constant. Luckily, there is a nice way to achieve this. The idea is to move the overtime pay computation into a private nested enum, and to pass an instance of this strategy enum to the constructor for the PayrollDay enum. The PayrollDay enum then delegates the overtime pay calculation to the strategy enum, eliminating the need for a switch statement or constant-specific method implementation in PayrollDay.
41%
Flag icon
enum PayrollDay {     MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,     SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND);
Brian
Seems like would’ve been more instructive example not to provide a default constructor and force Strategy selection as indicated in the text. But this is clever and readable and I like it.
Robert
· Flag
Robert
Right. And more than instructive, it'd also be clearer (to a future person figuring out the code) and less error prone (forces a developer to make a decision what a new day type — e.g., Holiday — shou…
41%
Flag icon
But it also includes other sets for which you know all the possible values at compile time, such as choices on a menu, operation codes, and command line flags. It is not necessary that the set of constants in an enum type stay fixed for all time. The enum feature was specifically designed to allow for binary compatible evolution of enum types.
Brian
Recommendations for safely persisting enum types when we recognize the enum set might change over time (if we allow for only expanding and not shrinking list)? I assume there are no guarantees of value consistency across compilations? Or are there if order of declaration doesn’t change? Maybe also if new values are only appended?...
Robert
· Flag
Robert
> I assume there are no guarantees of value consistency across compilations? Or are there if order of declaration doesn’t change? Maybe also if new values are only appended?
The guarantee on the compil…
44%
Flag icon
For example, suppose you want to support a category of test that succeeds only if it throws a particular exception. The exception type is essentially a parameter of the test. You could encode the exception type name into the test method name using some elaborate naming pattern, but this would be ugly and fragile
Brian
Have used this pattern to make it clear to humans what the test is up to, but absolutely agree not to use naming introspectively to affect runtime behavior. the "test" prefix rule in some test frameworks has made me feel uneasy.
46%
Flag icon
If you know that an interface does not have default methods, you may choose to omit Override annotations on concrete implementations of interface methods to reduce clutter.
Brian
I haven’t found Overrides to be ‘clutter’ I think makes sense to always do?
Robert
· Flag
Robert
I agree. I still think you should annotate implementations of abstract and interface methods. If in the future the abstract/interface method goes away, your method is now an orphan. With the @Override…
47%
Flag icon
If you can convince yourself that you’ll never want to write a method that accepts only objects with the marking, then you’re probably better off using a marker annotation. If, additionally, the marking is part of a framework that makes heavy use of annotations, then a marker annotation is the clear choice.
Brian
I guess. I feel old and still have a bias against annotations where types can be made more explicit via interfaces. Consistency for readability and understandability is a strong argument though. No one should ever be dogmatic about anything. (SWIDT? ;) )
48%
Flag icon
Many method references refer to static methods, but there are four kinds that do not. Two of them are bound and unbound instance method references. In bound references, the receiving object is specified in the method reference. Bound references are similar in nature to static references: the function object takes the same arguments as the referenced method. In unbound references, the receiving object is specified when the function object is applied, via an additional parameter before the method’s declared parameters.
Brian
Wow, never done this but I can see where it might be tempting. Starts to result in some magick-looking code (or perhaps just ugly), if you ask me... :/ actually, the inbound case doesn’t seem too bad, unless it’s also accepting arguments in addition to the object that’s the target of the call so that the receiver and the args are all implicit args? Reminds me of the simulated OO straight C dev I did in a class where we defined a bunch of methods whose first argument was always the data struct “handling” the method call...except more hidden.
49%
Flag icon
If the source is a primitive and the result is an object reference, prefix Function with <Src>ToObj, for example DoubleToObjFunction (three variants).
49%
Flag icon
Most of the standard functional interfaces exist only to provide support for primitive types. Don’t be tempted to use basic functional interfaces with boxed primitives instead of primitive functional interfaces. While it works, it violates the advice of Item 61, “prefer primitive types to boxed primitives.” The performance consequences of using boxed primitives for bulk operations can be deadly.
49%
Flag icon
You should seriously consider writing a purpose-built functional interface in preference to using a standard one if you need a functional interface that shares one or more of the following characteristics with Comparator: • It will be commonly used and could benefit from a descriptive name. • It has a strong contract associated with it. • It would benefit from custom default methods.
49%
Flag icon
It is a statement of programmer intent that serves three purposes: it tells readers of the class and its documentation that the interface was designed to enable lambdas; it keeps you honest because the interface won’t compile unless it has exactly one abstract method; and it prevents maintainers from accidentally adding abstract methods to the interface as it evolves. Always annotate your functional interfaces with the @FunctionalInterface annotation.
Brian
If you create a functional interface, annotate it @FunctionalInterface
49%
Flag icon
The easiest way to avoid this problem is not to write overloadings that take different functional interfaces in the same argument position. This is a special case of the advice in Item 52, “use overloading judiciously.”
56%
Flag icon
each time you write a method or constructor, you should think about what restrictions exist on its parameters. You should document these restrictions and enforce them with explicit checks at the beginning of the method body. It is important to get into the habit of doing this. The modest work that it entails will be paid back with interest the first time a validity check fails.
58%
Flag icon
A safe, conservative policy is never to export two overloadings with the same number of parameters. If a method uses varargs, a conservative policy is not to overload it at all, except as described in Item 53.
72%
Flag icon
Use the Javadoc @throws tag to document each exception that a method can throw, but do not use the throws keyword on unchecked exceptions.
72%
Flag icon
One way to ensure that exceptions contain adequate failure-capture information in their detail messages is to require this information in their constructors instead of a string detail message.
73%
Flag icon
A third approach to achieving failure atomicity is to perform the operation on a temporary copy of the object and to replace the contents of the object with the temporary copy once the operation is complete.
74%
Flag icon
Better still, follow the advice in Item 59 and use the class AtomicLong, which is part of java.util.concurrent.atomic. This package provides primitives for lock-free, thread-safe programming on single variables. While volatile provides only the communication effects of synchronization, this package also provides atomicity.
74%
Flag icon
It is acceptable for one thread to modify a data object for a while and then to share it with other threads, synchronizing only the act of sharing the object reference. Other threads can then read the object without further synchronization, so long as it isn’t modified again. Such objects are said to be effectively immutable [Goetz06, 3.5.4]. Transferring such an object reference from one thread to others is called safe publication
« Prev 1 2 Next »