Great book written again by Great Developer.
Though every item is important but i wanted to share few important quotations i found from this book.
1) One advantage of static factory methods is that, unlike constructors, they have names.
2) A second advantage of static factory methods is that, unlike constructors, they are not required to create a new object each time they’re invoked.This allows immutable classes (Item 15) to use preconstructed instances, or to cache instances as they’re constructed, and dispense them repeatedly to avoid creating
unnecessary duplicate objects. The Boolean.valueOf(boolean) method illustrates this technique: it never creates an object. This technique is similar to the Flyweight pattern
3) A third advantage of static factory methods is that, unlike constructors,they can return an object of any subtype of their return type.
4) Fourth advantage of static factory methods is that they reduce the verbosity of creating parameterized type instances.
5) The main disadvantage of providing only static factory methods is that classes without public or protected constructors cannot be subclassed.
A second disadvantage of static factory methods is that they are not readily distinguishable from other static methods.
Here are some common names for static factory methods:
• valueOf—Returns an instance that has, loosely speaking, the same value as its parameters. Such static factories are effectively type-conversion methods.
• of—A concise alternative to valueOf, popularized by EnumSet (Item 32).
• getInstance—Returns an instance that is described by the parameters but cannot be said to have the same value. In the case of a singleton, getInstance takes no parameters and returns the sole instance.
• newInstance—Like getInstance, except that newInstance guarantees that each instance returned is distinct from all others.
• getType—Like getInstance, but used when the factory method is in a different class. Type indicates the type of object returned by the factory method.
• newType—Like newInstance, but used when the factory method is in a different class. Type indicates the type of object returned by the factory method.
6) Static factories and constructors share a limitation: they do not scale well to large numbers of optional parameters.Luckily, there is an alternative that combines the safety of the telescoping constructor pattern with the readability of the JavaBeans pattern. It is a form of the Builder pattern. Instead of making the desired object directly,the client calls a constructor (or static factory) with all of the required parameters and gets a builder object.
//Builder Pattern
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public Builder carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; return this; }
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
Note that NutritionFacts is immutable, and that all parameter default values are in a single location. The builder’s setter methods return the builder itself so that invocations can be chained. Here’s how the client code looks:
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).sodium(35).carbohydrate(27).build();
7) There’s a new way to create unnecessary objects in release 1.5. It is called autoboxing, and it allows the programmer to mix primitive and boxed primitive types, boxing and unboxing automatically as needed.
Always,prefer primitives to boxed primitives, and watch out for unintentional autoboxing.
8) An obsolete reference is simply a reference that will never be dereferenced again.
9) Finalizers are unpredictable, often dangerous, and generally unnecessary.
10) One kind of value class that does not require the equals method to be overridden is a class that uses instance control to ensure that at most one object exists with each value. Enum types fall into this category. For these classes, logical equality is the same as object identity, so Object’s equals method functions as a logical equals method.
When you override the equals method, you must adhere to its general contract.
Here is the contract, copied from the specification for Object [JavaSE6]:
The equals method implements an equivalence relation. It is:
• Reflexive: For any non-null reference value x, x.equals(x) must return true.
• Symmetric: For any non-null reference values x and y, x.equals(y) must return true if and only if y.equals(x) returns true.
• Transitive: For any non-null reference values x, y, z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) must return true.
• Consistent: For any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
11) The Liskov substitution principle says that any important property of a type should also hold for its subtypes, so that any method written for the type should work equally well on its subtypes
12) Many classes in the Java platform libraries, such as String, Integer, and Date, include in their specifications the exact value returned by their hashCode method as a function of the instance value. This is generally not a good idea, as it severely limits your ability to improve the hash function in future releases. If you leave the details of a hash function unspecified and a flaw is found or a better hash
function discovered, you can change the hash function in a subsequent release,confident that no clients depend on the exact values returned by the hash function.
13) Equality test imposed by the compareTo method should generally return the same results as the equals method. If this provision is obeyed, the ordering imposed by the compareTo method is said to be consistent with equals. If it’s violated, the ordering is said to be inconsistent with equals. A class whose compareTo method imposes an order that is inconsistent with equals will still work, but sorted collections containing elements of the class may not obey the general contract of the appropriate collection interfaces (Collection, Set, or Map). This is because the general contracts for these interfaces are defined in terms of the equals method, but sorted collections use the equality test imposed by compareTo in place of equals.
For example, consider the BigDecimal class, whose compareTo method is inconsistent with equals. If you create a HashSet instance and add new BigDecimal("1.0") and new BigDecimal("1.00"), the set will contain two elements because the two BigDecimal instances added to the set are unequal when compared using the equals method. If, however, you perform the same procedure using a TreeSet instead of a HashSet, the set will contain only one element because the two BigDecimal instances are equal when compared using the compareTo method. (See the BigDecimal documentation for details.)
14) Immutable objects are inherently thread-safe; they require no synchronization.
15) Interfaces are ideal for defining mixins. Loosely speaking, a mixin is a type that a class can implement in addition to its “primary type” to declare that it provides some optional behavior. For example, Comparable is a mixin interface that allows a class to declare that its instances are ordered with respect to other mutually comparable objects. Such an interface is called a mixin because it allows the optional functionality to be “mixed in” to the type’s primary functionality.Abstract classes can’t be used to define mixins for the same reason that they can’t be retrofitted onto existing classes: a class cannot have more than one parent, and there is no reasonable place in the class hierarchy to insert a mixin.
Interfaces should be used only to define types. They should not be used to export constants.
16) You must use raw types in class literals. The specification does not permit the use of parameterized types (though it does permit array types and primitive types) [JLS, 15.8.2]. In other words, List.class,String[].class, and int.class are all legal, but List
17) 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. The use of unbounded wildcard types in place of raw types does not affect the behavior of the instanceof operator in any way. In this case, the angle brackets and question marks are just noise. This is the preferred way to use the instanceof operator with generic types.
18) For quick reference generic terms often used are
<table border=1 align=center>
<tr><th>Term<th>Example</tr>
<tr><td>Parameterized type<td>List<String></tr>
<tr><td>Actual type parameter<td>String</tr>
<tr><td>Generic type<td>List<E></tr>
<tr><td>Formal type parameter<td>E</tr>
<tr><td>Unbounded wildcard type<td>List<?></tr>
<tr><td>Raw type<td>List</tr>
<tr><td>Bounded type parameter<td><E extends Number></tr>
<tr><td>Recursive type bound<td><T extends Comparable<T>></tr>
<tr><td>Bounded wildcard type<td>List<? extends Number></tr>
<tr><td>Generic method<td>static <E> List<E> asList(E[] a)</tr>
<tr><td>Type token<td>String.class</tr>
</table>
19) 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
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.
20) Because of these fundamental differences, arrays and generics do not mix well. For example, it is illegal to create an array of a generic type, a parameterized type, or a type parameter. None of these array creation expressions are legal: new List
Why is it illegal to create a generic array? Because it isn’t typesafe. If it were legal, casts generated by the compiler in an otherwise correct program could fail at runtime with a ClassCastException. This would violate the fundamental guarantee provided by the generic type system.
21) To make this more concrete, consider the following code fragment:
// Why generic array creation is illegal - won't compile!
List<String>[] stringLists = new List<String>[1]; // (1)
List<Integer> intList = Arrays.asList(42); // (2)
Object[] objects = stringLists; // (3)
objects[0] = intList; // (4)
String s = stringLists[0].get(0); // (5)
Let’s pretend that line 1, which creates a generic array, is legal. Line 2 creates and initializes a List
Types such as E, List
22) In summary, arrays and generics have very different type rules. Arrays are covariant and reified; generics are invariant and erased.
23)
Parameterized types are invariant. In other words, for any two distinct types Type1 and Type2, List<Type1> is neither a subtype nor a supertype of List<Type2>. While it is counterintuitive that List<String> is not a subtype of List<Object>, it really does make sense. You can put any object into a
List<Object>, but you can put only strings into a List<String>.
24) For maximum flexibility, use wildcard types on input parameters that represent producers or consumers.If an input parameter is both a producer and a consumer, then wildcard types will do you no good: you
need an exact type match, which is what you get without any wildcards.
PECS stands for producer-extends, consumer-super.
In other words, if a parameterized type represents a T producer, use ;if it represents a T consumer, use . In our Stack example, pushAll’s src parameter produces E instances for use by the Stack, so the appropriate type for src is Iterable; popAll’s dst parameter consumes E instances
from the Stack, so the appropriate type for dst is Collection. The PECS mnemonic captures the fundamental principle that guides the use of wildcard types. Naftalin and Wadler call it the Get and Put Principle [Naftalin07, 2.4].
25) Do not use wildcard types as return types.
26) If a type parameter appears only once in a method declaration, replace it with a wildcard.
27) When a class literal is passed among methods to communicate both compile-time and runtime type information, it is called a type token [Bracha04].
28) To associate data with enum constants, declare instance fields and write a constructor that takes the data and stores it in the fields.
29) Selection among overloaded methods is static, while selection among overridden methods is dynamic.
A safe, conservative policy is never to export two overloadings with the same number of parameters.
30) While the Java platform libraries largely adhere to the spirit of the advice in this item, there are a number of classes that violate it. For example, the String class exports two overloaded static factory methods, valueOf(char[]) and valueOf(Object), that do completely different things when passed the same object reference. There is no real justification for this, and it should be regarded as an anomaly with the potential for real confusion.
31) Nearly every local variable declaration should contain an initializer.
32) Unfortunately, there are three common situations where you can’t use a for-each loop:
a. Filtering—If you need to traverse a collection and remove selected elements,then you need to use an explicit iterator so that you can call its remove method.
b. Transforming—If you need to traverse a list or array and replace some or all of the values of its elements, then you need the list iterator or array index in order to set the value of an element.
c. Parallel iteration—If you need to traverse multiple collections in parallel,then you need explicit control over the iterator or index variable, so that all iterators or index variables can be advanced in lockstep (as demonstrated unintentionally in the buggy card and dice examples above).
33) Don’t use float or double for any calculations that require an exact answer.Use BigDecimal if you want the system to keep track of the decimal point and you don’t mind the inconvenience and cost of not using a primitive type.
34) Applying the == operator to boxed primitives is almost always wrong.
35) So when should you use boxed primitives? They have several legitimate uses.The first is as elements, keys, and values in collections. You can’t put primitives in collections, so you’re forced to use boxed primitives.
36) Avoid strings where other types are more appropriate
a) Strings are poor substitutes for other value types.
b) Strings are poor substitutes for enum types.
c) Strings are poor substitutes for aggregate types.
// Inappropriate use of string as aggregate type
String compoundKey = className + "#" + i.next();
This approach has many disadvantages. If the character used to separate fields occurs in one of the fields, chaos may result. To access individual fields, you have to parse the string, which is slow, tedious, and error-prone. You can’t provide equals, toString, or compareTo methods but are forced to accept the behavior
that String provides. A better approach is simply to write a class to represent the aggregate, often a private static member class.
37) Use checked exceptions for conditions from which the caller can reasonably be expected to recover.
38) This table summarizes the most commonly reused exceptions
| Exception | Occasion for Use |
|---|---|
| IllegalArgumentException | Non-null parameter value is inappropriate |
| IllegalStateException | Object state is inappropriate for method invocation |
| NullPointerException | Parameter value is null where prohibited |
| IndexOutOfBoundsException | Index parameter value is out of range |
| ConcurrentModificationException | Concurrent modification of an object has been detected where it is prohibited |
| UnsupportedOperationException | Object does not support method |
39) Always declare checked exceptions individually, and document precisely the conditions under which each one is thrown using the Javadoc @throws tag.
40) A failed method invocation should leave the object in the state that it was in prior to the invocation. A method with this property is said to be failure atomic.
41) The language specification guarantees that reading or writing a variable is atomic unless the variable is of type long or double [JLS, 17.4.7]. In other words,reading a variable other than a long or double is guaranteed to return a value that was stored into that variable by some thread, even if multiple threads modify the variable concurrently and without synchronization.
42) Synchronization is required for reliable communication between threads as well as for mutual exclusion. This is due to a part of the language specification known as the memory model, which specifies when and how changes made by one thread become visible to others [JLS, 17, Goetz06 16].
43) The libraries provide the Thread.stop method,but this method was deprecated long ago because it is inherently unsafe—its use can result in data corruption. Do not use Thread.stop. A recommended way to stop one thread from another is to have the first thread poll a boolean field that is initially false but can be set to true by the second thread to indicate that the first thread is to stop itself. Because reading and writing a boolean field is atomic,some programmers dispense with synchronization when accessing the field:
//Broken! - How long would you expect this program to run?
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args)
throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested)
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
You might expect this program to run for about a second, after which the main thread sets stopRequested to true, causing the background thread’s loop to terminate. However, the program never terminates: the background thread loops forever!
The problem is that in the absence of synchronization, there is no guarantee as to when, if ever, the background thread will see the change in the value of stop-Requested that was made by the main thread. In the absence of synchronization,it’s quite acceptable for the virtual machine to transform this code:
while (!done)
i++;
into this code:
if (!done)
while (true)
i++;
This optimization is known as hoisting, and it is precisely what the HotSpot server VM does. The result is a liveness failure: the program fails to make progress. One way to fix the problem is to synchronize access to the stopRequested field. This program terminates in about one second, as expected:
//Properly synchronized cooperative thread termination
public class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop() {
stopRequested = true;
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
public static void main(String[] args)
throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested())
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
44) The volatile modifier performs no mutual exclusion, it guarantees that any thread that reads the field will see the most recently written value:
45) To avoid deadlock and data corruption, never call an alien method from within a synchronized region. More generally, try to limit the amount of work that you do from within synchronized regions. When you are designing a mutable class, think about whether it should do its own synchronization. In the modern multicore era, it is more important than ever not to synchronize excessively.Synchronize your class internally only if there is a good reason to do so,and document your decision clearly.
46) Unless you have a compelling reason to do otherwise, use ConcurrentHashMap in preference to Collections.synchronizedMap or Hashtable.
47) For interval timing, always use System.nanoTime in preference to System.currentTime-Millis. System.nanoTime is both more accurate and more precise, and it is not affected by adjustments to the system’s real-time clock.
48) Use lazy initialization judiciously.If you need to use lazy initialization for performance on a static field, use the lazy initialization holder class idiom.
49) Any program that relies on the thread scheduler for correctness or performance is likely to be nonportable.
50) The main technique for keeping the number of runnable threads down is to have each thread do some useful work and then wait for more. Threads should not run if they aren’t doing useful work. In terms of the Executor Framework (Item 68), this means sizing your thread pools appropriately [Goetz06 8.2], and keeping tasks reasonably small and independent of one another. Tasks shouldn’t be too small, or dispatching overhead will harm performance.
51) Thread groups are obsolete.Hence avoid them.
52) Inner classes (Item 22) should not implement Serializable. They use compiler-generated synthetic fields to store references to enclosing instances and to store values of local variables from enclosing scopes. How these fields correspond to the class definition is unspecified, as are the names of anonymous and local classes. Therefore, the default serialized form of an inner class is illdefined.A static member class can, however, implement Serializable.
53) To associate data with enum constants, declare instance fields and write a constructor that takes the data and stores it in the fields.
Hope you enjoy reading the book.
About the Author
Joshua Bloch is a Senior Staff Engineer at Sun Microsystems, Inc., where he is an architect in the Core Java Platform Group. He designed, implemented, and maintained many parts of the Java platform, including the award-winning Java Collections Framework, the assert construct, and the java.math package. He led the JCP expert groups for Assertions (JSR-14), Preferences (JSR-10), and Metadata (JSR-175). Previously he was a Senior Systems Designer at Transarc Corporation, where he designed and implemented many parts of the Encina distributed transaction processing system.
In addition to Effective Java Programming Language Guide, Bloch wrote chapters in The Java Tutorial Continued and Camelot and Avalon - A Distributed Transaction Facility. He has also written a handful of technical papers.
He holds a B.S. from Columbia University and a Ph.D. from Carnegie-Mellon University. His Ph.D. thesis on the replication of abstract data objects was nominated for the ACM Distinguished Dissertation Award.
No comments:
Post a Comment