effective java: general programming last updated: fall 2008

26
Effective Java: General Programming Last Updated: Fall 2008

Upload: whitney-houston

Post on 08-Jan-2018

230 views

Category:

Documents


0 download

DESCRIPTION

General Programming 3 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); } // No for-each loop or generics before release 1.5 for (Iterator i = c.iterator(); i.hasNext(); ) { doSomething( (Element) i.next()); }

TRANSCRIPT

Page 1: Effective Java: General Programming Last Updated: Fall 2008

Effective Java: General Programming

Last Updated: Fall 2008

Page 2: Effective Java: General Programming Last Updated: Fall 2008

General Programming2

Agenda Material From Joshua Bloch

Effective Java: Programming Language Guide

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

Page 3: Effective Java: General Programming Last Updated: Fall 2008

General Programming3

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 collectionfor (Element e : C) { doSomething(e);}

// No for-each loop or generics before release 1.5for (Iterator i = c.iterator(); i.hasNext(); ) { doSomething( (Element) i.next());}

Page 4: Effective Java: General Programming Last Updated: Fall 2008

General Programming4

More Item 45 Sample problem with while loops

Problem disappears with local declarations in a for loop

// Spot the bug?Iterator<Element> i = c.iterator();while (i.hasNext()) { doSomething(i.next());}

Iterator<Element> i2 = c2.iterator();while (i.hasNext()) { // Bug! doSomething(i2.next());}

Page 5: Effective Java: General Programming Last Updated: Fall 2008

General Programming5

More Item 45 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());}

// Compile time error – cannot find symbol ifor (Iterator<Element> i2 = c2.iterator(); i.hasNext(); ) { doSomething(i2.next());}

Page 6: Effective Java: General Programming Last Updated: Fall 2008

General Programming6

More Item 45 A final for loop example

for (int i=0, n = expensiveComputation(); i < n; i++) {

doSomething(i);}

Note that there are two loop variables: i and n Scope of both is limited to for loop Correct if expensiveComputation() has a constant

value inside the loop

Page 7: Effective Java: General Programming Last Updated: Fall 2008

General Programming7

Item 46: Prefer for-each Loops to Traditional for Loops

// Preferred idiom for iterating over a collections and arraysfor (Element e: C) { // read “:” as “in” doSomething(e);}

// No longer the preferred idiom to iterate over a collectionfor (Iterator I = c.iterator(); i.hasNext(); ) { doSomething( (Element) i.next()); // No generics before 1.5}

// No longer the preferred idiom to iterate over an arrayfor (int i=0; i < a.length; i++ ) { doSomething( a[i] ); // Note: you still need this idiom if you want write a[i] = …}

Page 8: Effective Java: General Programming Last Updated: Fall 2008

General Programming8

More Item 46// 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 }}

// Fixed – but still uglyfor (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()); }}

Page 9: Effective Java: General Programming Last Updated: Fall 2008

General Programming9

More Item 46// For each loop solves problemfor (Suit suit : suits ) { for (Rank rank : ranks) { deck.add (new Card(suit, rank); }}

// Similar problem, but fails silentlyenum 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); }}

Page 10: Effective Java: General Programming Last Updated: Fall 2008

General Programming10

More Item 46 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 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

Page 11: Effective Java: General Programming Last Updated: Fall 2008

General Programming11

Item 47: Know and Use the Libraries

// Common, but deeply flawed exampleprivate 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 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?

It’s easy (if you know the libraries) Use Random.nextInt() - Available since 1.2

Page 12: Effective Java: General Programming Last Updated: Fall 2008

General Programming12

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);}

Results: 3 items bought $0.3999999999999999 in change

Page 13: Effective Java: General Programming Last Updated: Fall 2008

General Programming13

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); }};

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));

Page 14: Effective Java: General Programming Last Updated: Fall 2008

General Programming14

More Item 49// Repaired versionComparator < Integer> naturalOrder = new Comparator<Integer>() { // 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 }};

// Another little gempublic 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

Page 15: Effective Java: General Programming Last Updated: Fall 2008

General Programming15

More Item 49// Performance problem with autoboxingpublic 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?

As elements, keys, and values in Collections Otherwise, use primitives

Page 16: Effective Java: General Programming Last Updated: Fall 2008

General Programming16

Item 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 typeString 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.

Page 17: Effective Java: General Programming Last Updated: Fall 2008

General Programming17

Item 51: Beware the Performance of String Concatenation

// Inappropriate use of string concatenation – performs horriblypublic String statement() { String result = “”; for (int i=0; I < numItems(); i++) { result += lineForItem(i); // String concatenation }} // StringBuilder version – much fasterpublic String statement() { StringBuilder b = new StringBuilder(numItems * LINE_WIDTH); for (int i=0; I < numItems(); i++) { b.append( lineForItem(i)); } return b.toString();}

Page 18: Effective Java: General Programming Last Updated: Fall 2008

General Programming18

Item 52: Refer to Objects by Their Interfaces

// Good – uses interfaces as typeList <Subscriber> subscribers = new Vector<Subscriber>(); // Bad – uses class as typeVector <Subscriber> subscribers = new Vector<Subscriber>(); // Second form prohibits maintenance change toList <Subscriber> subscribers = new ArrayList<Subscriber>();

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

Page 19: Effective Java: General Programming Last Updated: Fall 2008

General Programming19

Item 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

Page 20: Effective Java: General Programming Last Updated: Fall 2008

General Programming20

More Item 53//Reflective instantiation with interface access – bulky (vs calling a constructor), with possible runtime errorspublic 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); }

// Exercise the set s.addAll(Arrays.asList(args).subList(1, args.length)); System.out.println(s);}

Page 21: Effective Java: General Programming Last Updated: Fall 2008

General Programming21

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 Calls to native methods are now often slower JVMs are much more efficient

Page 22: Effective Java: General Programming Last Updated: Fall 2008

General Programming22

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

Think how slow/limited computer systems were in the 1970s

Bottom line: Advice is even more relevant now

Page 23: Effective Java: General Programming Last Updated: Fall 2008

General Programming23

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() // 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, doesn’t help legacy code

Page 24: Effective Java: General Programming Last Updated: Fall 2008

General Programming24

More Item 55 Fortunate fact

Good API design usually consistent with good performance Don’t 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

Page 25: Effective Java: General Programming Last Updated: Fall 2008

General Programming25

Item 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

Page 26: Effective Java: General Programming Last Updated: Fall 2008

General Programming26

More 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()