Fast and modular event library for Java.
To use LambdaEvents with Gradle/Maven you can follow the instructions on my maven server.
repositories {
maven {
url "https://maven.lenni0451.net/releases"
}
}
dependencies {
implementation "net.lenni0451:LambdaEvents:x.x.x"
}
<repository>
<id>lenni0451-maven-releases</id>
<name>Lenni0451 Maven Repository</name>
<url>https://maven.lenni0451.net/releases</url>
</repository>
<dependency>
<groupId>net.lenni0451</groupId>
<artifactId>LambdaEvents</artifactId>
<version>x.x.x</version>
</dependency>
You should check the maven server for the latest version.
You can download the jar file from my Jenkins server.
Since LambdaEvents has no dependencies you don't need to download any other jar files.
To use LambdaEvents you need to create an instance of the LambdaManager
class.
It is the main class of the library used to register and call events.
LambdaManager eventManager = LambdaManager.basic(generator);
Or for a thread safe version:
LambdaManager eventManager = LambdaManager.threadSafe(generator);
There is no global instance to prevent event conflicts.
Because of the dynamic nature of LambdaEvents you need to provide an IGenerator
implementation.
It is used to generate the caller which calls the event listener.
The following implementations are provided:
- ReflectionGenerator
- MethodHandleGenerator
- LambdaMetaFactoryGenerator
Check out the JMH Benchmark section for performance comparisons.
The MethodHandleGenerator
and the LambdaMetaFactoryGenerator
have an optional MethodHandles.Lookup
parameter.
To create your own implementation you need to implement the IGenerator
interface.
The generate
method is used to generate a caller for handler which take the event as a parameter.
The generateVirtual
method is used to generate a caller for handler which don't take the event as a parameter.
In LambdaEvents there is no need to implement an interface or extend a class to create an event.
You can pass any object as an event. Remember that the class is used to identify the event type. Inheritance is not checked and treated as a different event type.
LambdaEvents has 6 different ways to listen to events:
Type | Description |
---|---|
Static methods | A static method annotated with @EventHandler |
Virtual methods | A virtual/non-static method annotated with @EventHandler |
(static) Runnable field | A runnable field annotated with @EventHandler |
(static) Consumer field | A consumer field annotated with @EventHandler |
Independent Runnable | A runnable which is passed to the register method |
Independent Consumer | A consumer which is passed to the register method |
All register
/unregister
methods have an optional event class
parameter to specify the type of the event to register/unregister.
This parameter is required when registering an independent event handler.
Runnable fields or Consumer fields without type parameters require the event type(s) to be added to the @EventHandler(events = {Event.class})
annotation.
Methods are required to not have any parameters or to have the event type as a parameter. Methods without parameters require the event type(s) to be added to the @EventHandler(events = {Event.class})
annotation.
Independent Runnables or Consumers require the event type(s) to be passed to the register
method.
To register static event handler (methods and fields) you need to call the register
method of the LambdaManager
instance passing the owner class.
eventManager.register(Example.class);
To register virtual event handler (methods and fields) you need to call the register
method of the LambdaManager
instance passing the owner object.
eventManager.register(new Example());
To register independent event handler (runnables and consumers) you need to call the register
method of the LambdaManager
instance passing the handler, priority and event type(s).
//Runnable
Runnable handler = () -> System.out.println("called");
eventManager.register(handler, 0, Event.class);
//Consumer
Consumer<Event> handler = e -> System.out.println("called " + e);
eventManager.register(handler, 0, Event.class);
To unregister event handler you have to call the respective unregister
method of the LambdaManager
instance in the same way you registered them.
//Static
eventManager.unregister(Example.class);
//Virtual
eventManager.unregister(oldExampleInstance);
//Independent
eventManager.unregister(handler, Event.class);
To call an event you need to call the call
method of the LambdaManager
instance passing the event object.
eventManager.call(new Event());
LambdaEvents supports priorities for event handlers which is used to determine the execution order.
The higher the priority is, the earlier the event handler is called.
Since there is no requirement for an event to implement an interface or extend a class you have to implement the cancellation yourself.
Example:
public class Event {
private boolean cancelled = false;
public boolean isCancelled() {
return this.cancelled;
}
public void setCancelled(final boolean cancelled) {
this.cancelled = cancelled;
}
}
public class Caller {
public static void callEvent(final LambdaManager eventManager) {
Event event = eventManager.call(new Event());
if (event.isCancelled()) {
return;
}
//Continue the method
//...
}
}
To cancel the event call chain and prevent following event handlers from being executed you can throw the StopCall.INSTANCE
exception.
If an exception is thrown during the registration process, the exception will be thrown to the caller.
If an exception is thrown by an event handler, the ExceptionHandler
of the LambdaManager
instance will be called.
It receives the handler, the event and the thrown exception as parameters.
By default the ExceptionHandler
will print the stack trace of the exception to the console (System.err
).
The Benchmark shows the average time it takes to call an event 100_000 times.
The lower the time is, the better the performance of the generator is.
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
CallBenchmark.callLambdaMetaFactory | avgt | 4 | 2092914,322 | 145474,182 | ns/op |
CallBenchmark.callMethodHandles | avgt | 4 | 3568765,480 | 91089,783 | ns/op |
CallBenchmark.callReflection | avgt | 4 | 2597966,622 | 122017,888 | ns/op |