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

C#-Like Events For Java

4.86/5 (8 votes)
28 Aug 2016CPOL3 min read 19K  
Simplifying Java events

Introduction

I was thrilled by the release of Java 8 so much. I have been waiting for features like Lambda expressions and streams for long as I am working with both C# and Java and these features have been supported in C# since a while. Unfortunately, I found a simple and efficient way for declaring events in classes is still missing. Don't get me wrong, I am not claiming that there are no event handling Java. Both have their own techniques based on Observable design pattern. I just expected to find in Java 8 an efficient and simple way to declare events and be able to register their handlers like C#.

There is a subtle difference between both techniques that gives the edge for C# in my opinion. In Java, the common technique is to consider the class which the events belongs to, as the observed subject. In C#, the event declared by the class is the observed subject and not the class. This makes the logic of keeping a list of event handlers and notifying them encapsulated in the event object itself and not in the class the events belong to. This reduces the effort of declaring an event in your class and achieves Single Responsibility Design Principle.

Because of this, I created some classes to declare events and assign handlers to them like in C# which makes handling events, a breeze. I use them with every class to declare events. Before we see them, keep in mind that we are trying to do the following:

  • Declaring events inside some class in a simple way
  • Being able to bind multiple listeners or handlers for the same event
  • Event logic should be written once and used many times
  • Event logic doesn't belong to the class declaring the event

The classes can be downloaded from here and are described below:

  • EventArgs: The class that holds the augments or the information about the event. For any information that needs to be shared about the event to its handlers, a new event argument class is to be created holding the required information and extending EventArgs class.
  • IEventHandler<T extends EventArgs>: The interface to be implemented by the event handler of this event.
  • IEvent<T extends EventArgs>: A generic interface for the event. It declares the essential functionalities of the event.
  • Event<T extends EventArgs>: The default implementation for the Event which encapsulates the logic of keeping records of the registered event handlers and notifying them all upon firing the event.

Example

Now, let's see an example of an email client class that needs to declare two events. The first is message received event and the second is connection lost event. For the latter, we don't need any further information about the event other than its occurrence. The declaration of this event inside this class will be like the following:

Java
public final IEvent<EventArgs> ConnectionLostEvent = new Event<EventArgs>();

For the message received event, we need first to create MessageRcvArgs class that contains the contents of the message.

Java
class MessageRcvArgs extends EventArgs {......}

Then, the declaration of the event will be like the following:

Java
public final IEvent<MessageRcvArgs> MsgReveivedEvent = new Event<MessageRcvArgs>();

So the email client class will look like the following with two extra methods for testing the events:

Java
class EmailClient{
    
    public final IEvent<MessageRcvArgs> MsgReveivedEvent = new Event<MessageRcvArgs>();
    public final IEvent<EventArgs> ConnectionLostEvent = new Event<EventArgs>();
    
    public void testMsgRcvEvent() 
    {
        MessageRcvArgs args = new MessageRcvArgs();
        args.setSender("someone@someDomain.com");
        args.setTitle("Hello, Events");
        args.setContent("This is the message content");
        this.MsgReveivedEvent.fire(this, args);
    }
    
    public void testConnectioLostEvent()
    {
        this.ConnectionLostEvent.fire(this, EventArgs.Empty);
    }
}

Now to add event handlers for this class, we can use Lambda expression or the old way for providing immediate interface definitions. Like the following:

Java
EmailClient client = new EmailClient();

client.MsgReveivedEvent.addHandler((sender, arg) ->
{
    System.out.println("Event Sender: " + sender.toString());
    System.out.println("Message sender: " + arg.getSender());
    System.out.println("Message title: " + arg.getTitle());
    System.out.println("Message content: " + arg.getContent());
});

client.ConnectionLostEvent.addHandler(new IEventHandler<EventArgs>() {
    @Override
    public void handle(Object sender, EventArgs args) {
        System.out.println("The connection is lost");
    }
});

client.testMsgRcvEvent();
client.testConnectioLostEvent();

The output when executed will be like the following:

Java
Event Sender: EmailClient@2f92e0f4
Message sender: someone@someDomain.com
Message title: Hello, Events Message
content: This is the message content The connection is lost

So whenever you need to add a new event, you just need to create its event arguments class and then declare the event directly.

License

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