Title: Effective Java: General Programming
1Effective Java General Programming
2Agenda
- Material From Joshua Bloch
- Effective Java 2nd Edition
- Cover Items 45-56
- General Programming Chapter
- Bottom Line
- Nuts and bolts of the Java language
- Treatment of two extralinguistic language
facilities - Optimization and naming conventions
3Item 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 -
- // No for-each loop or generics before release
1.5 - for (Iterator i c.iterator() i.hasNext() )
- doSomething( (Element) i.next()) // Note
the cast -
4More Item 45 Problems with while Loops
- Sample problem with while loops
- Problem disappears with local declarations in a
for loop - // Spot the bug?
- IteratorltElementgt i c.iterator()
- while (i.hasNext())
- doSomething(i.next())
-
- IteratorltElementgt i2 c2.iterator()
- while (i.hasNext())
- doSomething(i2.next())
-
BUG!
Unfortunately, this bug is silent
5More 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 (IteratorltElementgt i c.iterator()
i.hasNext() ) - doSomething(i.next())
-
- // Compile time error cannot find symbol i
- for (IteratorltElementgt i2 c2.iterator()
i.hasNext() ) - doSomething(i2.next())
-
6More Item 45 Example of Multiple Initializations
- A final for loop example
- for (int i0, n expensiveComputation() i lt n
i) - doSomething(i)
-
- 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
7Item 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 i0 i lt a.length i )
- doSomething( ai )
- // Note you still need this idiom if you
want write ai -
8More Item 46 Nested Iterations
- // Can you spot the bug?
- enum Suit CLUB, DIAMOND, HEART, SPADE
- enum Rank ACE, DEUCE, , KING
- Collection ltSuitgt suits Arrays.asList(Suit.value
s()) - Collection ltRankgt rank Arrays.asList(Rank.values
()) - List ltCardgt deck new ArrayListltCardgt()
- for (IteratorltSuitgt i suits.iterator()
i.hasNext() ) - for (IteratorltRankgt j ranks.iterator()
j.hasNext() ) - deck.add (new Card(i.next(), j.next())
// throws NoSuchElementException -
-
- // Fixed but still ugly
- for (IteratorltSuitgt i suits.iterator()
i.hasNext() ) - Suit suit i.next()
- for (IteratorltRankgt j ranks.iterator()
j.hasNext() ) - deck.add (new Card(suit, j.next())
-
9More 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
- CollectionltFacegt faces Arrays.asList(Face.values
()) - for (IteratorltFacegt i faces.iterator()
i.hasNext()) - for IteratorltFacegt 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)
10More Item 46 Iterable interface
- Simple to implement Iterable interface
- // public interface IterableltEgt
- // Returns an iterator over the elements in
this iterable - public IteratorltEgt iterator()
-
- You should provide this API to your clients, if
appropriate - Three cases where client cant use a for-each
loop - 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
11More Item 46 Implementing and then using Iterable
- public class IterableExample
- public static void main( String args)
- ExampleltStringgt example new
ExampleltStringgt() - example.add("hat") example.add("cat")
- for (String s example)
- System.out.println (s)
-
-
-
- public class ExampleltEgt implements IterableltEgt
- SetltEgt s new TreeSet()
-
- public void add (E e) s.add(e)
- public IteratorltEgt iterator() return
s.iterator() -
12Item 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 - See example in Bloch where 2/3 of results show up
in half the range - sometimes, can fail catastrophically
- What if rnd.nextInt() returns Integer.MIN_VALUE?
- What to do?
- Its easy (if you know the libraries)
- Use Random.nextInt() - Available since 1.2
13More Item 47 Library Advantages
- 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 - Dont reinvent the wheel
- Library code is better than your code!
- Bloch says its not a comment about your
abilities (But this is Bloch and peers were
talking about) - You dont have the same resources
14Item 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 gt price price
10 ) - funds - price
- itemsBought
-
- System.out.println ( itemsBought items
bought.) - System.out.println ( Change funds)
-
- Results
- 3 items bought
- 0.3999999999999999 in change
15Item 49 Prefer Primitive Types to Boxed
Primitives
- // Broken comparator can you spot the flaw?
- Comparator lt Integergt naturalOrder
- new ComparatorltIntegergt() // Anonymous
type - public int compare (Integer first, Integer
second) - return first lt second ? -1 // Auto
unboxing - (first second // No auto
unboxing (!) - ? 0 1)
-
-
- Sample uses
- naturalOrder.compare(new Integer(41), new
Integer(42)) - naturalOrder.compare(new Integer(42), new
Integer(42)) naturalOrder.compare(new
Integer(43), new Integer(42))
16More Item 49
- // Repaired version
- Comparator lt Integergt naturalOrder
- new ComparatorltIntegergt()
// Still an anonymous type - public int compare (Integer first, Integer
second) - int f first int s second
// Auto unboxing - return f lt 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)
-
-
- Doesnt print Unbelievable
- But does throw NullPointerException!
17More 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 lt Integer.MAX_VALUE i)
- sum i
-
- System.out.println(sum)
-
- Orders of magnitude slower than it should be
- So, when to use boxed primitives?
- As elements, keys, and values in Collections
- Otherwise, use primitives
18Item 50 Avoid Strings Where Other Types Are More
Appropriate
- Strings are a poor substitute for other value
types - Input arrives as String from file, keyboard or
network - Transform to underlying type, eg int, float, or
boolean - Strings are a poor substitute for enum types
- 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()
- 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 - Strings are poor substitutes for capabilities
- A capability grants access to a resource
- The problem is that the String namespace is
global - Hence, anyone can create any String.
19Item 51 Beware the Performance of String
Concatenation
- // Inappropriate use of string concatenation
performs horribly - public String statement()
- String result
- for (int i0 I lt numItems() i)
- result lineForItem(i) // String
concatenation -
-
-
- // StringBuilder version much faster
- public String statement()
- StringBuilder b new StringBuilder(numItems
LINE_WIDTH) - for (int i0 I lt numItems() i)
- b.append( lineForItem(i))
-
- return b.toString()
-
20Item 52 Refer to Objects by Their Interfaces
- // Good uses interfaces as type
- List ltSubscribergt subscribers new
VectorltSubscribergt() -
- // Bad uses class as type
- Vector ltSubscribergt subscribers new
VectorltSubscribergt() -
- // Second form prohibits maintenance change to
- List ltSubscribergt subscribers new
ArrayListltSubscribergt() - If you get into the habit of using interfaces as
types - Your programs will be much more flexible
- If appropriate interface types exist, use for
- parameters
- return values
- variables
- fields
21Item 53 Prefer Interfaces to Reflection
- Reflection allows full access to any class
- Possible to obtain, all Constructors, Methods,
and Fields - Update or invoke eg Method.invoke
- 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
- Create instances reflectively, but
- Access instances through an interface or
superclass - You may not even have to use java.lang.reflect
22More 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 - Classlt?gt cl null // note that try/catch
block interrupts declaration - try
- cl Class.forName (args0)
- 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 ltStringgt s null
- try
- s (SetltStringgt) 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
23Item 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 - Calls to native methods are now often slower
- JVMs are much more efficient
24Item 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 Dont do it.
- Rule 2 (for experts only) Dont do it yet that
is, not until you have a perfectly clear and
unoptimized solution - Note that this advice is 3 decades old
- Think how slow/limited computer systems were in
the 1970s - Bottom line Advice is even more relevant
now
25More 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() // return component
size - Return type is a mutable height/width record
- No sharing possible, so, a new object created on
every call - Ideally, Dimension should be immutable
- Too late now!
- As of release 1.2, two new methods added
- int getHeight(), int getWidth()
- Unfortunately, doesnt help legacy code
26More Item 55
- Fortunate fact
- Good API design usually consistent with good
performance - Dont warp an API for performance reasons
- 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
- Use a profiling tool
- Results often conflict with intuition
- 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 - Performance varies from JVM to JVM
27Item 56 Adhere to Generally Accepted Naming
Conventions
- Packages
- com.google.inject, org.joda.time.format
- Class and Interface names
- Timer, FutureTask, LinkedHashMap, HttpServlet
- Method and Field names
- Remove(), ensureCapacity(), getCrc()
- Local Variable
- i, xref, houseNumber
- Constant
- MIN_VALUE, NEGATIVE_INFINITY
- Type Parameter
- T, E, K, V, X, T1, T2
28More Item 56
- Methods that perform some actions
- Verb or verb phrase
- append(), drawImage()
- Methods that return boolean
- Name usually starts with is sometimes has
- isDigit(), isProbablePrime(), isEmpty(),
isEnabled(), hasSiblings() - Methods that return nonboolean
- 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
- toString(), toArray()
- view methods use as
- asType(), asList()
- Common static factory names
- valueOf(), of(), getInstance(), newInstance(),
getType(), and newType()