I have several types of events, for example:abstract class Event {    static class KeyPress extends Event { ... }    static class KeyRelease extends Event { ... }    static class KeyHold extends Event { ... }    // ...}And many listeners which respond to some of the above events by registering them in an event handler. It looks like this currently:abstract class AbstractListener {    Set<Class<? extends Event>> eventTypes;    protected abstract boolean respond(Event event);}class DownKeyListener exteneds AbstractListener {    DownKeyListener () {        // just prepares to register to receive these events. doesn't matter how exactly.        eventTypes.add(KeyPress.class);        eventTypes.add(KeyHold.class);        //no KeyRelease e.g.    }    boolean respond(Event event) {        if (event instanceof KeyPress)            return handleKeyPress(event);        else if (event instanceof KeyHold)            return handleKeyHold(event);        return false;    }    private boolean handleKeyPress(KeyPress e) { ... }    private boolean handleKeyHold(KeyHold e) { ... }}What I don't like about this is that there is nothing forcing or checking at least the relation between the registered events and the checks for them and handling in the respond method. This keeps leading to developer bugs. it's also a lot of code with instanceofs for little benefit (I would say).So I though about doing something smart like this: create a map between the event types and the handlers so each event that is registered for handling will have a handler:abstract class AbstractListener {    Map<Class<? extends Event>, Function<? extends Event, Boolean> map = new ...    //             ^ doesn't ensure these event ^: are the same but at least    //                                             that someone responds    // to ensure same event i can do    protected <T extends Event> void register(Class<T> event, Function<T, Boolean> function) {        map.put(event, function);    }    protected abstract boolean respond(Event event);}And then:class DownKeyListener exteneds AbstractListener {    DownKeyListener () {        Map.put(KeyPress.class, keyPressFunction);        Map.put(KeyHold.class, keyHoldFunction);    }    boolean respond(Event event) {        Function<? extends Event, Boolean> f = map.get(event.getClass());        return f == null ? false : f.apply(event);    }    Function<KeyPress, Boolean> keyPressFunction = event -> ...;    Function<KeyHold, Boolean> keyHoldFunction = event -> ...;}Of course this doesn't work because of generics. apply gives an error and I understand whyThe method apply(capture#4-of ? extends Event) in the type Function<capture#4-of ? extends Event,Boolean> is not applicable for the arguments (capture#5-of ? extends Event)I don't know how to get what I want working correctly. Some things I had in mind:Cast the result of map.get to something that will ensure it works properlyChange the respond method to be generic protected abstract <T extends Event> boolean respond(T event); which give the similar error:The method apply(capture#3-of ? extends Event) in the type Function<capture#3-of ? extends Event,Boolean> is not applicable for the arguments (T)Anyone has a suggestion on achieving what I want in any way?
How to ensure a method handling each event in an event system?
java;design;event programming;generics
I figured it out using my generics approach. My second point about changing respond to a generic <T extends Event> boolean respond(T event) was indeed the right approach. The compiler error for incompatible types can be solved with a dirty but safe cast. Here is the full working codepublic class Test {    public static void main(String[] args) {        DownKeyListener dkl = new DownKeyListener();        System.out.println(dkl.respond(new KeyPress()));        System.out.println(dkl.respond(new KeyHold()));        System.out.println(dkl.respond(new KeyRelease()));    }}abstract class Event {    static class KeyPress extends Event {}    static class KeyHold extends Event {}    static class KeyRelease extends Event {}}abstract class AbstractListener {    private Map<Class<? extends Event>, Function<? extends Event, Boolean>> map = new HashMap<>();    protected <T extends Event> void register(Class<T> event, Function<T, Boolean> function) {        map.put(event, function);    }    <T extends Event> boolean respond(T event) {        Function<? extends Event, Boolean> f = map.get(event.getClass());        return f == null ? false : ((Function<T, Boolean>) f).apply(event);    }}class DownKeyListener extends AbstractListener {    DownKeyListener() {        register(KeyPress.class, keyPressHandler);        register(KeyHold.class, keyHoldHandler);    }    Function<KeyPress, Boolean> keyPressHandler = e -> true;    Function<KeyHold, Boolean> keyHoldHandler = e -> true;}The output of running this istrue  true  falseas required.There are 3 things i want to point out about this approach.The first is the ease of use and compile time safety. It couples the event registering (the list of event to listen to which in this cases is the map's keys) and the event handling. For every event type which is registered a handler for that event type must be given and when the listener needs to respond to an event that same handler is used. Creating a new event type does not entail any additional work like visitor methods or new interfaces. It is created and if some listener wants to use it it's ready.The second thing is that the respond method can be moved to the abstract superclass because it has the same behavior for all listeners: get the handler for the event, call it and return the result. If a subclass listener wants to change this for a specific event type they can override it, check the event type and for the rest call super.The third thing is that cast and the loss of information between putting the event-function in the map and getting the function from the event. The map is declared with 2 wildcards with no way to force a relation between them as far as i know. this is because of the lack of generic fields in java. if such a thing ever came to exist it would simplify this approach. The forcing of the same types for the event and its handler is done in the register method which adds to the map but that enforcement is lost in the field declaration. That means that when getting the value from the key there is no more compile time correspondence and a cast has to be made to the same type. We know this cast is safe if we only used the register method to populate the map otherwise we're doomed. a generic field would eliminate the need for a safe cast.That's it. I learned a lot from the different answers and my fighting with Java generics and I post here verbosely for the benefit of everyone else. Hopefully this helps someone else in the future.