There are many different events, all implementing the same interface:
interface Event {}
class FooEvent implements Event {}
class BarEvent implements Event {}
Every event has a dedicated handler:
interface EventHandler<T extends Event> {
    void handle(T event);
}
class FooEventHandler implements EventHandler<FooEvent> {
    @Override
    public void handle(FooEvent event) { }
}
class BarEventHandler implements EventHandler<BarEvent> {
    @Override
    public void handle(BarEvent event) { }
}
All event handlers are created once and added to a map. Whenever an event occurs, this map should be used to find the proper event hander.
class Main {
    Map<Class<? extends Event>, EventHandler<? extends Event>> eventHandlerRegistry = Map.of(
            FooEvent.class, new FooEventHandler(),
            BarEvent.class, new BarEventHandler()
    );
    void handleEvent(Event event) {
        EventHandler<? extends Event> handler = this.eventHandlerRegistry.get(event.getClass());
        handler.handle(event); // DOES NOT COMPILE: needed=capture<? extends Event>, given=Event
    }
}
Unfortunately this last line does not compile. I can make it compile by leaving out the type parameter of EventHandler like this:
EventHandlerhandler = this.eventHandlerRegistry.get(event.getClass());
handler.handle(event); // WARNING: unchecked call to 'handle(T)' as a member of raw type 'EventHandler'
But this does not quite feel right... I am aware of PECS, but I feel kind of trapped because I produce AND consume my EventHandlers.
How can I implement this cleanly?
 
     
    