Monday, January 13, 2014

Effective Java 2 Review

Item 6 Eliminate obsolete object references
a single-element enum type is the best way to implement a singleton.
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. (Stack elements for example)
Another common source of memory leaks is caches.
WeakHashMap is useful only if the desired lifetime of cache
entries is determined by external references to the key, not the value. (Help to eliminate memory leaks)
WeakReferences are cleared agressively; SoftReferences are not. Using a SoftReference tells the garbage collector that you would like it to keep the object
around for a while, until memory considerations cause it to reclaim the object.
By contrast, using a WeakReference tells the garbage collector that there's no reason to keep the object around any longer than necessary.
A third common source of memory leaks is listeners and other callbacks.
The best way to
ensure that callbacks are garbage collected promptly is to store only weak references
to them, for instance, by storing them only as keys in a WeakHashMap.

Item 7: Avoid finalizers
Just provide
an explicit termination method, and require clients of the class to invoke this
method on each instance when it is no longer needed.
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.

Item 9: Always override hashCode when you override equals
You
must override hashCode in every class that overrides equals. equal objects must have equal hash codes.


To recap, all classes that implement Cloneable should override clone with a
public method whose return type is the class itself. This method should first call
super.clone and then fix any fields that need to be fixed. some
expert programmers simply choose never to override the clone method and never
to invoke it except, perhaps, to copy arrays. A fine approach to object copying is to provide a copy constructor or copy
factory.

Why wait and notify are in Object?
wait and notify are communication mechanism between two thread.
Locks are made available on per Object basis,
In Java all object has a monitor. Threads waits on monitors so, to perform a wait, we need 2 parameters:
- a Thread
- a monitor (any object)

In the Java design, the thread can not be specified, it is always the current thread running the code. However, we can specify the monitor
(which is the object we call wait on). This is a good design, because if we could make any other thread to wait on a desired monitor,
this would lead to an "intrusion", posing difficulties on designing/programming concurrent programs. Remember that in Java all operations that are
intrusive in another thread's execution are deprecated (e.g. stop()).
why wait and notify method in object because threads wait for lock and lock is implemented on Object level. its as simple as this.


make each class or member as inaccessible as
possible.
package-private—The member is accessible from any class in the package
where it is declared. Technically known as default access
protected—The member is accessible from subclasses of the class where it is
declared
Instance fields should never be public.
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.
There are two ways to fix the
problem. You can make the public array private and add a public immutable list.
Alternatively, you can make the array private and add a public method that
returns a copy of a private array:
if a class is package-private or is a private nested class, there is
nothing inherently wrong with exposing its data fields

An immutable class is simply a class whose instances cannot be modified. All of
the information contained in each instance is provided when it is created and is
fixed for the lifetime of the object. The Java platform libraries contain many
immutable classes, including String.
Immutable objects are inherently thread-safe; they require no synchronization.
The only real disadvantage of immutable classes is that they require a
separate object for each distinct value.
You
should always make small value objects, such as PhoneNumber and Complex,
immutable.(There are several classes in the Java platform libraries, such as java.util.Date and java.awt.Point, that should have been immutable but
aren’t.)
If a class cannot
be made immutable, limit its mutability as much as possible.

What are the differences between Maps returned by Collections.synchronizedMap(Map) and ConcurrentHashMap
ConcurrentHashMap does not allow null keys or values.

With generics, you tell the compiler
what types of objects are permitted in each collection. The compiler inserts casts
for you automatically and tells you at compile time if you try to insert an object of
the wrong type.

Since release
1.5, Java has provided a safe alternative known as unbounded wildcard types. If
you want to use a generic type but you don’t know or care what the actual type
parameter is, you can use a question mark instead. For example, the unbounded
wildcard type for the generic type Set<E> is Set<?> (read “set of some type”).

