Java 8 introduced the now popular Lambda expressions. Initially, reading and debugging Lambda expressions was very confusing, and so some developers still think that the added cleanliness and readability Lambda expressions offer is not worth the headache. Here's why they're wrong.

What's the Big Deal with Lambda Expressions?

Functional programming has a declarative style that uses Lambda expressions. What's so cool about Lambda expressions? They can be passed around.

So, imagine you have a variable - Variable X - and you want to pass it around your application. It's pretty simple, right? You can use Variable X in method parameters, local variables, or instance variables, and you can even have it injected into your application.

But what about blocks of code? What if you want to pass them around? Is that just as straightforward? Well, thanks to Lambda expressions, it can be.

Functional Interfaces

Functional interfaces are a special type of interface that can only have one abstract method, meaning a functional interface's implementations will represent only one behavior. Lambda can be used to represent one instance of a functional interface where the Lambda parameters and return types are matched.

It's important to mention that any interface with one abstract method, with or without the @FunctionalInterface annotation, can be used with Lambda expressions. The annotation is just a way to ensure that the interface will have only one abstract method. See the example below:


public interface Pencil {

   void write(String message);

All About Lambda Expressions

As mentioned before, Lambda expressions are blocks of code that can be passed around. The basic syntax is:

Pencil pencil = p -> System.out.println(p);

The above piece of code is the same as:

public class Paper implements Pencil {


   public void write(String message) {




Now, we have two options: we can either pass the Pencil instance or the Paper object around.

This is a simple example of a functional interface and a Lambda expression. Java already has some useful interfaces built for common scenarios. 

Let's take a look at two widely used functional interfaces on the java.util.function package: Consumer and Supplier.


A Consumer takes one parameter and returns nothing. Here is the interface:


public interface Consumer<T> {

   void accept(T t);


It'll be easier to remember this one if we think, "It always consumes something, so I should inform something to be consumed," as my Java mentor would say. This interface could have been used on the previous Pencil example, where the interface just writes some text and we use a void method.

public void testWords() {

   Consumer<String> consumer = p -> System.out.println(p);

   printIt(consumer, "can you print it?");


public void printIt(Consumer<String> consumer, String word) {



The above code would print "can you print it?"


A Supplier does not take a parameter, and it returns the type T supplied by this supplier. Here is the interface:


public interface Supplier<T> {

    T get();


My mentor also has a saying for this one: "It always supplies something, and I don't need to inform anything."

 Let's take a look at an example:

public void generateNumbers() {

   Supplier<Integer> supplier =  () -> new Random().nextInt();



public Integer getRandomNumber(Supplier<Integer> supplier) {

   return supplier.get();


When we execute the code above, we get a random integer number printed.

Is It Really That Easy?

Yes! That's all you need to know about the basics of Lambda expressions. If you know how and when to use Lambda expressions in combination with other Java features, you can create some fancy and highly usable code. Java opens a wonderful world of possibilities, and Lambda expressions are a power part of this world. If you know the basics of how they work, complex scenarios become easier.




Roseane Silva

Roseane Silva is a Java Engineer at Avenue Code. She is very curious about what is going on behind the scenes. She loves reading about core concepts and also likes playing around with tests and databases.

Does Your App Need a State Management Framework?


Boosting Productivity with IntelliJ


Getting Started with OAuth 2.0 Authorization Code with PKCE