【问题标题】:Pitfalls of Event Handling in JavaJava中事件处理的陷阱
【发布时间】:2009-12-14 21:38:42
【问题描述】:

我正在开发一个需要 Java 对象才能产生事件的程序。我非常熟悉它在 C# 中的工作原理,并且有足够的经验来了解其中的陷阱。

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

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

注意:Java 1.5

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

【问题讨论】:

    标签: c# java events event-handling


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        the wikipedia page 中有关于如何使用java.util.Observablejava.util.Observer 实现模式的示例。一般的想法是让实现Observer 的类自己订阅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 称为 听众)。它在两者之间提供了一个清晰的关注点分离。观察者需要将自己注册到可观察对象。

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

        【讨论】:

          【解决方案4】:

          Java 没有专门的事件概念。它是通过 API 实现的,类似于 Observable + Observer。据我所知,Java 规范中没有专门的 lambda-functer API。

          【讨论】:

            【解决方案5】:

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

            关于事件的唯一“陷阱”可以说是在 Java 上下文中(通常)是在 Swing 容器(组件)和事件分派中。 swing 框架是单线程的,您应该使用事件调度线程(即回调)在事件侦听器中执行计算密集/高延迟的工作。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-11-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多