Bloch 8

advertisement
Effective Java:
General Programming
Spring 2013
Agenda

Material From Joshua Bloch


Cover Items 45-56


“General Programming” Chapter
Bottom Line:



2
Effective Java 2nd Edition
Nuts and bolts of the Java language
Treatment of two extralinguistic language
facilities
Optimization and naming conventions
General Programming
Item 45: Minimize the Scope of
Local Variables


Similar to Item 13: “Minimize the accessibility of classes and
members”
Some older languages (eg C) require declarations at the beginning
of a block


A habit worth breaking
Important Case: Prefer for loops to while loops
// Preferred idiom for iterating over a collection
for (Element e : C) {
doSomething(e);
// Note the lack (of an
explicit) cast
}
3
// No for-each loop or generics before release 1.5
for (Iterator i = c.iterator(); i.hasNext(); ) {
doSomething( (Element) i.next());
// Note the
cast
General Programming
}
More Item 45: Problems with
while Loops

Sample problem with while loops

Problem disappears with local declarations in a for loop
// Spot the bug?
Iterator<Element> i = c.iterator(); BUG!
while (i.hasNext()) {
doSomething(i.next());
Unfortunately,
}
this bug is silent
Iterator<Element> i2 = c2.iterator();
while (i.hasNext()) {
doSomething(i2.next());
}
4
General Programming
More Item 45: Solution with for
Loops

Consider the same formulation with for loops


Result is compile time error
Note: with for loop – no reason to change variable names
for (Iterator<Element> i = c.iterator();
i.hasNext(); ) {
doSomething(i.next());
}
5
// Compile time error – cannot find symbol i
for (Iterator<Element> i2 = c2.iterator();
i.hasNext(); ) {
doSomething(i2.next());
}
General Programming
More Item 45: Example of
Multiple Initializations

A final for loop example
for (int i=0, n = expensiveComputation(); i < n; i++) {
doSomething(i);
}



6
Note that there are two loop variables: i and n
Scope of both is limited to for loop
Avoid if expensiveComputation() does not have
a constant value
General Programming
Item 46: Prefer for-each Loops to
Traditional for Loops
// Preferred idiom for iterating over a collections and
arrays
for (Element e: elements) {
// read “:” as “in”
doSomething(e);
}
// No longer the preferred idiom to iterate over a
collection
for (Iterator i = c.iterator(); i.hasNext(); ) {
doSomething( (Element) i.next());
// No generics
before 1.5
}
// No longer the preferred idiom to iterate over an array
for (int i=0; i < a.length; i++ ) {
doSomething( a[i] );
// Note: you still need this idiom if you want write
General Programming
a[i] = …
7
More Item 46: Nested Iterations
// Can you spot the bug?
enum Suit { CLUB, DIAMOND, HEART, SPADE }
enum Rank { ACE, DEUCE, …, KING }
Collection <Suit> suits = Arrays.asList(Suit.values());
Collection <Rank> rank = Arrays.asList(Rank.values());
List <Card> deck = new ArrayList<Card>();
for (Iterator<Suit> i = suits.iterator(); i.hasNext(); ) {
for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); ) {
deck.add (new Card(i.next(), j.next());
// throws
NoSuchElementException
}
}
8
// Fixed – but still ugly
for (Iterator<Suit> i = suits.iterator(); i.hasNext(); ) {
Suit suit = i.next();
for (Iterator<Rank> j = ranks.iterator(); j.hasNext(); ) {
deck.add (new Card(suit, j.next());
}
}
General Programming
More Item 46: Using the for-each
Loop
// For each loop solves problem
for (Suit suit : suits ) {
for (Rank rank : ranks) {
deck.add (new Card(suit, rank));
}
}
// Similar problem, but fails silently
enum Face { ONE, TWO, THREE, FOUR, FIVE, SIX }
Collection<Face> faces = Arrays.asList(Face.values());
for (Iterator<Face> i = faces.iterator(); i.hasNext()) {
for Iterator<Face> j = faces.iterator(); j.hasNext()) {
System.out.println(i.next() + “ “ + j.next());
}
}
// Output is ONE ONE, TWO TWO, etc, instead of all combinations
// Same fix
for (Face face1 : faces) {
for (Face face2 : faces) {
System.out.println(face1 + “ “ + face2);
}
}
9
General Programming
More Item 46: Iterable
interface



Simple to implement Iterable interface:
// public interface Iterable<E> {
// Returns an iterator over the elements in
this iterable
public Iterator<E> iterator();
}
You should provide this API to your clients, if appropriate
Three cases where client can’t use a for-each loop



