简体   繁体   中英

Variable arguments with different types?

I have a List of event listeners in my code:

private List<EventListener> listeners = new ArrayList<EventListener>();
listeners.add(new EventListener() {
    @Override
    public void someEvent(String arg1, MyClass arg2) {
        // ...
    }

    @Override
    public void someOtherEvent(AnotherClass arg1, int arg2) {
        // ...
    }
}

Currently, I am calling the listeners using a for loop:

for (EventListener listener : listeners) {
    listener.someEvent("Hello world", (MyClass) myObject);
}

I would like to call it using a single method, like this:

fireEvent("someEvent", "Hello world", (MyClass) myObject);

Or possibly an array or something for the event arguments.

One way to do this would be to create some sort of event object, but I don't particularly want to do this as it seems messy (someone tell me if I'm wrong here; I'm inexperienced with Java). Is there a way to create a fireEvent similar to above? EventListener is an interface, if that helps.

Theoretically, you can do this using java reflection:

public void fireEvent(String name, Object... args) {
    Method method = null;
    // 1. find method
    for (Method m : EventListener.class.getMethods()) {
        if (m.getName().equals(name)) {
            method = m;
            break;
        }
    }

    if (method == null) {
        throw new IllegalArgumentException("Unknown event method: " + name);
    }

    // 2. call method on all listeners
    for (EventListener l : listeners) {
        try {
            method.invoke(l, args);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

(Note that this is a trivial version that does not cover all eventualities like overloaded event methods etc.)

But I strongly advice do NOT do that! It's not only ugly and hard to read, it also makes your program being NOT typesafe any more! When you use the wrong name String or the wrong number or types of parameters, the compiler won't notice, but the program will break at runtime!

So I suggest to simply have one protected fireXXXEvent method for every event handler method of your listener (using a simple for loop). In your case this would be:

protected void fireSomeEvent(String arg1, MyClass arg2);
protected void fireSomeOtherEvent(AnotherClass arg1, int arg2);

Of course you can also introduce event objects (possibly by subclassing java.util.EventObject ). But this might not necessarily reduce the number of methods in your listener (but it can - depends on the types of events you've got).

There are some fancier strategies eg using a generic event handler with event type objects and generic event objects as in JavaFX, but I think this is not recommended if you're not very familiar with java.

Sidenote: Use either a CopyOnWriteArrayList for storing your listeners or iterate over a copy of listeners when firing the events otherwise you might get a ConcurrentModificationException if a listeners tries to remove itself from the listener list.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM