Sunday, November 2, 2008

Review of Effective Java 2nd Edition

I have read Effective Java 2nd Edition recently. It contains 78 "items" where Joshua Bloch depicts usage of Java language the right way. All in all, I liked this book very much. Especially the chapters 2, 4 and 8 were most valuable to me. Except some introductory "items", whole book is a set of interesting articles similar to a blog.

Next I'll write down a summary of the most items of this book. I use bold font when I found an item important and italic font when I found it surprising.

Chapter 2 - Creating and Destroying Objects

The interesting stuff starts here.
Item 1 introduces you to the static factory methods and their advantages and disadvantages over constructors (boring).
Item 2 is much more useful - it introduces the "Builder pattern" as the best method to initialize objects. More widespread term is IMO the "Fluent Interfaces".
Item 3 shows us how to implement a singleton the right way - through a single-element enum (remember that enum can have methods).
Item 4 is about achieving noninstantiability of classes - through private constructor.
Item 5 is about optimizing code by using primitive types, not using Calendar and not being stupid when instantiating Strings.
Item 6 is about memory optimization through being aware of memory leaks when you program a class that manages its own memory.
Item 7 has a descriptive name - avoid finalizers.

Chapter 3 - Methods Common to All Objects

This chapter is about methods of java.lang.Object. Items 8, 9 and 11 are about overriding equals, hashCode and clone. In one word - it is hard. If I must do it, I rather use reflection-driven library from Apache Commons Lang. I found Item 10 interesting, because it encourages everyone to always override toString to improve user-friendliness of you class. I agree and I use Apache Commons Lang to do the job for me. Item 12 is about implementing Comparable, which is obviously similar to implementing equals.

Chapter 4 - Classes and Interfaces

Item 13 - Minimize accessibility of classes and members. In other words, "worship encapsulation".
Item 14 - Don't use public fields in public classes. IMO use static code analysis and soon you'll write every field of every class private...
Item 15 is much more interesting - it is called Minimize mutability. This is very good in multithreaded applications. More on this item can be found here.
Item 16 - Favor composition over inheritance. It is well known practice in the blogs but I've never seen this done in practice.
Item 17 is about pitfalls of enabling inheritance of your class. I didn't read it because I have never had to design a class for future inheritance.
Item 18 - name of this item is IMO bad, so I won't write it. It tells us to use interfaces (not concrete classes, not even abstract classes) as types of objects. Reasons are obvious.
Item 19 - Don't use interfaces just to export constants.
Item 20 - Don't use tagged classes. Tagged classes are classes with a 'tag' field which defines what the class really is. You will see many switches in tagged classes over this tag field. Use class hierarchy instead. This principle is IMO just a special case of not using switches. Switches stink. Use class hierarchies instead if appropriate.
Item 21 - What is Java way for function pointers? Right - the strategy pattern. You define the one-method interface. Then you pass its implementation instance as a parameter. If you need the implementation just once, use anonymous class. Otherwise use public static inner classes.
Item 22 - Favor static inner classes over nonstatic. I don't use inner classes so I didn't read this item.

Chapter 5 - Generics

Most of this chapter is just introductory material. It is probably so becouse there were no generics in the first edition of the book.
Item 23 - Don't use raw types in new code.
Item 24 - Eliminate unchecked warnings. Do it by following the item 23.
Item 25 - Prefer lists to arrays.
Item 26 - Favor generic types.
Item 27 - Favor generic methods.
Item 28 - This is IMO the only useful item in this chapter. Use bounded wildcards to increase API flexibility. For producers use extends, for consumers use super.

Chapter 6 - Enums and Annotations

Item 30 - Favor enums to integer and string constants.
Item 31 - Don't use ordinal value of an enum. Use instance fields instead.
Item 32 - Use EnumSet instead of bit fields.
Item 33 - Don't use ordinals to index arrays. Use EnumMap instead.
Item 34 is about simulating extensible enum types with interfaces.
Item 35 - Favor annotations over naming patterns.
Item 36 - Use @Override.
Item 37 encourages us to use marker interfaces (like Serializable) to define types. Annotation is not appropriate here, because it does not define a type.

Chapter 7 - Methods

Item 38 - Check your method parameters for validity.
Item 39 - Make defensive copies of mutable objects passed to you or from you as a class if you cannot trust your client (or you can afford the performance penalty).
Item 40 - Choose method names carefully. Avoid long parameter lists. Prefer two-element enum types over boolean parameters.
Item 41 - If you must overload a method, the overloaded method should have its unique number of parameters.
Item 42 - Use varargs for printf-like methods only.
Item 43 - Return emtpy collections instead of nulls.
Item 44 - Document your exposed API (using Javadoc).

Chapter 8 - General Programming

Item 45 - Minimize the scope of the local variables.
Item 46 - Prefer for-each loops to traditional for loops.
Item 47 - Don't reinvent the wheel. Reuse other programmers' code.
Item 48 - Don't use float or double where exact results are needed. It can miss the result by something like 0.00000000001, which is annoying. Use long or BigDecimal instead.
Item 49 - Favor primitive types to boxed primitives.
Item 50 - Don't overuse strings, where other types are more appropriate (a number, boolean, a complex class, ...).
Item 51 - Use StringBuilder instead of string concatenation.
Item 52 - Refer to objects by their interfaces instead of concrete classes.
Item 53 - You should use reflection only if you need to instantiate classes not available to you at compile time.
Item 54 - Be careful when using native methods. I don't use them so I didn't read this item.
Item 55 - Any pre-mature optimization is evil! This is one of the most important items in this book. If you absolutely must optimize (either for performance or the memory), measure the performance gains.
Item 56 - Use generally accepted naming conventions of Java.

Chapter 9 - Exceptions

Item 57 - use exceptions only for exceptional conditions. Never use them for program flow control.
Item 58 - Use checked exceptions for recoverable conditions and runtime exceptions for programming errors.
Item 59 - Use checked exception only for recoverable conditions.
Item 60 - Reuse exception already in the Java programming language.
Item 61 - Use exception translation from lower levels of your design to higher levels. But don't over-use it, sometimes is better if lower levels don't throw any exception at all.
Item 62 - Document your exceptions.
Item 63 - Your exceptions should output meaningful messages with all values participating on exception displayed.
Item 64 - You should implement failure atomicity of methods that throw exceptions. All these methods should leave the object in consistent state.
Item 65 - Don't use empty catch blocks. You shouldn't ignore exceptions.

Chapter 10 - Concurrency

Mr Bloch designed the java.util.concurrency, so approximately half of the items here introduce new features of it.
Item 66 - When more threads use same mutable data, reads and writes must be synchronized.
Item 67 - Don't over-synchronize. Do as little in the synchronized block as possible.
Item 68 - Prefer new executors and tasks from java.util.concurrent to threads.
Item 69 - wait and notify have almost no use these days. Use concurrent collections and synchronizers from new java.util.concurrent.
Item 70 - you have to clearly document how concurrent your class is.
Item 71 is interesting - it is about lazy initialization. The advice here is not to use it if you don't have to. It is just a performance optimization. If you must do it, use double-check idiom to avoid double initialization in multithreaded environments.
Item 72 contains two advices - threads should not run if they aren't doing useful work and don't use Thread.yield. The key point here is to be less dependent on thread sheduler and therefore provide more portability.
Item 73 in one sentence - don't use thread groups, they are obsolete.

Chapter 11 - Serialization

Whole chapter is about serialization. I have never needed it, so I didn't read this chapter and I find it rather useless.

No comments: