Notes of “Effective Java” (Chapter 1-6)

Item 1: Consider static factory methods instead of constructors

advantage:

  1. Customized meaningful names better than constructors.
  2. Associated with class instead of creating new objects.
  3. Able to return subtypes.

For the 2nd advantage, static factory methods form the basis of Service provider Framework including service interface, provider interface, provider registration API and service access API.

Item 2: Consider a builder when faced with many constructor parameters

Compare with telescoping constructors and JavaBean Style.

Builder is set as a static inner class. Builder makes the object initialized immutable.


Item 3: Enforce the singleton property with a private constructor or an enum type

Three ways to implement Singleton patter:

  • Public field
  • Static factory method
  • Enum Singleton

Without Enum, readResovle() function needs to be added to avoid creating spurious instances when doing serialization.

Item 4: Enforce noninstantiability with a private constructor

Some utility classes like java.lang.Math or java.util.Arrays are not designed to be instantiated. For preventing them from instantiation and subclassing, make the constructor to be private.

Item 5: Avoid creating unnecessary objects

Creating new object especially heavy objects is expensive. Therefore, reusing object always increases efficiency.

Example: String appending, Boxed primitives.

Item 6: Eliminate obsolete object references

Although Java has garbage collector, memory leak can still happen. GC reclaims the memory by inspecting the references of objects.

Therefore, we need to null out the obsolete object references to release the unused object memory.

Common memory leak scenarios: Objects constructed inside classes, Cache, Callbacks.

Notice the Weak references and weakHashmap.

Item 7: Avoid finalizers

In summary, don’t use finalizers except as a safety net or to terminate noncritical native resources. In those rare instances where you do use a finalizer, remember to invoke super.finalize.

Explicit termination inside a “try finally” is preferable and reliable.

Item 8: Obey the general contract when overriding equals

Conditions do not need overriding equals():

  1. Instances are distinguished by reference.
  2. Equals() defined in superclass works.
  3. You do not care the equals() function.

Contract when overriding equals():

Reflexive, Symmetric, Transitive, Consistent.

There is no perfect way to override equals() between the subclasses with additional value components and superclasses.

Notice the @Override annotation.

Item 9: Always override hashCode when you override equals

Principle: equal objects according the equals() function must produce the same hashcode.

General recipe for hashCode():

result = 31 * result + c;

  • boolean: (f?1:0).
  •  byte, char, short, or int: (int) f
  • long: (int) (f ^ (f >>> 32))
  • float: Float.floatToIntBits(f)
  • double: Double.doubleToLongBits(f)
  •  null: 0

Note we could lazily initialize the hashCode value.

Item 10: Always override toString

Faciliate the class client user by giving useful information in string.

Item 11: Override clone judiciously

Once one class implements the Cloneable interface and overrides the clone() method, invoking super.clone() will return a field-to-field copy of this class object in which the method is called. If a class contains only primitive fields or references to immutable objects, then it is usually the case that no fields in the object returned by super.clone need to be modified. Otherwise, deep copy is needed.

Be careful to use clone except for arrays. Usually it is better to use copy constructor and copy factory method.

  • public Yum(Yum yum);
  • public static Yum newInstance(Yum yum);

Item 12: Consider implementing Comparable

public interface Comparable<T> {
int compareTo(T t);
}

Classes that depend on comparison include the sorted collections TreeSet and TreeMap, and the utility classes Collections and Arrays, which contain searching and sorting algorithms. General interfaces like Set, Map, and Collection depend on equals() method.

Principle:

If the most significant fields are equal, go on to compare the next-most-significant fields, and so on. If all fields are equal, the objects are equal; return zero.

Item 13: Minimize the accessibility of classes and members

The rule of thumb is simple: make each class or member as inaccessible as possible.

Exported API: public, protected.

If a method overrides a superclass method, it is not permitted to have a lower access level in the subclass than it does in the superclass. This is necessary to ensure that an instance of the subclass is usable anywhere that an instance of the superclass is usable.  A special case of this rule is that if a class implements an interface, all of the class methods that are also present in the interface must be declared public. This is so because all members of an interface are implicitly public.

  • Instance fields should never be public
  • Classes with public mutable fields are not thread-safe
  • Public static final fields should be only used for constants

Item 14: In public classes, use accessor methods, not public fields