10
Filtering – client needs to traverse a collection and remove selected
elements
Transforming – client needs to traverse a collection and replace some
values
Parallel Iteration – client needs to traverse multiple collections in
parallel, and hence need to control iterator or index variable
General Programming
More Item 46: Implementing and
then using Iterable
public class IterableExample {
public static void main( String[] args) {
Example<String> example = new Example<String>();
example.add("hat"); example.add("cat");
for (String s: example) {
System.out.println (s);
}
}
}
public class Example<E> implements Iterable<E> {
Set<E> s = new TreeSet();
public void add (E e) { s.add(e);}
public Iterator<E> iterator() { return s.iterator(); }
}
11
General Programming
Item 47: Know and Use the
Libraries
// Common, but deeply flawed!
private static final Random rnd = new Random();
static int random (int n) {
return Math.abs(rnd.nextInt()) % n;
}

Three flaws:


if n is a small power of 2, sequence (quickly) repeats
if n is not a power of 2, some numbers are more frequent


sometimes, can fail catastrophically


What if rnd.nextInt() returns Integer.MIN_VALUE?
What to do?


12
See example in Bloch where 2/3 of results show up in half the range
It’s easy (if you know the libraries)
Use Random.nextInt() - Available since 1.2
General Programming
More Item 47: Library
Advantages



13
Using a library takes advantage of
 Knowledge of experts who wrote it
 Experience of users who used it before you
Libraries evolve
 Numerous features added to libraries in every major
release
 Bloch suggests studying java.lang, java.util,
and java.io
Don’t reinvent the wheel
 Library code is better than your code!
 Bloch says it’s not a comment about your abilities
(But this is Bloch and peers we’re talking about…)
 You don’t have the same resources
General Programming
Item 48: Avoid float and
double if Exact Answers are
Required
// Broken – uses floating point for monetary
calculation!
public static void main (String[] args) {
double funds = 1.00;
int itemsBought = 0;
for (double price = .10; funds >= price; price
+=10 ) {
funds -= price;
itemsBought++;
}
System.out.println ( itemsBought + “ items
bought.”);
System.out.println ( “Change” $” + funds);
}
14 
Results:
General Programming
Item 49: Prefer Primitive Types
to Boxed Primitives
// Broken comparator – can you spot the flaw?
Comparator < Integer> naturalOrder =
new Comparator<Integer>() {
// Anonymous
type
public int compare (Integer first, Integer
second) {
return first < second ? -1 :
// Auto
unboxing
(first == second
// No auto
unboxing (!)
? 0 : 1);
}
};

15
Sample uses:

naturalOrder.compare(new Integer(41), new
Integer(42));
General Programming
More Item 49
// Repaired version
Comparator < Integer> naturalOrder =
new Comparator<Integer>() {
// Still an anonymous type
public int compare (Integer first, Integer second) {
int f = first; int s = second;
// Auto unboxing
return f < s ? -1 : (f == s ? 0 : 1);
// No unboxing needed
}
};
// Another little gem
public class Unbelievable {
static Integer i;
public static void main(String[] args) {
(if i == 42)
System.out.println(“Unbelievable”);
}
}

Doesn’t print “Unbelievable”

But does throw NullPointerException!

When mixing primitives and boxed primitives, the boxed primitive is auto unboxed
16
General Programming
More Item 49
// Performance problem with autoboxing
public static void main(String[] args) {
Long sum = 0L;
// ok if declaration is “long sum = 0;”
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum +=i;
}
System.out.println(sum);
}


Orders of magnitude slower than it should be
So, when to use boxed primitives?


17
As elements, keys, and values in Collections
Otherwise, use primitives
General Programming
Item 50: Avoid Strings Where
Other Types Are More Appropriate

Strings are a poor substitute for other value types



Strings are a poor substitute for enum types


Input arrives as String from file, keyboard or network
Transform to underlying type, eg int, float, or boolean
Simply use enum types directly (See Bloch Item 30)
Strings are poor substitutes for aggregate types
// Innappropriate use of String as aggregate type
String compounKey = classname + “#” + i.next();





Strings are poor substitutes for capabilities



18
What if delimeter “#” is in classname or i.next()?
How do you access fields (except by parsing)?
What about equals(), compareTo(), and toString()?
Better to simply write a class to represent the aggregate
A capability grants access to a resource
The problem is that the String namespace is global
Hence, anyone can create any String.
General Programming
Item 51: Beware the Performance
of String Concatenation
// Inappropriate use of string concatenation – performs
horribly
public String statement() {
String result = “”;
for (int i=0; i < numItems(); i++) {
result += lineForItem(i);
// String concatenation
}
}
// StringBuilder version – much faster
public String statement() {
StringBuilder b = new StringBuilder(numItems *
LINE_WIDTH);
for (int i=0; I < numItems(); i++) {
b.append( lineForItem(i));
}
return b.toString();
General Programming
19 }
Item 52: Refer to Objects by Their
Interfaces
// Good – uses interfaces as type
List <Subscriber> subscribers = new Vector<Subscriber>();
// Bad – uses class as type
Vector <Subscriber> subscribers = new
Vector<Subscriber>();
// Second form prohibits maintenance change to
List <Subscriber> subscribers = new
ArrayList<Subscriber>();

