Created
January 16, 2018 19:22
-
-
Save tylermenezes/d5db502a4e9ef21cc00e3121634839ef to your computer and use it in GitHub Desktop.
Java Callback Primer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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