Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

C# Like Event Handlers Pattern in Java

5.00/5 (3 votes)
26 Mar 2017CPOL1 min read 12.9K  
Simulating C# event handlers in Java

Introduction

For those of us who come from the C# world, sometimes it can be a bit difficult to deal with the way events are handled in Java with listeners. This pattern is implemented to solve that problem in a familiar way to .NET.

Background

A few weeks ago, for work reasons, I had to go to the Java world and leave behind .NET. Everything was fine until I had to face the listeners, although it is a fairly interesting (observer) pattern at times that can be a bit cumbersome. For this, I solved my problem in this way (implementing a pattern similar to the C # eventhandlers), although it is a solution that may not necessarily be definitive but could serve you on more than one occasion.

Using the Code

Thanks to @FunctionalInterfaces, it is possible to build a kind of .NET delegate.

What is a functional interface?

Java
@FunctionalInterface
public interface IEvent<TEventArgs extends Object> {
    void invoke(Object source, TEventArgs eventArgs);
}

Now, we can define a reutilizable EventHandler class for event manage:

Java
public class EventHandler<TEventArgs>
{
    private ArrayList<IEvent<TEventArgs>> eventDelegateArray = new ArrayList<>();
    public void subscribe(IEvent<TEventArgs> methodReference)
    {
        eventDelegateArray.add(methodReference);
    }
    public void unSubscribe(IEvent<TEventArgs> methodReference)
    {
        eventDelegateArray.remove(methodReference);
    }
    public void invoke(Object source, TEventArgs eventArgs)
    {
        if (eventDelegateArray.size()>0)
            eventDelegateArray.forEach(p -> p.invoke(source, eventArgs));
    }
    public void close()
    {
        if (eventDelegateArray.size()>0)
            eventDelegateArray.clear();
    }
}

This EventHanlder class allows us to subscribe, un-subscribe, invoke, clean up resources of our defined event.

For purposes of testing our code, we will create an event producing class and a consumer class (subscriber) of our event.

Java
public class DummyEventProducer
{
    // The event
    public EventHandler<String> myEvent = new EventHandler<>();

    public void onMyEvent(String A)
    {
        myEvent.invoke(this, A);
    }
}
Java
public class DummySubscriber {

    // The method will be subscribed to the event
    public void methodCallWhenEventGetTriggered(Object source, String eventArgs)
    {
        System.out.println("event fired with eventargs: " + eventArgs);
    }
}

Now the main entry point of our test app:

Java
public class Main {

    public static void main(String[] args)
    {
        // A dummy producer
        DummyEventProducer producer = new DummyEventProducer();

        // A dummy subscribers
        DummySubscriber testingInstanceA = new DummySubscriber();
        DummySubscriber testingInstanceB = new DummySubscriber();
        DummySubscriber testingInstanceC = new DummySubscriber();

        // We create weak event references because we want to un-subscribe later
        IEvent<String> EventSink1 = 
        	testingInstanceA::methodCallWhenEventGetTriggered;
        IEvent<String> EventSink2 = 
        	testingInstanceB::methodCallWhenEventGetTriggered;
        IEvent<String> EventSink3 = 
        	testingInstanceC::methodCallWhenEventGetTriggered;

        // subscribe to the event on dummy producer
        producer.myEvent.subscribe(EventSink1);
        producer.myEvent.subscribe(EventSink2);
        producer.myEvent.subscribe(EventSink3);

        // fire the event on producer
        producer.onMyEvent("Hola MUNDO with decoupled subscriptions!");

        // unsubscribe to the event on dummy producer
        producer.myEvent.unSubscribe(EventSink1);
        producer.myEvent.unSubscribe(EventSink2);
        producer.myEvent.unSubscribe(EventSink3);

        // fire the event on producer again
        producer.onMyEvent("Hola MUNDO! with no events subscriptions :(");

        // IF YOU DON CARE ABOUT UNSUBSCRIBE 
        // YOU CAN CREATE STRONG EVENTS REFERENCES DIRECTLY TO THE SUBSCRIBER
        producer.myEvent.subscribe(testingInstanceA::methodCallWhenEventGetTriggered);
        producer.myEvent.subscribe(testingInstanceB::methodCallWhenEventGetTriggered);
        producer.myEvent.subscribe(testingInstanceC::methodCallWhenEventGetTriggered);

        // fire the event on producer again
        producer.onMyEvent("Hola MUNDO! with strong references 
                           subscriptions (cannot be un-subscribed one by one");

        // clear all subscriptions
        producer.myEvent.close();

        // fire the event on producer again
        producer.onMyEvent("Hola MUNDO! again");
    }
}

And that's it! I hope it will be useful for you.

Points of Interest

I do not recommend using strong references as they can generate memory leaks, but instead, try to use weak references, especially when it comes to events.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)