Implementing Observer Pattern in Java
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
I define an observer callback, a way to register and remove observers, and a subject that owns the registrations. When state changes, the subject first creates the event or immutable state snapshot, then captures the listeners for that notification cycle and invokes them according to a documented policy. For example, iterating List.copyOf(listeners) lets one callback remove itself without changing the current iteration, but that copy alone does not make concurrent registration and subject state safe; those still need a lock or concurrent structure. I provide a removal handle when listener lifetimes differ, avoid holding internal locks during callbacks, and decide what ordering and one listener exception mean.
Implementing Observer Pattern in Java
Direct Answer
Define an observer callback and a subject or subscription API, store registrations, update state, capture the intended listener and state snapshot, then invoke callbacks according to a documented timing and error policy. Copying a list avoids self-removal problems during one-thread iteration but is not by itself a complete thread-safety design. Provide a registration handle or removal method when observer lifetimes differ.
Code Example
interface Observer { void update(String status); }
interface Subject {
void attach(Observer o);
void detach(Observer o);
void notifyObservers();
}
class OrderSubject implements Subject {
private final List<Observer> observers = new ArrayList<>();
private String status;
public void attach(Observer o) { observers.add(o); }
public void detach(Observer o) { observers.remove(o); }
public void notifyObservers() {
// defensive copy: an observer may detach itself during update()
for (Observer o : List.copyOf(observers)) o.update(status);
}
public void setStatus(String status) {
this.status = status; // 1) state change first
notifyObservers(); // 2) then notify
}
}
class EmailObserver implements Observer {
private final String to;
EmailObserver(String to) { this.to = to; }
public void update(String status) { System.out.println("Email " + to + ": " + status); }
}
// Usage
var order = new OrderSubject();
Observer email = new EmailObserver("a@b.com");
order.attach(email);
order.setStatus("SHIPPED"); // -> Email a@b.com: SHIPPED
order.detach(email); // unregister to avoid the lapsed-listener leak
Common Mistakes & Pitfalls
- Iterating the live list. An observer detaching itself in
update()throwsConcurrentModificationException. UseList.copyOf(observers)orCopyOnWriteArrayList. - No
detachmethod. Without unregister, observers leak (the lapsed listener problem). - Notifying before the state change. Observers then read stale data; always update state first.
- Coupling observers to each other. Don't assume one observer ran before another — order isn't guaranteed.
Check your understanding
Answer these without looking back at the article.
- How do you make the Observer pattern thread-safe?
- How would you implement Observer using Java's functional interfaces (lambdas)?
- Why must you update state before notifying observers?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.