Observable.notifyObservers(): примеры (JAVA)
Observable.notifyObservers(): voidОписание Observable.notifyObservers()
Метод notifyObservers() входит в класс java.util.Observable и предназначен для оповещения всех зарегистрированных наблюдателей (реализаций java.util.Observer) о том, что состояние наблюдаемого объекта изменилось. Существует две перегрузки: notifyObservers() и notifyObservers(Object arg). Метод ничего не возвращает (тип void).
Ключевые моменты поведения:
- Оповещение происходит только если у Observable установлен флаг изменения (функция
setChanged()была вызвана). После оповещения флаг автоматически сбрасывается (внутри notifyObservers используется clearChanged()). - При вызове notifyObservers без аргумента каждому наблюдателю передаётся
nullв качестве второго параметра методаupdate(Observable o, Object arg). При использовании notifyObservers(arg) передаётся именно этот объект. - Метод синхронизован по внутреннему состоянию Observable, чтобы список наблюдателей и флаг changed обрабатывались корректно в многопоточной среде. При оповещении создаётся копия списка наблюдателей, и дальше вызовы update выполняются вне критической секции для уменьшения вероятности взаимных блокировок.
- Класс java.util.Observable и интерфейс java.util.Observer помечены как устаревшие (deprecated) начиная с Java 9. В новых проектах рекомендуется использовать альтернативные механизмы реактивного или событийного взаимодействия.
Подписи методов (ключевые):
public void notifyObservers()public void notifyObservers(Object arg)protected void setChanged()- устанавливает флаг изменения, необходимое предварительное действие для оповещения.protected void clearChanged()- сбрасывает флаг; обычно вызывается внутри notifyObservers.
Аргументы и возвращаемые значения:
- Аргумент: либо отсутствует, либо произвольный объект
Object arg, который будет передан наблюдателям. Значение может бытьnull. - Возврат: отсутствует (
void).
Примеры использования notifyObservers()
Пример 1. Минимальный рабочий пример с передачей аргумента.
import java.util.Observable;
import java.util.Observer;
class MyObservable extends Observable {}
public class Demo1 {
public static void main(String[] args) {
MyObservable obs = new MyObservable();
obs.addObserver(new Observer() {
@Override
public void update(Observable o, Object arg) {
System.out.println("Observer received: " + arg);
}
});
obs.setChanged();
obs.notifyObservers("Hello");
}
}
Observer received: Hello
Пример 2. Вызов notifyObservers() без setChanged() - оповещение не произойдёт.
import java.util.Observable;
import java.util.Observer;
class MyObservable2 extends Observable {}
public class Demo2 {
public static void main(String[] args) {
MyObservable2 obs = new MyObservable2();
obs.addObserver((o, arg) -> System.out.println("Update: " + arg));
//Без setChanged()
obs.notifyObservers("Will not be delivered");
obs.setChanged();
obs.notifyObservers("Delivered");
}
}
Delivered
Пример 3. Несколько наблюдателей и null-аргумент.
MyObservable obs = new MyObservable();
obs.addObserver((o, arg) -> System.out.println("A: " + arg));
obs.addObserver((o, arg) -> System.out.println("B: " + arg));
obs.setChanged();
obs.notifyObservers();
A: null B: null
Альтернативы и похожие механизмы в Java
- java.beans.PropertyChangeSupport - для отслеживания изменений конкретных свойств объекта. Предпочтителен при необходимости передачи имени свойства, старого и нового значений. Не помечен как устаревший.
- java.util.concurrent.Flow (Reactive Streams API) - асинхронная, back-pressure-aware модель для потоковой передачи данных. Подходит для реактивных сценариев и больших объёмов событий.
- SubmissionPublisher - реализация издателя из Flow API, удобна для простых публикаций с возможностью асинхронной доставки.
- Сторонние библиотеки (RxJava, Project Reactor) - расширенные реактивные возможности, операторы преобразования, объединения и т.д.
- События на базе слушателей (Listener pattern) - пользовательские интерфейсы слушателей и методы add/removeListener; часто применяется в GUI и серверных компонентах.
Выбор зависит от требований: для простых уведомлений PropertyChangeSupport чаще удобнее, для реактивной обработки данных - Flow или RxJava.
Эквиваленты в других языках
Краткие примеры и отличия по языкам.
- PHP - встроенные интерфейсы SplSubject/SplObserver: уведомления синхронные, похожие на Observable, но не помечены устаревшими.
<?
class MySubject implements SplSubject {
private $observers;
private $state;
public function __construct() { $this->observers = new SplObjectStorage(); }
public function attach(SplObserver $o){ $this->observers->attach($o); }
public function detach(SplObserver $o){ $this->observers->detach($o); }
public function notify(){
foreach ($this->observers as $obs) { $obs->update($this); }
}
public function setState($s){ $this->state = $s; }
public function getState(){ return $this->state; }
}
class MyObserver implements SplObserver {
public function update(SplSubject $s){ echo "State: " . $s->getState() . "\n"; }
}
$sub = new MySubject();
$sub->attach(new MyObserver());
$sub->setState('ok');
$sub->notify();
?>
State: ok
// Node.js
const EventEmitter = require('events');
const ev = new EventEmitter();
ev.on('m', (data) => console.log('got', data));
ev.emit('m', 5);
got 5
class Observable:
def __init__(self):
self._obs = []
self._changed = False
def add_observer(self, o): self._obs.append(o)
def set_changed(self): self._changed = True
def notify(self, arg=None):
if not self._changed: return
for o in list(self._obs): o.update(self, arg)
self._changed = False
class Obs:
def update(self, source, arg):
print('got', arg)
o=Observable(); o.add_observer(Obs()); o.set_changed(); o.notify('x')
got x
using System;
class Program {
static event Action OnMsg;
static void Main(){
OnMsg += s => Console.WriteLine(s);
OnMsg?.Invoke("hi");
}
}
hi
package main
import "fmt"
func main(){
ch := make(chan string)
go func(){
for m := range ch { fmt.Println(m) }
}()
ch <- "msg"
close(ch)
}
msg
import kotlin.properties.Delegates
var p: Int by Delegates.observable(0) { prop, old, new ->
println("$old -> $new")
}
fun main(){ p = 5 }
0 -> 5
Отличия от Java Observable: в языках обычно есть более современные или встроенные механизмы событий (делегаты, каналы, Rx-подходы), и они чаще не помечены устаревшими.
Типичные ошибки при использовании notifyObservers()
- Отсутствие setChanged() - самый распространённый промах; notifyObservers не оповестит наблюдателей, если флаг изменения не установлен. Пример выше (Demo2) иллюстрирует это.
- Ожидание возврата значения - notifyObservers возвращает void; для получения ответов от наблюдателей требуется собственный протокол (например, callback-схема или Future).
- Изменение списка наблюдателей во время оповещения - прямые модификации списка наблюдателей внутри update могут приводить к неожиданному поведению; Observable создаёт копию списка перед вызовами, но кастомные реализации могут быть уязвимы.
- Передача изменяемых объектов - если передаётся мутабельный объект, все наблюдатели получают ссылку на один экземпляр; изменение аргумента в одном наблюдателе повлияет на остальных.
- Многопоточность - хотя Observable синхронизирован, логика в update может блокировать; долгие операции в update блокируют поток уведомления. В таких случаях стоит делегировать обработку в отдельную задачу.
- Использование устаревшей API - Observable/Observer помечены deprecated; начинать новый проект с них не рекомендуется.
Пример ошибки: ожидание результата от наблюдателя.
// Ожидание значения (не сработает на базе notifyObservers)
// Не существует стандартного механизма возврата результата через notifyObservers()
(нет вывода; необходимость собственной схемы ответов)
Изменения и статус API
- Класс java.util.Observable и интерфейс java.util.Observer помечены как устаревшие (deprecated) в Java 9. Причина: ограниченная гибкость, синхронизированный подход и плохая интеграция с современными реактивными моделями.
- Никаких существенных изменений в поведении notifyObservers в поздних версиях Java не вводилось; вместо этого рекомендовано использовать современные альтернативы: Flow API, SubmissionPublisher, PropertyChangeSupport или сторонние реактивные библиотеки.
- Для новых проектов рекомендуется выбирать API, соответствующий требованиям: синхронные простые уведомления - PropertyChangeSupport или пользовательские listener'ы; асинхронные и потоковые сценарии - Flow/Rx.
Расширенные и редкие варианты применения
Пример A. Асинхронная доставка уведомлений за пределы notifyObservers: делегирование выполнения в отдельный Executor, чтобы не блокировать поток, вызывающий notifyObservers.
import java.util.*;
import java.util.concurrent.*;
class AsyncObservable extends Observable {
private final Executor exec = Executors.newCachedThreadPool();
public void notifyObserversAsync(Object arg) {
if (!hasChanged()) return;
List obs;
synchronized (this) {
obs = new ArrayList<>(this.countObservers()>0 ? Collections.list(new Vector<>(Arrays.asList()).elements()) : Collections.emptyList());
//Прямой доступ к списку наблюдателей в Observable защищён, но для демонстрации используется копирование.
clearChanged();
}
// в реальном коде следует получить копию через API или переопределить хранение наблюдателей
for (Observer o : obs) {
exec.submit(() -> o.update(this, arg));
}
}
}
// Использование ниже опущено из-за громоздкости примера
(выполнение update в пуле потоков; вывод зависит от реализации наблюдателей)
Пример B. Миграция с Observable на PropertyChangeSupport для отслеживания конкретного свойства.
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class BeanWithPCS {
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private int value;
public void addListener(PropertyChangeListener l){ pcs.addPropertyChangeListener(l); }
public void removeListener(PropertyChangeListener l){ pcs.removePropertyChangeListener(l); }
public void setValue(int v){
int old = this.value; this.value = v;
pcs.firePropertyChange("value", old, v);
}
}
// При добавлении слушателя метод update будет получать старое и новое значение
value изменилось: old -> new (в зависимости от слушателя)
Пример C. Кастомная реализация с возвратом результатов от наблюдателей: сбор ответов и объединение.
import java.util.*;
interface ResObserver { Object update(Object arg); }
class ResObservable {
private final List obs = new ArrayList<>();
void add(ResObserver o){ obs.add(o); }
List
["ok:x"]
Пример D. Использование Flow API как современная альтернатива для back-pressure-aware передачи событий.
import java.util.concurrent.SubmissionPublisher;
public class FlowDemo {
public static void main(String[] args) throws Exception {
try (SubmissionPublisher pub = new SubmissionPublisher<>()) {
pub.subscribe(new java.util.concurrent.Flow.Subscriber<>() {
private java.util.concurrent.Flow.Subscription sub;
public void onSubscribe(java.util.concurrent.Flow.Subscription s){ sub = s; s.request(1); }
public void onNext(String item){ System.out.println("got: " + item); sub.request(1); }
public void onError(Throwable t){}
public void onComplete(){}
});
pub.submit("a");
Thread.sleep(100);
}
}
}
got: a
Комментарии к расширенным вариантам:
- Асинхронные вызовы обеспечивают немедленное возвращение инициатору, но требуют обработки ошибок и синхронизации результатов.
- PropertyChangeSupport удобен при необходимости передачи старого и нового значений свойства.
- Flow API и Rx-подходы обеспечивают гибкое управление скоростью передачи и обработкой ошибок.
джава Observable.notifyObservers() function comments
- джава Observable.notifyObservers() - аргументы и возвращаемое значение
- Функция java Observable.notifyObservers() - описание
- Observable.notifyObservers() - примеры
- Observable.notifyObservers() - похожие методы на java
- Observable.notifyObservers() на javascript, c#, python, php
- Observable.notifyObservers() изменения java
- Примеры Observable.notifyObservers() на джава