library
intermediateObserver Pattern & Event Handling
Implement publish-subscribe in Java using listeners, PropertyChangeSupport, or modern reactive alternatives.
The subject keeps a list of listeners and calls them when something happens. It never needs to know who they are.
Observer = a newsletter subscription. You subscribe (register). When the publisher has news (state change), all subscribers receive the update. You can unsubscribe anytime. The publisher doesn't need to know who you are — just that you're on the list.
Key Concepts
1
public class OrderService {
private final List<OrderListener> listeners = new CopyOnWriteArrayList<>();2
public void addListener(OrderListener l) { listeners.add(l); }
public void removeListener(OrderListener l) { listeners.remove(l); }3
private void fire(Order o) {
for (OrderListener l : listeners) l.onPlaced(o);
}
}4
service.addListener(order -> email.confirm(order));
service.addListener(order -> warehouse.reserve(order));5
What it buys. Without it, OrderService imports the mailer, the warehouse and the analytics client, and
gains a dependency for every feature. With it, it knows only OrderListener.
OrderServiceOrderListener
6
CopyOnWriteArrayList is the right list here, and this is its canonical use. Listeners are registered at
startup and read on every event, and a plain ArrayList would throw
ConcurrentModificationException if a listener removed itself during notification.
CopyOnWriteArrayListArrayListConcurrentModificationException
7
One listener must not break the rest.
for (OrderListener l : listeners) {
try { l.onPlaced(o); }
catch (RuntimeException e) { log.warn("listener failed", e); }
}8
Without the catch, the first failing listener stops the others — and the order in which they happened to
register decides which side effects occurred.
9
Forgetting to unregister is a memory leak. The subject holds a strong reference, so a listener lives as
long as the subject does. If listeners come and go, remove them, or hold them weakly.
10
Notification is synchronous. The caller waits for every listener in turn, so a slow one slows the
transaction that triggered it. Hand the work to an executor, or publish to a queue, when that matters.
11
What the JDK offers.
PropertyChangeSupport the JavaBeans version, still used in Swing
Flow.Publisher reactive streams with backpressure, Java 9
Observable / Observer deprecated since Java 9 -- do not use12
And in Spring, ApplicationEventPublisher with @EventListener is this pattern with the registration
done for you, and @Async to make it non-blocking.
ApplicationEventPublisher@EventListener@Async
13
What the interviewer is probing.1. "What list should hold the listeners and why?" Probing: the concurrency detail. Stalls:
"An ArrayList." Moves up: CopyOnWriteArrayList — listeners are read on every event and rarely
written, and a listener removing itself during notification would otherwise throw.
14
2. "One listener throws. What happens to the others?" Probing: isolation. Stalls: "They
still run." Moves up: without a try/catch around each call the exception stops the loop, so which
side effects occurred depends on registration order.
15
3. "How does this pattern leak memory?" Probing: the strong reference. Stalls: "It does
not." Moves up: the subject holds the listener, so it lives as long as the subject; unregister, or
hold them weakly.
16
4. "Why is java.util.Observable deprecated?" Probing: whether you know what replaced it.
Stalls: "It is old." Moves up: it was not generic, not serialisable usefully and required
subclassing; listeners, PropertyChangeSupport or Flow.Publisher replaced it.