views:

316

answers:

6

I'm working on a program that needs a Java object to have an event. I'm quite familiar with how this works in C#, having had enough experience to learn the pitfalls.

What are the pitfalls of working with events in Java? How are they different from events in C# 2.0?

Example: An object changed event to prompt a save from the owner object.

Note: Java 1.5

Related: C# event handling (compared to Java)

+7  A: 

Java has no built-in concept of events, so you are best off using variations of The Observer Pattern.

matt b
+1  A: 

Java doesn't have a dedicated concept of Event. It's implemented through APIs along the lines of Observable + Observer. As far as I know, there is no dedicated lambda-functer API in the Java specification.

Romain
A: 

Events are strictly container specific in Java, and the standard library merely provides a generalized interface (which is typically extended for specific requirements).

The only 'gotcha' regarding events that can arguably be considered in context of Java (in general) is in Swing containers (Component) and event dispatching. The swing framework is single-threaded and you are expected to not use the event dispatch thread (i.e. the call back) to do computationally intensive/high-latency work in the event listener.

+3  A: 

In C#, you're supposed to do like this when you fire an event:

public event SomeDelegate MyEvent;

private void FireMyEvent(MyEventArgs args)
{
    var deleg = MyEvent;
    if (deleg != null) deleg(args);
}

... to protect yourself from concurrent modification (in case a thread removes an event listener between you checking the nullness of MyEvent and calling it). In Java, you'd use a CopyOnWriteArrayList instead to protect yourself from concurrent modification:

private final CopyOnWriteArrayList<MyEventListener> listeners = 
    new CopyOnWriteArrayList<MyEventListener>();

private void fireMyEvent(MyEventArgs args){
    // Iteration is performed over a snapshot of the list, concurrent
    // modifications from other threads are invisible to the iterator
    // and will not cause ConcurrentModificationExceptions.
    for (MyEventListener listener : listeners)
        listener.eventOccurred(args);
}
gustafc
A: 

This is a link on how to create custom events in Java, at least the article says so... link

:)

ultrajohn
+1  A: 

As mentioned earlier, Java doesn't have delegates and events that C# has. But considering it's a "generalized" implementation of the Observer pattern (GoF) you can implement it on your own.

There are examples in the wikipedia page on how to implement the pattern with java.util.Observable and java.util.Observer. The general idea is to let classes that implement Observer to subscribe themselves to an Observable class.

I usually roll my own implementation since it is darn easy to do so, as you only need to make an interface declaring the methods that the "observable" class call to it's registered "observers". Here is a simple example of an observable class that can register SimpleObserver objects and perform some kind of event on them:

public class MyObservableClass {

    List<SimpleObserver> observers = new ArrayList<SimpleObserver>();

    /**
     * Registers the observer
     */
    public void addObserver(SimpleObserver observer) {
        observers.add(observer);
    }

    /**
     * Removes the registered observer (to be nice towards the
     * garbage collector).
     */
    public void removeObserver(SimpleObserver observer) {
        observers.remove(observer);
    }

    /**
     * Notifies the observers with the given data
     */
    private void notifyObservers(String data) {
        for(SimpleObserver o : observers) {
            o.onEvent(data);
        }
    }

    public void doSomething() {
        // Do some stuff
        String data = "Waffles and pwnies";
        // Notify the observers that something happened.
        notifyObservers(data)
    }

}

…and here is the simple observer interface.

public interface SimpleObserver {
    void onEvent(String data);
}

This may seem a bit complex, but the benefit is that the Observable class doesn't need to know what exact other objects are "listening" to it (which is why observers are sometimes called listeners). It provides a clean separation of concerns between them both. The Observers need to register themselves to an observable.

The only "gotcha" that I can think of is that of a memory leak that this pattern may cause even in a memory managed environment such as Java. This is because of the "reference islands" between Observers and Observables which will confuse the garbage collector and not attempt to remove the objects from memory. It is always a good idea to remove unused observers.

Spoike
Watch out in a multi threaded scenario as it's not thread safe. The list of observers could change whilst it is being iterated over resulting in a `ConcurrentModificationException`. Most newer implementations of this pattern use the `CopyOnWriteArrayList` instead of 'ArrayList'
pjp