Chapter 42: Abstraction in Java
This chapter is mostly conceptual: abstraction means showing what something does while hiding how (or deferring “how” to subclasses). Abstract classes are Chapter 43; interfaces are Chapter 44.
1. Topic title
Abstraction: name the capability, hide or postpone the mechanics
2. What it means
Every class already abstracts something—you call read() on an input type without re-implementing the OS buffer logic. Design-level abstraction is the same instinct at your boundaries:
- Essential: “I can serialize this object to JSON.”
- Accidental today: “I use Jackson vs manual string building.”
Good abstractions let you swap implementations without rewriting every caller.
3. Why it is used
Reduce cognitive load — callers think in verbs (save, send, render), not in every field and helper.
Isolate change — persistence format changes stay inside a small module if the rest talks to a narrow interface.
4. Real-world example
HTTP client: your service depends on “can execute GET and return body,” not on whether you used Java 11 HttpClient, Apache HttpClient, or a mock in tests.
5. Java code example
/** Abstraction as a tiny contract without inheritance yet. */
interface Clock {
long millis();
}
final class SystemClock implements Clock {
@Override
public long millis() {
return System.currentTimeMillis();
}
}
final class FixedClock implements Clock {
private final long value;
FixedClock(long value) {
this.value = value;
}
@Override
public long millis() {
return value;
}
}
class Greeter {
private final Clock clock;
Greeter(Clock clock) {
this.clock = clock;
}
String greeting(String name) {
return "Hello " + name + " @ " + clock.millis();
}
}
public class AbstractionDemo {
public static void main(String[] args) {
System.out.println(new Greeter(new SystemClock()).greeting("Ada"));
System.out.println(new Greeter(new FixedClock(1)).greeting("Bob"));
}
}Here Greeter depends on Clock, not on System. That is dependency on an abstraction—tests can use FixedClock.
6. Explanation of code
interface Clock names one capability. Implementations differ; Greeter stays stable. Chapter 44 goes deeper on interface mechanics.
7. Common mistakes
Leaking internals through getters that expose deep mutable graphs—callers bind to your structure, not your intent.
Over-abstracting early — two copies of similar code might be coincidence; wait until a second real use before inventing layers.
8. Best practices
Name abstractions after behaviors (Notifier, RateLimiter) more often than technologies (KafkaProducerWrapper) unless the tech is the contract.
Keep surfaces small — fewer methods mean fewer ways to couple accidentally.
9. Small practice task
Introduce interface RandomSource { int nextInt(int bound); } with java.util.Random behind one implementation and a FixedRandom that returns a constant for tests. Inject it into a DiceRoller that rolls 1–6.
Beginner tip
If “abstraction” sounds vague, translate it to “I depend on a small promise, not on a big concrete class.” The next two chapters show Java’s two big language tools for that promise.