Java中事件处理的陷阱

时间:2009-12-14 21:38:42

标签: c# java events event-handling

我正在开发一个需要Java对象才能拥有事件的程序。我非常熟悉它在C#中是如何工作的,有足够的经验来学习陷阱。

在Java中处理事件有哪些陷阱?它们与C#2.0中的事件有什么不同?

示例:对象更改了事件以提示从所有者对象进行保存。

注意:Java 1.5

相关:C# event handling (compared to Java)

5 个答案:

答案 0 :(得分:7)

Java没有内置的事件概念,所以最好使用The Observer Pattern的变体。

答案 1 :(得分:3)

在C#中,你应该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);
}

...保护自己免受并发修改(如果线程在检查MyEvent的空值并调用它之间删除了一个事件监听器)。在Java中,您使用CopyOnWriteArrayList来保护自己免受并发修改:

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);
}

答案 2 :(得分:1)

Java没有专门的Event概念。它是通过Observable + Observer行的API实现的。据我所知,Java规范中没有专用的lambda-functer API。

答案 3 :(得分:1)

如前所述,Java没有C#所拥有的delegates and events。但考虑到它是Observer pattern(GoF)的“通用”实现,您可以自己实现它。

the wikipedia page中有关于如何使用java.util.Observablejava.util.Observer实现模式的示例。一般的想法是让实现Observer的类订阅自己的Observable类。

我经常推出自己的实现,因为它很容易实现,因为你只需要创建一个接口来声明“observable”类调用它注册的“观察者”的方法。下面是一个可观察类的简单示例,它可以注册SimpleObserver个对象并对它们执行某种事件:

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)
    }

}

...这里是简单的观察者界面。

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

这可能看起来有点复杂,但好处是Observable类不需要知道其他对象正在“监听”它(这就是为什么 observers 有时被称为< EM>听众)。它提供了两者之间关注点的清晰分离。观察员需要将自己注册到一个可观察者身上。

我能想到的唯一“陷阱”是内存泄漏,即使在Java等内存管理环境中,这种模式也可能导致内存泄漏。这是因为Observers和Observables之间的“引用孤岛”会混淆垃圾收集器而不会尝试从内存中删除对象。删除未使用的观察者总是一个好主意。

答案 4 :(得分:0)

事件在Java中是严格特定于容器的,标准库仅提供通用接口(通常根据特定要求进行扩展)。

关于可以在Java(通常)的上下文中考虑的事件的唯一“问题”是Swing容器(组件)和事件调度。 swing框架是单线程的,你应该使用事件调度线程(即回调)来在事件监听器中进行计算密集型/高延迟的工作。