214

I want to do something like this in Java but I don't know the way:

When event "object 1 say 'hello'" happens, then object 2 responds to that event by saying "hello".

Can somebody give me a hint or sample code?

JDJ
4,3363 gold badges28 silver badges45 bronze badges
asked Jun 7, 2011 at 18:48
2

7 Answers 7

457

You probably want to look into the observer pattern.

Here's some sample code to get yourself started:

import java.util.*;
// An interface to be implemented by everyone interested in "Hello" events
interface HelloListener {
 void someoneSaidHello();
}
// Someone who says "Hello"
class Initiater {
 private List<HelloListener> listeners = new ArrayList<HelloListener>();
 
 public void addListener(HelloListener toAdd) {
 listeners.add(toAdd);
 }
 
 public void sayHello() {
 System.out.println("Hello!!");
 
 // Notify everybody that may be interested.
 for (HelloListener hl : listeners)
 hl.someoneSaidHello();
 }
}
// Someone interested in "Hello" events
class Responder implements HelloListener {
 @Override
 public void someoneSaidHello() {
 System.out.println("Hello there...");
 }
}
class Test {
 public static void main(String[] args) {
 Initiater initiater = new Initiater();
 Responder responder = new Responder();
 
 initiater.addListener(responder);
 
 initiater.sayHello(); // Prints "Hello!!!" and "Hello there..."
 }
}
blackgreen
46.2k29 gold badges167 silver badges159 bronze badges
answered Jun 7, 2011 at 18:50
10
  • 2
    What if multiple threads are generating the source events, will this be synchronized properly ? Commented Nov 5, 2012 at 5:18
  • Depends on the siruation. Each listener will be notified according to the order they registered. (Btw, I don't understand what you mean by multiple threads here. The listener code will be exectued on the same thread that caused the event to occur.) Commented Nov 5, 2012 at 8:20
  • 1
    Does java have no built in thing for this? I would really prefer to do do this in abstract pattern, not implement for loop for every event. Commented Jan 9, 2016 at 2:41
  • @TomášZato, you can use Observer/Observable but those classes are from Java 1.0 and uses Object so you'd probably end up with some casts in your code. Also, listeners.forEach(HelloListener::someoneSaidHello) could be an option if you just don't like the looping. Commented Jan 9, 2016 at 7:43
  • 1
    As java.util.Observer got deprecated from Java 9 would there be any better option in implementing custom event? Commented Jun 16, 2020 at 20:51
29

What you want is an implementation of the observer pattern. You can do it yourself completely, or use java classes like java.util.Observer and java.util.Observable

answered Jun 7, 2011 at 18:51
1
22

There are 3 different ways you may wish to set this up:

  1. Thrower inside of Catcher
  2. Catcher inside of Thrower
  3. Thrower and Catcher inside of another class in this example Test

THE WORKING GITHUB EXAMPLE I AM CITING Defaults to Option 3, to try the others simply uncomment the "Optional" code block of the class you want to be main, and set that class as the ${Main-Class} variable in the build.xml file:

4 Things needed on throwing side code:

import java.util.*;//import of java.util.event
//Declaration of the event's interface type, OR import of the interface,
//OR declared somewhere else in the package
interface ThrowListener {
 public void Catch();
}
/*_____________________________________________________________*/class Thrower {
//list of catchers & corresponding function to add/remove them in the list
 List<ThrowListener> listeners = new ArrayList<ThrowListener>();
 public void addThrowListener(ThrowListener toAdd){ listeners.add(toAdd); }
 //Set of functions that Throw Events.
 public void Throw(){ for (ThrowListener hl : listeners) hl.Catch();
 System.out.println("Something thrown");
 }
////Optional: 2 things to send events to a class that is a member of the current class
. . . go to github link to see this code . . .
}

2 Things needed in a class file to receive events from a class

/*_______________________________________________________________*/class Catcher
implements ThrowListener {//implement added to class
//Set of @Override functions that Catch Events
 @Override public void Catch() {
 System.out.println("I caught something!!");
 }
////Optional: 2 things to receive events from a class that is a member of the current class
. . . go to github link to see this code . . .
}
answered May 18, 2012 at 6:12
25
  • 6
    @GlassGhost: The problem is that main is static, and there's no such thing as this in a static function. You need to create a new Catcher1() somewhere, and pass that instance instead. 1.5 didn't allow this in a static context either; i'm pretty sure it has never been allowed. Commented Jan 23, 2014 at 20:32
  • 6
    @GlassGhost: The code that uses this is in a constructor, not in main. That's why it works. Move it to main, and i guarantee it won't. That's what people have been trying to tell you, and what your answer is trying to do. I don't give a damn what's on github -- i care what's on SO. And what you have on SO is broken. Commented Aug 3, 2014 at 4:07
  • 7
    @GlassGhost: I don't think your answer is inadequate overall. The problem i see with it is that the code won't work as is -- you're trying to use this from main, which won't compile in any released version of Java. If that part were in a constructor instead, or if main created a new Catcher1() and used that instead of this, it should work, even in 1.6+. Commented Aug 3, 2014 at 4:49
  • 6
    @GlassGhost: "A method that is declared static is called a class method. A class method is always invoked without reference to a particular object. An attempt to reference the current object using the keyword this or the keyword super or to reference the type parameters of any surrounding declaration in the body of a class method results in a compile-time error." -- JLS for Java 5, §8.4.3.2 Commented Aug 3, 2014 at 5:23
  • 34
    This is one of the strangest code styles I've ever seen Commented Sep 6, 2014 at 22:40
7

The following is not exactly the same but similar, I was searching for a snippet to add a call to the interface method, but found this question, so I decided to add this snippet for those who were searching for it like me and found this question:

 public class MyClass
 {
 //... class code goes here
 public interface DataLoadFinishedListener {
 public void onDataLoadFinishedListener(int data_type);
 }
 private DataLoadFinishedListener m_lDataLoadFinished;
 public void setDataLoadFinishedListener(DataLoadFinishedListener dlf){
 this.m_lDataLoadFinished = dlf;
 }
 private void someOtherMethodOfMyClass()
 {
 m_lDataLoadFinished.onDataLoadFinishedListener(1);
 } 
 }

Usage is as follows:

myClassObj.setDataLoadFinishedListener(new MyClass.DataLoadFinishedListener() {
 @Override
 public void onDataLoadFinishedListener(int data_type) {
 }
 });
Jon Thoms
10.9k8 gold badges53 silver badges73 bronze badges
answered Jun 3, 2019 at 12:32
1

Terminology

  • listeners are observers/handlers
  • dispatcher is the subject/observers container

Usually, when people implement the observer pattern, they require the dispatcher to exist before any listener can subscribe to it. But there is a better way called Signals.

Signals is an events library. It decouples the dispatcher's listeners by introducing a Signal object that allows both register listeners and dispatch events. Signals are automatically created from an interface via Proxy. It takes care of all the boilerplate code for managing listeners, plus it adds some nice sugar code API.

Listener -> Signal <- Dispatcher

interface Chat{
 void onNewMessage(String s); 
}
class Foo{
 Signal<Chat> chatSignal = Signals.signal(Chat.class);
 
 void bar(){
 chatSignal.addListener( s-> Log.d("chat", s) ); // logs all the messaged to Logcat
 }
}
class Foo2{
 Signal<Chat> chatSignal = Signals.signal(Chat.class);
 
 void bar2(){
 chatSignal.dispatcher.onNewMessage("Hello from Foo2"); // dispatches "Hello from Foo2" message to all the listeners
 }
}

In this example, the Signal is automatically created from the Chat interface. It allows Foo to register for it and Foo2 to dispatch new messages without interaction.

Disclaimer: I am the author of Signals.

answered Mar 15, 2021 at 21:46
0

Ahem, I recently needed to do events and I stumbled upon this topic. I decided to add my own implementation based on the C# version of events, maybe someone will read it and it will be useful to him :

@FunctionalInterface
public interface Action{
 void accept(Object... args);
}
public class CustomEvent {
 protected List<Action> listeners = new ArrayList<>();
 public void addListener(Action arg0){
 listeners.add(arg0);
 }
 public void removeListener(Action arg0){
 listeners.remove(arg0);
 }
 public void invoke(Object... args){
 for (Action listener : listeners) {
 listener.accept(args);
 }
 }
}
public class Example1 {
 public CustomEvent onValueChanged;
 
 private void doSomething(){
 onValueChanged.invoke(); // or .invoke(arg0, arg1, ...)
 }
}
public class Example2 {
 private Example1 example1;
 private Action linkToAction;
 private void init(){
 example1 = new Example1();
 linkToAction = args -> {
 doSomethingAnother(); // or doSomethingAnother((Type)args[0], (Type)args[1], ...)
 }
 example1.onValueChanged.addListener(linkToAction);
 }
 
 public void doSomethingAnother(){}
 
 public void unsubscribe(){
 example1.onValueChanged.removeListener(linkToAction);
 }
}

This is a simple example, the implementation of the Action interface, that I made, is based on the Consumer interface, so the method names are similar, but you can also change it.

answered Feb 16, 2022 at 1:39
0
import java.util.ArrayList;
import java.util.List;
// Define the ButtonListener interface
interface ButtonListener {
 void onClick();
 void onMouseOver();
}
// Implement the ButtonListener interface- Implementation of Listner called the EventHandler
class ButtonEventHandler implements ButtonListener {
 @Override
 public void onClick() {
 System.out.println("Button clicked!");
 }
 
}
class AnotherButtonEventHandler implements ButtonListener {
 @Override
 public void onMouseOver() {
 System.out.println("Mouse over button!");
 }
}
// Class to manage action listeners
class ButtonActionListener {
 private List<ButtonListener> actionListenersRegister = new ArrayList<>();
 public void registerListeners(ButtonListener buttonListener) {
 actionListenersRegister.add(buttonListener);
 }
 public void notifyOnClick() {
 for (ButtonListener listener : actionListenersRegister) {
 listener.onClick();
 }
 }
 public void notifyOnMouseOver() {
 for (ButtonListener listener : actionListenersRegister) {
 listener.onMouseOver();
 }
 }
}
// Test class
public class Test {
 public static void main(String[] args) {
 ButtonActionListener actionListener = new ButtonActionListener();
 // Register event handlers
 actionListener.registerListeners(new ButtonEventHandler());
 actionListener.registerListeners(new AnotherButtonEventHandler());
 // Simulate button click
 actionListener.notifyOnClick();
 // Simulate mouse over
 actionListener.notifyOnMouseOver();
 }
}
  • Multiple Listeners: Each listener can handle the event in its own way.

  • Event Source: The button (or any event source) doesn't need to know what each listener does. It simply notifies all registered listeners.

  • Modularity: This approach keeps the code modular and maintainable.

answered Apr 21 at 9:57

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.