Skip to content

Instantly share code, notes, and snippets.

@tylermenezes
Created January 16, 2018 19:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tylermenezes/d5db502a4e9ef21cc00e3121634839ef to your computer and use it in GitHub Desktop.
Save tylermenezes/d5db502a4e9ef21cc00e3121634839ef to your computer and use it in GitHub Desktop.
Java Callback Primer
import java.util.*;
public class ExampleApp
{
public void Start()
{
ListenForUserJoin("tylermenezes");
}
public void ListenForUserJoin(String userToMonitor)
{
for (int i = 0; i < 10; i++) {
// `final` variables can be used within the anonymous class.
//
// In this case, we will create final variables for i, and userToMonitor.
//
// Java doesn't want the value of a variable to change once it's been passed into an
// anonymous class, so it requires it to be final. Other languages don't have this
// restriction, which can lead to confusion. e.g. in Javascript, you can do:
//
// var myId = 0;
// onEvent(() => console.log(myId));
// // ...
// myId = 1;
//
// This code will /sometimes/ print 0 and /sometimes/ print 1, depending on exactly
// how fast onEvent gets called, which can be confusing!
final int myId = i;
// (We could actually use `public void ListenForUserJoin(final String userToMonitor)`,
// since userToMonitor won't be changed inside the method, but we _can't_ use
// `for (final int i; ...)`, because `i` is changing. Once something is marked
// `final` it cannot change!)
final String myUserToMonitor = userToMonitor;
// Now we'll register some event listeners for the user.
Database.ListenForUserJoin(myUserToMonitor, new EventHandler() {
@Override
public void OnEvent(){
System.out.println("The user "+myUserToMonitor+" has joined the session! Updating button #"+myId);
}
});
}
}
}
// This is more-or-less what is going on "under the hood" when you use a method that registers
// a callback.
//
// Callbacks are just instances of classes (the `new EventHandler() { ... }` just creates a
// new class with no name, and overrides the important methods), so they can get assigned to
// a variable just like any other instance of a class.
//
// When we want to fire the event, we just get the instance of the class -- or, in this case,
// multiple instances -- and then call its OnEvent method!
interface EventHandler { void OnEvent(); }
public class Database
{
// A list of the instances implementing EventHandler. We'll call OnEvent() on the relevant ones whenever we
// get data.
protected static HashMap<String, List<EventHandler>> eventHandlers = new HashMap<String, List<EventHandler>>();
// Registers an event handler. We could technically just make eventHandlers public, and let people add their own,
// but this is a little nicer.
public static void ListenForUserJoin(String who, EventHandler onRegister)
{
if (!eventHandlers.containsKey(who)) eventHandlers.put(who, new ArrayList<EventHandler>());
eventHandlers.get(who).add(onRegister);
}
// Fires the event handlers for the user. IRL this would also probably do other stuff.
public static void UserJoin(String who)
{
if (eventHandlers.containsKey(who)) {
for (EventHandler handler : eventHandlers.get(who)) handler.OnEvent();
}
}
}
public class TestRunner
{
public static void main(String[] args)
{
ExampleApp foo = new ExampleApp();
foo.Start();
// Later, perhaps in a different thread
Database.UserJoin("tylermenezes");
Database.UserJoin("legobanana");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment