Explain Codes LogoExplain Codes Logo

Observer is deprecated in Java 9. What should we use instead of it?

java
concurrency-models
thread-safety
event-model
Alex KataevbyAlex Kataev·Mar 1, 2025
TLDR

java.util.Observable is out! Instead, use PropertyChangeSupport for property change listener mechanisms:

import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; public class ObservableBean { private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private String value; // Subscribe to value changes like it's your favourite YouTube channel public void addListener(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } // Where the magic happens. Or not? Let's see... public void setValue(String newValue) { String oldValue = this.value; this.value = newValue; pcs.firePropertyChange("value", oldValue, newValue); } } // Usage ObservableBean bean = new ObservableBean(); bean.addListener(evt -> System.out.println("Changed: " + evt.getNewValue())); bean.setValue("Hello"); // Hello to the Observable world

For asynchronous and reactive data flows, start using java.util.concurrent.Flow. It has mastered the art of non-blocking performance and loves to apply back-pressure as needed:

import java.util.concurrent.Flow.Subscriber; import java.util.concurrent.Flow.Subscription; import java.util.concurrent.SubmissionPublisher; // Publisher: data's personal Uber driver SubmissionPublisher<String> publisher = new SubmissionPublisher<>(); // Subscriber: Always waiting eagerly for the next data delivery Subscriber<String> subscriber = new Subscriber<>() { public void onSubscribe(Subscription subscription) { subscription.request(1); // Just one for now, I'm on diet } public void onNext(String item) { System.out.println(item); // Let's see what we got! } public void onError(Throwable t) { t.printStackTrace(); } // Oopsie Daisy public void onComplete() { System.out.println("Done"); } // That's a wrap, folks! }; publisher.subscribe(subscriber); // Connect subscriber, let the fun begin! publisher.submit("data"); // Start the data flow publisher.close(); // Bye Bye, Publisher. You've been great!

Exploring alternatives: what changed in Java 9?

Deprecation of the original Observer Pattern came with the change in Java's course towards more advanced concurrency models and safer practices. This includes improvements in areas that the old pattern just couldn't handle well such as serialization and thread safety. Instead of being rigid, be adaptable! Check out the Java Beans package for a richer event model.

Concurrent structures: making threads teamwork

In case of thread communication, concurrent data structures from java.util.concurrent package come to your rescue. They offer more robust solutions to attain thread-safety and avoid data inconsistencies in your application caused by synchronized-access problems!

Reactive streams: obtaining the Observer's grail

With Reactive Streams, Java took the antique Observer Pattern and brought it to the frontlines of asynchronous programming. Grappling with it might take some patience but the result? A high-performance system, able to handle stream-based data with ease. And who doesn't like the sound of that?

Legacy: navigating the minefield of deprecated code

Have lots of existing systems relying heavily on the Observer Pattern? Fear not. The deprecation of the Observer doesn't mean starting over completely. Instead, it's all about incremental improvements and slowly shifting towards newer paradigms.