If you get into the habit of using interfaces as types


If appropriate interface types exist, use for



20
Your programs will be much more flexible

parameters
return values
variables
fields
General Programming
Item 53: Prefer Interfaces to
Reflection

Reflection allows full access to any class



Powerful mechanism! But there is a price:





You lose all the benefits of compile time checking
Code for reflexive access is cumbersome and verbose
Performance suffers
As a rule, objects should not be reflexively accessed at
runtime
To limit use of reflection



21
Possible to obtain, all Constructors, Methods, and Fields
Update or invoke; eg Method.invoke
Create instances reflectively, but
Access instances through an interface or superclass
You may not even have to use java.lang.reflect
General Programming
More Item 53
// Reflective instantiation with interface access
// Bulky (vs calling a constructor), with possible runtime errors
public static void main (String [] args) {
// Translate the class name into a Class object
Class<?> cl = null; // note that try/catch block interrupts declaration
try{
cl = Class.forName (args[0]);
} catch (ClassNotFoundException e) {
// runtime, not compile time, error
System.err.println(”Class not found.”);
System.exit(1);
// terminates JVM! – generally bad
practice
// ok for command line utility
}
// Instantiate the class
Set <String> s = null;
try{
s = (Set<String>) cl.newInstance();
} catch (IllegalAccessException e) {
// runtime, not compile time,
error
System.err.println(”Class not accessible.”); System.exit(1);
} catch (InstantiationException e) {
// runtime, not compile time,
error
System.err.println(”Class not instantiable.”); System.exit(1);
}
22
// Exercise the set
s.addAll(Arrays.asList(args).subList(1, args.length));
General Programming
Item 54: Use Native Methods
Judiciously


Java allows calls to code written in other languages
Three historical reasons




Access to platform specific facilities
Access to legacy code
Performance critical sections
First and third reasons less compelling now


Java releases now features access to platform specific facilities
It is rarely advisable to use native methods for performance


23
Calls to native methods are now often slower
JVMs are much more efficient
General Programming
Item 55: Optimize Judiciously

Three quotes



More computing sins are committed in the name of efficiency
(without necessarily achieving it) than for any other single
reason – including blind stupidity (William A. Wulf, 1972)
We should forget about small efficiencies, say about 97% of the
time: premature optimization is the root of all evil (Donald E.
Knuth, 1974)
We follow two rules in the matter of optimization (M.A. Jackson,
1975)
Rule 1: Don’t do it.
Rule 2: (for experts only) Don’t do it yet – that is, not until you have
a perfectly clear and unoptimized solution

Note that this advice is 3+ decades old


24
Think how slow/limited computer systems were in the 1970s
Bottom line: Advice is even more relevant now
General Programming
More Item 55

Strive to write good programs rather than fast ones



But avoid design decisions that limit performance
Consider effect of API decisions, wire-level protocols, and data
formats
Example: java.awt.Component class

public Dimension getSize()
size



Too late now!
As of release 1.2, two new methods added:

25
Return type is a mutable height/width record
No sharing possible, so, a new object created on every call
Ideally, Dimension should be immutable


// return component

int getHeight(), int getWidth()
Unfortunately, doesn’t help legacy code
General Programming
More Item 55

Fortunate fact


Don’t warp an API for performance reasons



Good API design usually consistent with good performance
Performance problem may go away in future releases
But API design is permanent
If you have to optimize (for experts only!)

Measure performance before and after optimization



Performance problems are “needles in haystacks”



In a big haystack, you need a metal detector
In a big program, you need hard data
Java resists easy definition of costs for primitive operations

26
Use a profiling tool
Results often conflict with intuition
Performance varies from JVM to JVM
General Programming
Item 56: Adhere to Generally
Accepted Naming Conventions

Packages


Class and Interface names


MIN_VALUE, NEGATIVE_INFINITY
Type Parameter

27
i, xref, houseNumber
Constant


Remove(), ensureCapacity(), getCrc()
Local Variable


Timer, FutureTask, LinkedHashMap, HttpServlet
Method and Field names


com.google.inject, org.joda.time.format
T, E, K, V, X, T1, T2
General Programming
More Item 56:

Methods that perform some actions



Methods that return boolean



Name usually starts with “is”; sometimes “has”
isDigit(), isProbablePrime(), isEmpty(), isEnabled(),
hasSiblings()
Methods that return nonboolean





Verb or verb phrase
append(), drawImage()
noun, noun phrase, or verb phrase starting with “get”
size(), hashCode(), getTime()
“get” form required for Beans; other form often more readable
“getters” usually have “setters” (unless immutable…)
Special cases

type conversion methods use “to”


view methods use “as”


28
toString(), toArray()
asType(), asList()
Common static factory names

valueOf(), of(), getInstance(), newInstance(), getType(),
and
General Programming
newType()
Download