skip to content

Why were java.util.Observable and java.util.Observer deprecated in Java 9, and what should you use instead?

level: juniorimportance: should knowfreq 55%

answer

  1. Observable is a class -> single-inheritance trap
  2. Object arg = untyped events, casts everywhere
  3. setChanged() ceremony before notifyObservers()
  4. Deprecated Java 9, not removed
  5. Replace with PropertyChangeSupport or Flow

basics

~20 s

The old Observable/Observer classes were deprecated in Java 9 because they were weak and limited: Observable is a class (so you must extend it), it isn't thread-safe in a useful way, and it passes plain Object events. Use listeners, PropertyChangeSupport, or the reactive Flow API instead.

solid answer

~40 s

java.util.Observable (a class) and java.util.Observer (an interface) were the original Observer-pattern support in Java 1.0, deprecated in Java 9. They have real flaws: Observable is a concrete class, so a subject must extend it, blocking other inheritance; events are untyped (Object), forcing casts; change tracking via setChanged()/notifyObservers() is clumsy and easy to misuse; ordering and concurrency guarantees are weak; and it isn't Serializable-friendly. Modern replacements depend on the need: java.beans.PropertyChangeSupport/PropertyChangeListener for typed property-change notification, framework listener interfaces (e.g. Swing ActionListener), or java.util.concurrent.Flow (the reactive-streams Publisher/Subscriber API) for asynchronous backpressure-aware streams. The library still compiles for backward compatibility but you should not build new code on it.

go deeper

for a junior

Knows the legacy Observable/Observer were deprecated in Java 9 and that you should use listeners or Flow instead.

for a middle

Can name the concrete flaws (class not interface, untyped Object args, setChanged ceremony) and map each modern replacement to a scenario.

for a senior

Explains the inheritance/composition trade-off, the deprecation policy (compiles but discouraged), and picks PropertyChangeSupport vs Flow appropriately with reasoning about sync vs async and backpressure.

for a principal

Frames the deprecation as part of the JDK's shift toward composition, typed events, and the reactive-streams contract; can discuss migration strategy for legacy Observable-based code at scale.

## What the Observer pattern is The **Observer pattern** is a design pattern where one object (the **subject** or **publisher**) maintains a list of dependents (**observers** or **subscribers**) and notifies them automatically when its state changes. It decouples the thing producing events from the things reacting to them: the subject does not need to know the concrete types of its observers, only that they implement an agreed callback. ## The original JDK support: java.util.Observable / java.util.Observer Java 1.0 shipped two types to support this: - **`java.util.Observer`** — an interface with one method, `void update(Observable o, Object arg)`. An observer implements this to react. - **`java.util.Observable`** — a **concrete class** the subject must *extend*. It holds the observer list and offers `addObserver`, `deleteObserver`, `setChanged()`, and `notifyObservers(Object arg)`. The notification protocol is unusual: a subject must call `setChanged()` to flip an internal "changed" flag before `notifyObservers()` will actually fire; `notifyObservers()` then clears the flag. Forgetting `setChanged()` silently suppresses notifications. ## Why it was deprecated in Java 9 (JDK-8154801) It was deprecated (not removed) for several concrete reasons: 1. **`Observable` is a class, not an interface.** Java has single inheritance, so a subject that extends `Observable` cannot extend anything else. This is the classic "favor composition over inheritance" violation — you are forced into an inheritance relationship just to get notification support. 2. **Untyped events.** Both the `Observable o` and the `Object arg` passed to `update` are untyped. Observers must cast and there is no compile-time guarantee about what they receive. 3. **The `setChanged()` ceremony is error-prone.** The two-step changed-flag protocol is easy to get wrong and surprising. 4. **Weak concurrency and ordering guarantees.** `notifyObservers` invokes observers in an unspecified order; the threading model and what happens if the list changes during notification are not well defined for modern concurrent use. 5. **No serialization / event-model integration.** It predates and does not fit the JavaBeans event model or reactive streams. `@Deprecated` here means: still present and compiling for backward compatibility, but a clear signal not to use it in new code. ## What to use instead (chosen by your actual need) - **Typed property-change notification** — `java.beans.PropertyChangeSupport` (a helper you *compose*, not extend) plus `PropertyChangeListener`. You fire `firePropertyChange(name, oldValue, newValue)` and listeners get a typed `PropertyChangeEvent`. This is the idiomatic single-VM, synchronous replacement. - **Framework listeners** — most UI/IO frameworks define their own listener interfaces (e.g. Swing's `ActionListener`, `ChangeListener`). These are the Observer pattern, just typed and domain-specific. - **Reactive / asynchronous streams** — `java.util.concurrent.Flow` (added in Java 9) defines `Flow.Publisher`, `Flow.Subscriber`, `Flow.Subscription`, and `Flow.Processor`: the standard reactive-streams contract with **backpressure** (the subscriber requests how many items it can handle). Use this for async, possibly-infinite event streams. ## Deriving your own answer A junior should be able to say "the old classes were deprecated; use listeners or Flow." A senior adds *why* (class-not-interface, untyped, setChanged ceremony) and *which replacement for which scenario* (PropertyChangeSupport for sync property changes, Flow for async streams).

  • What is the single biggest design flaw of java.util.Observable being a class?
    Java has single inheritance, so a subject forced to extend Observable cannot extend any other class. It violates 'favor composition over inheritance' — composition-based helpers like PropertyChangeSupport avoid this by being a field you hold rather than a parent you extend.
  • If I just need typed property-change notifications inside one JVM, what is the idiomatic replacement?
    java.beans.PropertyChangeSupport composed into your class, firing PropertyChangeEvents to registered PropertyChangeListeners — synchronous, typed, and no inheritance requirement.

saying these in an interview costs you the question

  • Saying it was removed from the JDK (it was only deprecated, still compiles)
  • Claiming Observable is an interface (it is a concrete class)
  • Recommending you keep using Observable for new code
  • Forgetting that notifyObservers does nothing unless setChanged() was called first

context