Class is package-private or is a private nested class, there is nothing inherently wrong with exposing its data fields.

Item 15: Minimize mutability

  1. Make the immutable class to be final.
  2. Immutable objects are inherently thread-safe; they require no synchroni-zation.
  3. Use companion class such as StringBuilder replacing String for performance.
  4. Static factory is a good way for immutable class.
  5. Classes should be immutable unless there’s a very good reason to make them mutable.
  6. Make every field final unless there is a compelling reason to make it nonfinal.
  7. Don’t provide a public initialization method separate from the constructor or static factory unless there is a compelling reason to do so.

Item 16: Favor composition over inheritance

For most cases, composition is better than inheritance.

The keyword “super” is for calling overrided methods or constructors in superclass. The invocation in super.method() still calls the override methods but not overriden methods.

Item 17: Design and document for inheritance or else prohibit it

  • The class must document or simply prohibit its  self-use of overridable methods.
  • Constructors must not invoke overridable methods.
  • Neither clone() nor readObject() may invoke an overridable method, directly or indirectly, as they behave like constructors.
  • Prohibit subclassing in classes that are not designed and documented to be safely subclassed by “final” or making the constructor “private”.

Item 18: Prefer interfaces to abstract classes

Interface is generally the better way to define a type that permits multiple implementations.

Abstract class and Interface can be combined to generate skeletal implementation, such as AbstractCollection, AbstractSet, AbstractList.

Item 19: Use interfaces only to define types

Interfaces should only used to define type, representing some classes in hierarchy.

Enum and Utility class are more appropriate for defining constants.

Item 20: Prefer class hierarchies to tagged classes

Tagged classes are cluttered with tag fields, and switch statements, messing the encapsulation and  being prone to run-time errors.

Tagged class should be abandoned and replaced by abstract classes.

Item 21: Use function objects to represent strategies

Features like function pointers, delegates, lambda expressions call functions in functions.

Strategy pattern is built on these features typically on function pointers.

Function pointers is not supported in java. However, it can be emulated by a concrete class with only one method, as a “concrete strategy class”.

  • Strategy ==> Interface
  • Concrete strategy ==> Concrete class implementing the interface

Usually the concrete class is used as anonymous class. For class used repeatedly, singleton pattern is applied to the concrete class with one static and final instance.

Item 22: Favor static member classes over nonstatic

Four kinds of nested classes: static member classes, nonstatic member classes, anonymous classes, and local classes.

It is impossible to create an instance of a nonstatic member class without an enclosing instance.

Declare a member class that does not require access to an enclosing instance, always make it to be static.

Three common uses of anonymous classes:

  1. function objects
  2. process objects, such asRunnable, Thread
  3. static factory methods

Item 23: Don’t use raw types in new code

  • Do not use raw type to define variable, as the compiler will not check the type of parameters and it loses the type safety and may generate run-time error.
  • Generics like List<Object> can contain any arbitrary types but still with type safety.
  • Unbounded wildcard types like List<?> is capable to hold one of any type of element with type safety.
  • Generic type information is erased at runtime

Item 24: Eliminate unchecked warnings

Try to eliminate the unchecked warning, including:

  • unchecked cast warnings
  • unchecked method invocation warnings
  • unchecked generic array creation warnings
  • unchecked conversion warnings

Suppress the warning with an @SuppressWarnings(“unchecked”) annotation in narrowest scope if you are sure about the type safety.

Item 25: Prefer lists to arrays

Arrays are covariant and reifiable. Generics are invariant and erased in run-time.

Arrays provide runtime type safety but not compile-time type safety and vice versa for generics.

// Fails at runtime!
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // Throws ArrayStoreException
// Won't compile!
List<Object> ol = new ArrayList<Long>(); // Incompatible types
ol.add("I don't fit in");

Generics enforce their type constraints only at compile time and discard (or erase) their element type information at runtime.

it is illegal to create an array of a generic type such as “new List<String>[]” and “new List<E>[]”.

Non-reifiable type is one whose runtime representation contains less information than its compile-time representa-tion.

Casts to arrays of non-reifiable types should be used only under special circumstances. A better solution is to use list.

Item 26: Favor generic types

Generics are safer. Suppress the warning when casting.

@SuppressWarnings("unchecked")
public Stack() {
elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}

Item 27: Favor generic methods

