Observer Is Deprecated in Java 9. What Should We Use Instead of It

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

Why is that? Does it mean that we shouldn't implement observer pattern anymore?

Answering the latter part first -

YES, it does mean you shouldn't implement Observer and Obervables anymore.

Why were they deprecated -

They didn't provide a rich enough event model for applications. For example, they could support only the notion that something has changed, but didn't convey any information about what has changed.

Alex's answer puts it nicely upfront that Observer has a weakness: all Observables are the same. You have to implement the logic that is based on instanceof and cast object to concrete type into Observable.update() method.

To add to it there were bugs like one could not serialize the Observable class because as it didn't implement Serializable interface and all of its members were private.

What is a better alternative to that?

On the other hand Listeners have a lot of types and they have callback methods and don't require casting. As pointed by @Ravi in his answer you can make use of PropertyChangeListener instead.

For the rest of it the @Deprecation has been marked with proper documentation to explore other packages as linked in other answers as well.


Note that the deprecation was also marked with an analysis as stated in this mail -

These days, anyone encountering these is probably hitting them by
mistake while using RxJava or other reactive-stream frameworks. In
which case, users will normally want to instead use the jdk9
java.util.concurrent.Flow APIs that all reactive-streams frameworks
should be compatible/interoperable within their planned upcoming
jdk9-compatible versions.

Edit: It's also worth mentioning that the deprecation of the APIs is not primarily just because of the above reason, but also being unable to maintain such legacy code as mentioned in comments of a few of the bug reports (linked above) which were raised to mark an improvement in its implementation in one or another way.

Observer and Observable got deprecated and the reason stated is: they convey something has changed but not state what has changed, this is false?

But I was able to tell the observer that news has changed then. How that above statement is true?

The text from the issue tracker link says:

"For example, they support only the notion that something has changed, but they don't convey any information about what has changed."

In your example, the update method call tells the observer that something has changed, but not what actually changed. So, when you call setNews("Yo"), the indiaNews observer is told that newsAgency has changed. But it is NOT told what the change was. The observer can use the news argument to see the current state of the newsAgency, but there is no way to see what the state was before the change, or indeed what it was immediately after the change1.

In many use cases for Observer / Observable, the application needs to know what actually changed to trigger the update call.

THAT is the deficiency that being highlighted, and it is one of the reasons for the deprecation. The deprecation text in the javadocs list others as well:

"This class and the Observer interface have been deprecated. The event model supported by Observer and Observable is quite limited, the order of notifications delivered by Observable is unspecified, and state changes are not in one-for-one correspondence with notifications. For a richer event model, consider using the java.beans package. For reliable and ordered messaging among threads, consider using one of the concurrent data structures in the java.util.concurrent package. For reactive streams style programming, see the Flow API."


1 - Since the order of notification delivery is unspecified, the state of the observed object could have changed again by the time that the update call occurs.

Alternative to Java's Observable class?

Usually the observer pattern is implemented with an ad-hoc solution when ever it's needed. When it comes to behavioral patterns it's one of the simplest: two methods to control a list of "observers," and one method that notifies the observers when something interesting happens.

The observer pattern tends to arise too infrequently outside of certain domains, and when it does arise it tends be too specific to the application domain, so generic solutions are of little value. You can see the problem with the java.util.Observable class: if you inherit from Observable you have to accept every possible kind of "observer" that may be passed to you, which likely makes no sense for your application:

  • What if your object can produce two different kinds of events, and thus needs two different lists of observers?
  • What if the observers may influence your object depending on the event, e.g. by being able to veto a change?

That said, EventBus from Google Guava seems to do a pretty good job of simplifying event producing and handling by taking a radically different approach.

Other techniques based on annotations have been discussed on SO before.

Why should the observer pattern be deprecated?

Quoting directly from the paper:

To illustrate the precise problems of the observer pattern,
we start with a simple and ubiquitous example: mouse dragging.
The following example traces the movements of the
mouse during a drag operation in a Path object and displays
it on the screen. To keep things simple, we use Scala closures
as observers.

var path: Path = null
val moveObserver = { (event: MouseEvent) =>
path.lineTo(event.position)
draw(path)
}
control.addMouseDownObserver { event =>
path = new Path(event.position)
control.addMouseMoveObserver(moveObserver)
}
control.addMouseUpObserver { event =>
control.removeMouseMoveObserver(moveObserver)
path.close()
draw(path)
}

The above example, and as we will argue the observer
pattern as defined in [25] in general, violates an impressive
line-up of important software engineering principles:

Side-effects Observers promote side-effects. Since observers
are stateless, we often need several of them to simulate
a state machine as in the drag example. We have to save
the state where it is accessible to all involved observers
such as in the variable path above.

Encapsulation As the state variable path escapes the scope
of the observers, the observer pattern breaks encapsulation.

Composability Multiple observers form a loose collection
of objects that deal with a single concern (or multiple,
see next point). Since multiple observers are installed at
different points at different times, we can’t, for instance,
easily dispose them altogether.

Separation of concerns The above observers not only trace
the mouse path but also call a drawing command, or
more generally, include two different concerns in the
same code location. It is often preferable to separate the
concerns of constructing the path and displaying it, e.g.,
as in the model-view-controller (MVC) [30] pattern.

