209

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,298
  • 3
  • 25
  • 44
conmadoi
  • 2,163
  • 3
  • 14
  • 5
  • Related: [How to create custom Listeners in java?](http://stackoverflow.com/questions/6941321/how-to-create-custom-listeners-in-java). – Lucio Apr 26 '14 at 21:56
  • 1
    Related: [Java. Correct pattern for implementing listeners](https://stackoverflow.com/questions/2975935/java-correct-pattern-for-implementing-listeners) – Suragch Mar 31 '18 at 03:47

6 Answers6

453

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..."
    }
}

Related article: Java: Creating a custom event

Joel eldo
  • 23
  • 6
aioobe
  • 413,195
  • 112
  • 811
  • 826
  • 2
    What if multiple threads are generating the source events, will this be synchronized properly ? – Mike G Nov 05 '12 at 05: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.) – aioobe Nov 05 '12 at 08: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. – Tomáš Zato Jan 09 '16 at 02:41
  • @TomášZato, you can use [`Observer`](https://docs.oracle.com/javase/7/docs/api/java/util/Observer.html)/[`Observable`](https://docs.oracle.com/javase/7/docs/api/java/util/Observable.html) 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. – aioobe Jan 09 '16 at 07:43
  • Thanks, easy to understand solution for my problem. Also the shortest way of doing this I found so far – Max Belli Mar 09 '17 at 08:49
  • This is really my preferred way, after the Observer/Observable pattern got deprecated – MegaCookie Apr 12 '18 at 10:07
  • If the answer is "Observer pattern," then the answer is "There is no way to create a custom event. You can use Observer pattern to work around that." – Xwtek Dec 11 '18 at 15:28
  • java.util.Observer and java.util.Observable are now deprecated. – Jonathan Rosenne Aug 12 '19 at 08:32
  • 1
    As java.util.Observer got deprecated from Java 9 would there be any better option in implementing custom event? – Udaya Shankara Gandhi Thalabat Jun 16 '20 at 20:51
  • Other information can be found here https://stackoverflow.com/questions/49365350/java-create-a-custom-event-and-listener – Jones G Mar 06 '21 at 20:21
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

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 2
    Reuse - Recycle. But take a look at http://stackoverflow.com/questions/2380676/is-java-util-observable-used-anywhere – count0 May 25 '12 at 20:11
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 . . .
}
GlassGhost
  • 16,906
  • 5
  • 32
  • 45
  • This explains more division for both classes. That's the way, ah-ah ah-ah, I like it. – Niki Romagnoli Oct 03 '13 at 14:14
  • Really wish and admin would mark this as the accepted answer, it is clearly more comprehensive, simple, and terse. Also I could use the upvotes, I might know of a few questions that could use bounties ;) – GlassGhost Oct 03 '13 at 20:08
  • 5
    One cannot use 'this' literal within main since main is static. – Jafar Ali Dec 06 '13 at 05:11
  • @JafarAli Even though it compiles for me, what would you suggest? – GlassGhost Dec 06 '13 at 18:50
  • 3
    @GlassGhost. It gave me compile time error with java JDK 1.6 while trying. "Cannot use this in a static context". – Jafar Ali Dec 09 '13 at 12:12
  • https://github.com/GlassGhost/HexEd is a known working example of the above, but it uses jdk 1.5 . Are you Certain all 8 requirements are fulfilled? Can you show us what you're doing? – GlassGhost Dec 10 '13 at 00:35
  • 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. – cHao Jan 23 '14 at 20:32
  • @cHao I don't care if you're "pretty sure it has never been allowed" the link provided in my previous comment has been working for ages. – GlassGhost Aug 02 '14 at 20:59
  • 4
    @GlassGhost: Your link doesn't lead to proof that your answer's code will work, unless you can point to the file and line. I certainly don't see it. If you don't believe anyone, try compiling the code in your own answer. – cHao Aug 02 '14 at 23:53
  • @cHao https://github.com/GlassGhost/HexEd/commit/d29494426f226c80ec769140cdd4e05b93626780 added 8 comment lines so it is blatantly obvious what is going on here. BTW you don't tell me to try compiling my code that has been working for 3 years now. If you don't believe me just git clone and run "ant" in the directory to build the text editor.jar app. – GlassGhost Aug 03 '14 at 03:54
  • 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. – cHao Aug 03 '14 at 04:07
  • @cHao Look I was mad that you told me to try compiling my answer when I've compiled a million times. If you think my answere is inadequate; You're welcome to try making a better answer of how to do it with 2 classes as the question originally asked, with JDK 1.6 or newer. – GlassGhost Aug 03 '14 at 04:39
  • 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+. – cHao Aug 03 '14 at 04:49
  • @cHao I've been trying to tell you it works. Have you even compiled it? – GlassGhost Aug 03 '14 at 05:16
  • 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](http://docs.oracle.com/javase/specs/jls/se5.0/html/classes.html#8.4.3.2) – cHao Aug 03 '14 at 05:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58563/discussion-between-glassghost-and-chao). – GlassGhost Aug 03 '14 at 06:16
  • 34
    This is one of the strangest code styles I've ever seen – Eric Sep 06 '14 at 22:40
  • 1
    @Eric Have you seen anyone code in a hex editor? Real men code with a magnetized needle and a steady hand. – GlassGhost Sep 07 '14 at 01:16
  • 2
    @GlassGhost: I think you're confusing the style in which the code is authored with the style of the resulting sequence of bits. – Eric Sep 07 '14 at 12:29
  • 2
    @Eric there is no confusion here; it's called a joke. – GlassGhost Sep 07 '14 at 17:05
  • 4
    Not to be confused with try-throw-catch! Poor choice of names, methinks. – tudor -Reinstate Monica- Jun 11 '15 at 02:19
  • 2
    I see you removed the use of `this` from a static context, glad to see you've learned the basics of Java. – arkon Jul 20 '15 at 04:22
  • @tudor actually this is kind of how try-throw-catch works under the hood . . . – GlassGhost Jul 23 '15 at 18:03
  • 1
    I prefer the solution by @aioobe since you can implement a custom interface with multiple functions – Chris623 Aug 14 '16 at 08:08
  • @Chris623 aioobe's solution requires 3 classes regardless of scencario and does not allow nested classes. – GlassGhost Aug 16 '16 at 10:28
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) {
                }
            });
entpnerd
  • 10,049
  • 8
  • 47
  • 68
Ivan
  • 6,388
  • 3
  • 24
  • 30
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.

Ilya Gazman
  • 31,250
  • 24
  • 137
  • 216
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.