Generic singleton factory:

// Generic singleton factory pattern
private static UnaryFunction<Object> IDENTITY_FUNCTION =
new UnaryFunction<Object>()
{
public Object apply(Object arg) { return arg; }
};
// IDENTITY_FUNCTION is stateless and its type parameter is
// unbounded so it's safe to share one instance across all types.
@SuppressWarnings("unchecked")
public static <T> UnaryFunction<T> identityFunction() {
return (UnaryFunction<T>) IDENTITY_FUNCTION;
}

Recursive type bound is usually used for Comparable<T>.

public interface Comparable<T>; {
int compareTo(T o);
}
// Using a recursive type bound to express mutual comparability
public static <T extends Comparable<T>> T max(List<T> list) {...}

Item 28: Use bounded wildcards to increase API flexibility

Producer-extends, consumer-super(PECS)

// Wildcard type for parameter that serves as an E producer
public void pushAll(Iterable<? extends E> src) {
for (E e : src)
push(e);
}
// Wildcard type for parameter that serves as an E consumer
public void popAll(Collection<? super E> dst) {
while (!isEmpty())
dst.add(pop());
}

Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code.

Always use Comparable<? super T> in preference to Comparable<T>, since the type may implements the Comparable interface as an subinterface.

If a type parameter appears only once in a method declaration, replace it with a wildcard.

Can’t put any value except null into a List<?>, which means List of some particular type.

Item 29: Consider typesafe heterogeneous containers

Place the type parameter on the key rather than the container to enable the container to include different types.

// Typesafe heterogeneous container pattern - implementation
public class Favorites {
private Map<Class<?>, Object> favorites =
new HashMap<Class<?>, Object>();
public <T> void putFavorite(Class<T> type, T instance) {
if (type == null)
throw new NullPointerException("Type is null");
favorites.put(type, instance);
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}

Item 30: Use enums instead of int constants

Java’s enum types are full-fledged classes.

Enums provide high-quality implementations of all the Object methods, Comparable and Serializable.

Enums can also add methods or fields.

// Enum type with constant-specific method implementations
public enum Operation {
PLUS { double apply(double x, double y){return x + y;} },
MINUS { double apply(double x, double y){return x - y;} },
TIMES { double apply(double x, double y){return x * y;} },
DIVIDE { double apply(double x, double y){return x / y;} };
abstract double apply(double x, double y);
}

ValueOf(String) method can translate a constant’s name into the constant itself.

Consider the strategy enum pattern if multiple enum constants share common behaviors.

Item 31: Use instance fields instead of ordinals

Avoid using ordinal() method of enum.

// Abuse of ordinal to derive an associated value - DON'T DO THIS
public enum Ensemble {
SOLO, DUET, TRIO, QUARTET, QUINTET,
SEXTET, SEPTET, OCTET, NONET, DECTET;
public int numberOfMusicians() { return ordinal() + 1; }
}

Item 32: Use EnumSet instead of bit fields

Use general Set interface for input type.

// EnumSet - a modern replacement for bit fields
public class Text {
public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
// Any Set could be passed in, but EnumSet is clearly best
public void applyStyles(Set<Style> styles) { ... }
}

Item 33: Use EnumMap instead of ordinal indexing

It is better to use EnumMap to catalog relationship related with Enum type.

// Using an EnumMap to associate data with an enum
Map<Herb.Type, Set<Herb>> herbsByType =
new EnumMap<Herb.Type, Set<Herb>>(Herb.Type.class);
for (Herb.Type t : Herb.Type.values())
herbsByType.put(t, new HashSet<Herb>());
for (Herb h : garden)
herbsByType.get(h.type).add(h);
System.out.println(herbsByType);

Item 34: Emulate extensible enums with interfaces

In general, extending enums is a bad idea. If you really want to do that, define an interface for expected behaviors.

Item 35: Prefer annotations to naming patterns

Annotations do not directly affect program semantics, but they do affect the way programs are treated by tools and libraries, which can in turn affect the semantics of the running program. Annotations can be read from source files, class files, or reflectively at run time.

Annotations complement javadoc tags. In general, if the markup is intended to affect or produce documentation, it should probably be a javadoc tag; otherwise, it should be an annotation.

Item 36: Consistently use the Override annotation

Use @Override annotation except for the abstract methods or methods of interfaces.


Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s