Scalablity We could achieve a separation of concerns in our
example by creating a class for paths that itself publishes
events when the path changes. Unfortunately, there is no
guarantee for data consistency in the observer pattern.
Let us suppose we would create another event publishing
object that depends on changes in our original path, e.g.,
a rectangle that represents the bounds of our path. Also
consider an observer listening to changes in both the
path and its bounds in order to draw a framed path. This
observer would manually need to determine whether the
bounds are already updated and, if not, defer the drawing
operation. Otherwise the user could observe a frame on
the screen that has the wrong size (a glitch).

Uniformity Different methods to install different observers
decrease code uniformity.

Abstraction There is a low level of abstraction in the example.
It relies on a heavyweight interface of a control
class that provides more than just specific methods to install
mouse event observers. Therefore, we cannot abstract
over the precise event sources. For instance, we
could let the user abort a drag operation by hitting the escape
key or use a different pointer device such as a touch
screen or graphics tablet.

Resource management An observer’s life-time needs to be
managed by clients. Because of performance reasons,
we want to observe mouse move events only during a
drag operation. Therefore, we need to explicitly install
and uninstall the mouse move observer and we need to
remember the point of installation (control above).

Semantic distance Ultimately, the example is hard to understand
because the control flow is inverted which results
in too much boilerplate code that increases the semantic
distance between the programmers intention and
the actual code.

[25] E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design
patterns: elements of reusable object-oriented software.
Addison-Wesley Longman Publishing Co., Inc., Boston, MA,
USA, 1995. ISBN 0-201-63361-2.

Is Flow API replacing Observer and Observable

The new Flow API is designed as a common denominator for reactive stream libraries like RxJava and Reactive X. Building on Java 9, they can have their types extend the new interfaces (or so the thought goes). While it is of course charming to use the API inside the JDK, that is not the case in Java 9 and there are no concrete plans to introduce it (to the best of my knowledge).

Regarding Observer and Observable the issue which triggered the deprecation states:

Application developers should consider using java.beans for a richer change notification model. Or they should consider constructs in java.util.concurrent such as queues or semaphores to pass messages among threads, with reliable ordering and synchronization properties.

These are recommendations for application developers for writing new code. It gives no advice on updating existing code or what to do inside the JDK. I guess the reason for that is that both cases are supposed to stay as they are.

Note that Java does not use @Deprecated to necessarily mean "will be removed". Instead it can also mean "use better alternatives" and I think that is the case here. So to answer your question in a few words:

In Java 9 does Flow API replace Observer and Observable

No.

and if it doesn't what does.

Nothing.

Subscribe is deprecated: Use an observer instead of an error callback

subscribe isn't deprecated, only the variant you're using is deprecated. In the future, subscribe will only take one argument: either the next handler (a function) or an observer object.

So in your case you should use:

.subscribe({
next: this.handleUpdateResponse.bind(this),
error: this.handleError.bind(this)
});

See these GitHub issues:

  • https://github.com/ReactiveX/rxjs/pull/4202

  • https://github.com/ReactiveX/rxjs/issues/4159

When should we use Observer and Observable?

You have a concrete example of a Student and a MessageBoard. The Student registers by adding itself to the list of Observers that want to be notified when a new Message is posted to the MessageBoard. When a Message is added to the MessageBoard, it iterates over its list of Observers and notifies them that the event occurred.

Think Twitter. When you say you want to follow someone, Twitter adds you to their follower list. When they sent a new tweet in, you see it in your input. In that case, your Twitter account is the Observer and the person you're following is the Observable.

The analogy might not be perfect, because Twitter is more likely to be a Mediator. But it illustrates the point.

How to observe different attributes of same types with the Observer pattern?

The first argument in the update method is an Observable. That is your UserModel object that has changed, so it contains all the updated data. So instead of using the second parameter to pass the new value of an object you can use it to pass the name of the object that has changed (or use an enum because it's a bit cleaner).

A solution could look like this:

UserBean:

import java.util.Observable;
import java.util.Observer;

import observer.UserModel.ChangedValue;

public class UserBean implements Observer {

private Integer userId;
private String userName;
private String userEmail;
/* getters and setters */

@Override
public void update(Observable o, Object object) {
if (o instanceof UserModel && object instanceof ChangedValue) {
UserModel userModel = (UserModel) o;
ChangedValue changed = (ChangedValue) object;

switch (changed) {
case EMAIL:
setEmail(userModel.getEmail());
break;
case ID:
setUserId(userModel.getId());
break;
case NAME:
setUserName(userModel.getName());
break;
default:
throw new IllegalStateException("Unexpected ChangedValue type: " + changed);

}
}
}

//...
}

UserModel:

import java.util.Observable;

public class UserModel extends Observable {

public enum ChangedValue {
ID, //
NAME, //
EMAIL, //
//...
}

private Integer id;
private String name;
private String email;

//...

public void setId(Integer id) {
this.id = id;
setChanged();
notifyObservers(ChangedValue.ID);//use the enum types as parameters here
}

public void setName(String name) {
this.name = name;
setChanged();
notifyObservers(ChangedValue.NAME);
}

public void setEmail(String email) {
this.name = email;
setChanged();
notifyObservers(ChangedValue.EMAIL);
}
}

Note: Like mentioned in the comments a generic approach would be better, to avoid the object casts. It could be used similar to this implementation. Just add some generic parameters, but the idea stays the same.



Related Topics



Leave a reply



Submit