← Back to Advanced Java Course | Chapter 6: Design Patterns | Lesson 4 of 14

Java Observer Pattern

The observer pattern lets many objects be told when one thing changes, like followers getting a notice when someone posts. They sign up, and get updates automatically.
Syntax
java
interface Observer {
    void update(Data data);
}

class Subject {
    private List<Observer> observers = new ArrayList<>();
    void attach(Observer o) { observers.add(o); }
    void notifyAll(Data data) { for (Observer o : observers) o.update(data); }
}

Subject and Observer Interfaces

The Observer Pattern defines a one-to-many dependency between objects: when one object, the Subject, changes state, every one of its registered dependents, the Observers, is notified automatically without the Subject needing to know anything specific about them.

Example: Subject and Observer Interfaces

java
// Define the class Main
public class Main {
	// Define the interface Observer
	interface Observer { void update(String data); }
	// Define the interface Subject
	interface Subject {
		void attach(Observer o);
		void notifyObservers(String data);
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Print a line to the console
		System.out.println("Subject notifies every registered Observer automatically");
	}
}

Concrete Subject Implementation

A Concrete Subject tracks its observers in an internal list, exposing methods to attach or detach observers dynamically. When its state changes, it iterates through that list and calls each observer's update method to notify them.

Example: Concrete Subject Implementation

java
// Import java.util.* so it can be used by its short name
import java.util.*;
// Define the class Main
public class Main {
	// Define the interface Observer
	interface Observer { void update(String data); }
	// Define the class NewsPublisher
	static class NewsPublisher {
		// Create a new ArrayList object and store it in observers
		List<Observer> observers = new ArrayList<>();
		void attach(Observer o) { observers.add(o); }
		void publish(String data) {
			for (Observer o : observers) o.update(data);
		}
	}
	// Program entry point: the JVM starts running here
	public static void main(String[] args) {
		// Create a new NewsPublisher object and store it in publisher
		NewsPublisher publisher = new NewsPublisher();
		publisher.attach(data -> System.out.println("Received: " + data));
		publisher.publish("Breaking news");
	}
}

Concrete Observer Implementation

A Concrete Observer implements the update method that the Subject calls into. Inside that method, it runs whatever custom logic is appropriate given the new data it just received, entirely independent of how the other observers respond to the same notification.

Example: Concrete Observer Implementation

java
public class Main {
	interface Observer { void update(String data); }
	static class LoggingObserver implements Observer {
		public void update(String data) {
			System.out.println("Logged: " + data); // independent of other observers
		}
	}
	public static void main(String[] args) {
		Observer observer = new LoggingObserver();
		observer.update("event occurred");
	}
}

Dynamic Subscriptions

Observers can subscribe or unsubscribe from a Subject dynamically at runtime, not just at setup. This flexibility prevents memory leaks from observers that should have been removed, and ensures each observer only ever receives the specific events it's actually interested in.

Example: Dynamic Subscriptions

java
import java.util.*;
public class Main {
	interface Observer { void update(String data); }
	static class Subject {
		List<Observer> observers = new ArrayList<>();
		void attach(Observer o) { observers.add(o); }
		void detach(Observer o) { observers.remove(o); }
		void notifyEach(String data) { for (Observer o : observers) o.update(data); }
	}
	public static void main(String[] args) {
		Subject subject = new Subject();
		Observer o = data -> System.out.println("Got: " + data);
		subject.attach(o);
		subject.detach(o); // unsubscribed before the next notification
		subject.notifyEach("no listeners left");
	}
}

Java Built-in Alternatives

Modern Java code commonly implements this pattern with custom, purpose-built listener interfaces rather than reaching for the JDK's original built-in Observer/Observable classes, which have been deprecated since Java 9 due to design limitations like lacking proper event ordering guarantees.

Example: Java Built-in Alternatives

java
public class Main {
	interface ChangeListener { void onChange(String value); } // custom listener, not java.util.Observable (deprecated since Java 9)
	public static void main(String[] args) {
		ChangeListener listener = value -> System.out.println("Changed to: " + value);
		listener.onChange("new state");
	}
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Never detaching observers, so the subject keeps references to them and they cannot be garbage collected.
  2. Adding or removing observers while looping over the list in notifyObservers, which throws a ConcurrentModificationException.
  3. Notifying observers before the subject's state is updated, so they receive old data.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.