java 监控对集合的更改

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/553067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:50:08  来源:igfitidea点击:

Monitor changes to a collection

javaobserver-patternjavabeans

提问by willcodejavaforfood

Say you have the following java bean:

假设您有以下 java bean:

public class MyBean
{
    private List<String> names = new ArrayList<String>();

    public void addName(String name)
    {
        names.add(name);
        fireNamesPropertyChange(name);
    }
}

How would you normally implement a property change event for a collection? Do you try and use the index property which seems to be more for arrays than collections?

您通常如何为集合实现属性更改事件?您是否尝试使用似乎更适用于数组而不是集合的 index 属性?

回答by Esko

(NOTE: I updated this post after realizing a few mistakes of my own so this isn't the original but a more refined one instead)

注意:我在意识到自己的一些错误后更新了这篇文章,所以这不是原始的而是更精致的)

For this purpose I'd do two new interfaces, ListListenerand Listenableand then I would create a new class like ListenableArrayListwhich would wrap every Listmethod with a call to one (or more) relevant methods defined in ListListener. In code it'd be something like this:

为此我做了两个新的接口,ListListener并且Listenable然后我会创造一个新的类像ListenableArrayList这将每个包裹List的方法通过调用一个(或多个)中定义的相关方法ListListener。在代码中它会是这样的:

public class ListenableArrayList<T> extends ArrayList<T>
                                    implements Listenable<T> {

    private ArrayList<T> internalList;
    private ListListener<T> listener;

    /* .. */

    public void add(T item) {
        listener.beforeAdd(T item);
        internalList.add(item);
        listener.afterAdd(T item);
    }

    /* .. */

    public void setListener(ListListener<T> listener) {
        this.listener = listener;
    }

}

public interface ListListener<T> {
    /* .. */
    void beforeAdd(T item);
    void afterAdd(T item);
    /* .. */
}

public interface Listenable<T> {
    /* .. */
    void setListener(ListListener<T> listener);
    /* .. */
}

The reason I'd do it this way would be to allow for creating truly ad-hoc listeners on the fly instead of tying the ListenableArrayList to some specific implementation. For example with this the following would be possible:

我这样做的原因是允许动态创建真正的临时侦听器,而不是将 ListenableArrayList 绑定到某些特定实现。例如,以下是可能的:

Listenable<String> list = new ListenableArrayList<String>();

list.setListener(new ListListener<String>() {
    @Override
    public void beforeAdd(String item) {
        System.out.println("About to add element "+item+"...");
    }
    @Override
    public void afterAdd(String item) {
        System.out.println("...element "+item+" has been added.");
    }
});

A bit cluttered, maybe but on the other hand this would allow for easy extension to Collections, Sets and whatnot rather easily.

有点混乱,也许但另一方面,这将允许轻松扩展到集合、集合等等。

回答by Peter ?tibrany

Take a look at Glazed Listslibrary, which has support for observable collections.

看看Glazed Lists库,它支持可观察集合。

If I were to do it myself, I would likely create custom Listener interface with elementsAdded, elementsRemoved methods, or similar :-) (also depending on my needs)

如果我自己做,我可能会使用elementsAdded、elementsRemoved 方法或类似方法创建自定义侦听器界面:-)(也取决于我的需要)

回答by Scott Stanchfield

Normally I'd do the following:

通常我会做以下事情:

public class MyBean {
    private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    private List<String> names = new ArrayList<String>();
    public void addName(String name) {
        names.add(name);
        pcs.firePropertyChange("names", null, Collections.unmodifiableList(names));
    }
    public void addPropertyChangeListener(PropertyChangeListener l) {
        pcs.addPropertyChangeListener(l);
    }
    public void removePropertyChangeListener(PropertyChangeListener l) {
        pcs.removePropertyChangeListener(l);
    }
}

PropertyChangeSupport manages the listeners and fires the events on your behalf.

PropertyChangeSupport 管理侦听器并代表您触发事件。

By passing null as the "old value" it forces the event to be fired. (It's likely that listeners won't really care about the old value anyway)

通过将 null 作为“旧值”传递,它会强制触发事件。(无论如何,听众很可能不会真正关心旧值)

回答by Andrey Chaschev

JDK 7+ solution:

JDK 7+ 解决方案:

import javafx.collections.*;
import java.util.*;

public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("s1");
        list.add("s2");

        ObservableList<String> observableList = FXCollections.observableList(list);
        observableList.addListener(new ListChangeListener<String>() {
            @Override
            public void onChanged(Change<? extends String> change) {
                while(change.next()){
                    System.out.println("added: " + change.getAddedSubList());
                }
            }
        });

        observableList.add("s3");
    }
}

回答by Nick Fortescue

For a swing GUI event I'd normally just use an EventListenerListto do the work for me.

对于摆动 GUI 事件,我通常只使用EventListenerList来为我完成工作。

EDIT: on the rephrase of the questions: how do you treat collections, I'd usually use an event similar to the collections type, so for example a TreeModel event usually takes a TreePath argument, or for something in a map I'd indicate the key.

编辑:关于问题的重新表述:你如何处理集合,我通常会使用类似于集合类型的事件,因此例如 TreeModel 事件通常采用 TreePath 参数,或者对于地图中的某些内容我会指出钥匙。

However for simple JavaBeans the most common is assume a list/array and just use the index.

然而,对于简单的 JavaBeans,最常见的是假设一个列表/数组并只使用索引。

回答by Miserable Variable

Methinks you will need fireNamesPropertyAdd, fireNamesProperyDelete. A list level notification will IMHO not work, even if it was an array and an index was added as it can't handle deletes. If the element at some index can be changed, you will also need fireNamesProperyChange. It might be useful to have index as parameter in addition to the string value.

我想你会需要fireNamesPropertyAddfireNamesProperyDelete。恕我直言,列表级通知将不起作用,即使它是一个数组并且添加了一个索引,因为它无法处理删除。如果某个索引处的元素可以更改,您还需要fireNamesProperyChange. 除了字符串值之外,将索引作为参数可能很有用。

回答by Tom Hawtin - tackline

Are you perhaps looking for java.beans.PropertyChangeSupport?

您可能正在寻找java.beans.PropertyChangeSupport吗?

In my opinion, you should avoid PropertyChangeEvent. IndexedPropertyChangeEventis worse, and very infrequently used by Swing anyway. It's better to narrow the focus of your types, and fire a javax.swing.event.ChangeEventor similar (even just call a Runnable).

在我看来,你应该避免PropertyChangeEvent. IndexedPropertyChangeEvent更糟糕的是,无论如何 Swing 很少使用。最好缩小你的类型的焦点,并触发 ajavax.swing.event.ChangeEvent或类似的(甚至只是调用 a Runnable)。

For certain types (like lists!), Glazed Lists (or equivalent) mentioned in another post by Peter ?tibrany seem like a good way to go.

对于某些类型(例如列表!),Peter ?tibrany 在另一篇文章中提到的 Glazed List(或等效项)似乎是一个不错的方法。