Lambdas and Method references can be used to make your code way shorter, and (sometimes) more readable by getting rid of anonymous classes.
What are Anonymous Classes?
Anonymous classes are like local classes without a name. Imagine you have the following code:
Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { @Override public void run() { System.out.println("10 ticks later..."); } }, 10);
We hereby declare and instantiate a class implementing java.lang.Runnable that just prints some text. It doesn’t have any name, making it an anonymous class.
What are Lambdas?
Lambdas allow us to get rid of the anonymous class. You can directly define the run() method. The general syntax is like this:
// Methods without parameters () -> expression // Methods with one parameter param1 -> expression // Methods with more than one parameter (param1, param2) -> expression
The expression can be a single expression, or a block of code. For example, our above example would look like this:
Bukkit.getScheduler().runTaskLater(plugin, () -> System.out.println("10 ticks later..."), 10);
If your run() method from above would contain more than one expression, the lambda would look like this:
Bukkit.getScheduler().runTaskLater(plugin, () -> { System.out.println("10 ticks later..."); System.out.println("....."); }, 10);
Lambdas with parameters
Lambdas with one parameter
As said, Lambdas can also declare methods with parameters. Again, let’s imagine we have the following code:
List<Entity> creepersAsEntities = world.getEntities().stream().filter(new Predicate<Entity>() { @Override public boolean test(Entity entity) { return entity instanceof Creeper; } }).collect(Collectors.toList());
As you can see, our method called test expects one parameter of type Entity. The corresponding lambda expression looks like this:
List<Entity> creepersAsEntities = world.getEntities().stream().filter(entity -> { return entity instanceof Creeper; }).collect(Collectors.toList());
Lambdas with more parameters
Now imagine we have an anonymous class with a function that takes two or more arguments. For example, something like this:
player.getInventory().addItem(items).forEach(new BiConsumer<Integer, ItemStack>() { @Override public void accept(Integer index, ItemStack item) { System.out.println("Could not add item at index " + index + ": " + item.getAmount() + "x" + item.getType().name() + " to player " + player.getName() + " because their inventory is full."); } });
The corresponding lambda looks like this:
player.getInventory().addItem(items).forEach((index, item) -> { System.out.println("Could not add item at index " + index + ": " + item.getAmount() + "x" + item.getType().name() + " to player " + player.getName() + " because their inventory is full."); });
Method References
An even shorter way than lambdas can be achieved using method references. The following lambda
Bukkit.getOnlinePlayers().forEach(player -> { player.resetPlayerTime(); });
simply calls a method on the lambda parameter “player”, and it doesn’t require any parameters itself. Now, and only now, can we replace this lambda with an even shorter method reference:
Bukkit.getOnlinePlayers().forEach(Player::resetPlayerTime);
“That’s confusing!”
The lambda and method reference syntaxes can be a bit confusing. No one forces you to use them, you will always be able to use the old anonymous classes. However, you will start to love them once you understood how they worked.
IntelliJ can automatically convert your old code using anonymous classes to lambdas or method references:
This way, you can write your code in the old, familiar way, then let IntelliJ convert it for you. This can help you learn to understand the syntax.
Join my Discord Server for feedback or support. Just check out the channel #programming-help
🙂