There are two minor exceptions to the rule that you should not use raw types
in new code, both of which stem from the fact that generic type information is
erased at runtime. You must use raw types in class literals.
In other words, List.class,
String[].class, and int.class are all legal, but List<String>.class and
List<?>.class are not. The second exception to the rule concerns the instanceof operator. Because
generic type information is erased at runtime, it is illegal to use the instanceof
operator on parameterized types other than unbounded wildcard types.
In summary, using raw types can lead to exceptions at runtime, so don’t use
them in new code.
As a quick review,
Set<Object> is a parameterized type representing a set that can contain objects of
any type, Set<?> is a wildcard type representing a set that can contain only
objects of some unknown type, and Set is a raw type, which opts out of the
generic type system. The first two are safe and the last is not.
Unbounded wildcard type List<?>
Bounded type parameter <E extends Number>
Recursive type bound <T extends Comparable<T>>
Bounded wildcard type List<? extends Number>  Iterable of some subtype of E
Collection<? super E> collection of some supertype of E
PECS stands for producer-extends, consumer-super.
Generic method static <E> List<E> asList(E[] a)

Prefer lists to arrays
Arrays differ from generic types in two important ways. First, arrays are covariant.
This scary-sounding word means simply that if Sub is a subtype of Super, then the
array type Sub[] is a subtype of Super[]. Generics, by contrast, are invariant: for
any two distinct types Type1 and Type2, List<Type1> is neither a subtype nor a
supertype of List<Type2>. You might think this
means that generics are deficient, but arguably it is arrays that are deficient.
// Fails at runtime!
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // Throws ArrayStoreException
but this one is not:
// Won't compile!
List<Object> ol = new ArrayList<Long>(); // Incompatible types
ol.add("I don't fit in");
The second major difference between arrays and generics is that arrays are
reified [JLS, 4.7]. This means that arrays know and enforce their element types at
runtime. As noted above, if you try to store a String into an array of Long, you’ll
get an ArrayStoreException. Generics, by contrast, are implemented by erasure
[JLS, 4.6]. This means that they enforce their type constraints only at compile
time and discard (or erase) their element type information at runtime. Erasure is
what allows generic types to interoperate freely with legacy code that does not use
generics
For example, it is illegal to create an array of a generic type, a parameterized
type, or a type parameter.
When you get a generic array creation error, the best solution is often to use
the collection type List<E> in preference to the array type E[].You might sacrifice
some performance or conciseness, but in exchange you get better type safety
and interoperability.

The type parameter list, which declares the type parameter, goes between the
method’s modifiers and its return type. In this example, the type parameter list
is <E> and the return type is Set<E>.
// Generic method
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<E>(s1);
result.addAll(s2);
return result;
}

Comparables are
always consumers, so you should always use Comparable<? super T> in preference
to Comparable<T>. The same is true of comparators, so you should always
use Comparator<? super T> in preference to Comparator<T>.

The Java programming language provides three kinds of throwables: checked exceptions,
runtime exceptions, and errors.
use checked exceptions for conditions from which the caller
can reasonably be expected to recover. By throwing a checked exception, you
force the caller to handle the exception in a catch clause or to propagate it outward.
There are two kinds of unchecked throwables: runtime exceptions and errors.
They are identical in their behavior: both are throwables that needn’t, and generally
shouldn’t, be caught.
If a program throws an unchecked exception or an error,
it is generally the case that recovery is impossible and continued execution would
do more harm than good. ArrayIndexOutOfBoundsException
While the Java Language Specification does not require it, there is a strong
convention that errors are reserved for use by the JVM to indicate resource deficiencies,
invariant failures, or other conditions that make it impossible to continue
execution. Given the almost universal acceptance of this convention, it’s best not
to implement any new Error subclasses. Therefore, all of the unchecked throwables
you implement should subclass RuntimeException (directly or indirectly).

Not only does synchronization
prevent a thread from observing an object in an inconsistent state, but it
ensures that each thread entering a synchronized method or block sees the effects
of all previous modifications that were guarded by the same lock.
The consequences of failing to synchronize access to shared mutable data can
be dire even if the data is atomically readable and writable.


No comments:

Post a Comment