Scope, Loops, and Types
Source: Effective Java, 3rd Edition — Chapter 9 by Joshua Bloch (Items 57–62)
Chapter 9 covers everyday Java craft: variable scope, iteration, standard libraries, exact arithmetic, primitives vs boxes, and choosing the right types over strings.
Item 57: Minimize the scope of local variables
Declare locals where first used, with an initializer when possible. Premature declaration widens scope and adds clutter.
Prefer for loops that declare loop variables in the header — scope ends with the loop, preventing copy-paste bugs like reusing i from an earlier while:
for (Iterator<Element> i = c.iterator(); i.hasNext(); ) {
Element e = i.next();
}
Keep methods small so unrelated locals don’t share scope. Exception: variables used after a try block may need declaration before try if initialization can throw checked exceptions.
Local variable scope
1 / 2A method declares Result r; at the top, then finally assigns it 40 lines later inside an if/else
Pick an answer to see if you are right.
Item 58: Prefer for-each loops to traditional for loops
Enhanced for (for (Element e : c)) removes iterator/index clutter and works for collections, arrays, and anything Iterable:
for (Suit suit : suits)
for (Rank rank : ranks)
deck.add(new Card(suit, rank));
Avoid nested iterator loops that call next() on the outer iterator inside the inner loop (52-card deck bug).
When for-each won’t work: destructive filtering (Iterator.remove, or removeIf), in-place transform (list iterator / index), parallel iteration across collections. Then use explicit for/Iterator carefully.
For-each vs iterators
1 / 2Nested iterators: inner loop calls i.next() on outer iterator
Pick an answer to see if you are right.
Item 59: Know and use the libraries
Don’t reinvent Random.nextInt(bound) with Math.abs(rnd.nextInt()) % n — bias, bad periods, and rare negative results.
Prefer ThreadLocalRandom.current().nextInt(bound) (Java 7+) for general use; SplittableRandom for parallel/fork-join. Use Objects, Collections, java.util.concurrent, streams — experts already debugged them.
Item 60: Avoid float and double if exact answers are required
double cannot represent 0.1 exactly — money math drifts (1.03 - 0.42, candy-shopping loops).
For exact decimal needs:
BigDecimalwith String constructors (notdoublector)int/longcents (or smallest currency unit) when range allows
Use float/double for science/engineering approximations, not ledgers.
Item 61: Prefer primitive types to boxed primitives
Primitives vs boxes differ in identity, null, and performance.
Broken comparator: (i == j) compares references. Use Integer.compare(a, b) or compare unboxed int values.
Integer i; if (i == 42) → NPE on unboxing. Long sum = 0L in a tight loop → boxing churn.
Use boxes when required: collections, generics, reflection.
Item 62: Avoid strings where other types are more appropriate
Strings fit text. Don’t use them as:
- Numbers → parse to
int,BigDecimal, etc. - Enums → use enum types (Item 34)
- Aggregates → small classes, not
"className#index"keys - Capabilities → unforgeable keys (
ThreadLocal.Key), not global string namespaces
ThreadLocal<T> replaced string-keyed thread locals with type-safe, fast instances.
Strings vs other types
1 / 2ThreadLocal.set(String key, Object value) with client-chosen keys
Pick an answer to see if you are right.
Items 57–62 map
| Item | Move |
|---|---|
| 57 | Declare locals late; for-loop scope |
| 58 | for-each when you only need elements |
| 59 | Use library experts — Random.nextInt, etc. |
| 60 | BigDecimal or int cents for exact money |
| 61 | Primitives in hot paths; Integer.compare |
| 62 | Parse/enums/classes — not string everything |
Next: Performance, Reflection, and Style (Items 63–68).