Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Java Lambda Expressions: Functions as First-Class Citizens

DZone's Guide to

Java Lambda Expressions: Functions as First-Class Citizens

Want to learn more about Java lambda expressions? Check out this post on functional interfaces and lambda expressions.

· Java Zone ·
Free Resource

Delivering modern software? Atomist automates your software delivery experience.

Since Java 8, a lot of boilerplate code can be replaced with lambda expressions in our codebase. I really want to put out an article about Streams in Java, but since that only carries real value if we combine them with lambda expressions, I want to write about playing around with lambda expressions first.

Functional Interfaces in Java

A functional interface is an interface with a single abstract method, also known as SAM (Single Abstract Method) types. The concept was introduced in JDK 8, but there were interfaces prior to JDK 8 that compiled that definition. For example, Comparator has only one method:compare().

We can create our own as:

@FunctionalInterface
interface Calculator<T,R> {
    R calculate(T a, T b);
}


Here, the @FunctionalInterface annotation is checked by the compiler. So, if the interface does not contain exactly one abstract method, there is a compiler error.

It is not necessary to use this annotation when providing a type for a lambda expression, but, like other annotations (@Override, for example), it is a best practice to use it because it tells the compiler to check that it would work — otherwise, it will be overlooked until runtime.

Now, What Is a Lambda Expression?

A lambda expression is an inline implementation of a functional interface, eliminating the need of an anonymous class.

A lambda expression has three parts:

parameters [zero or more]
    ->
code block [if more than one statement, enclosed in curly braces { . . . } ] 
           [may contain free variables; values for these supplied by local or instance vbles]


For example:

(a,b) -> a + b; // given two numbers a and b, return another number with their summation.

(String str) -> System.out.println(str); // prints the given string into console


The equivalent of the first lambda expression is:

new Calculator<Integer, Integer>() {    
    @Override    
    public Integer calculate(Integer a, Integer b) {        
        return a + b;    
    }
};


You can see how lambda expressions help to get rid of the boilerplate code.

Naming Lambda Expressions

Every object in Java has a type; the same is true of lambda expressions. The type of a lambda expression is any functional interface for which the lambda expression is an implementation.

Naming a lambda expression is done by using an appropriate functional interface as its type, like naming any other object. For example:

Calculator<Integer, Integer> adder = (a,b) -> a + b;


The name of this lambda expression is adder of type Calculator.

Note: I am omitting the parameter type because if parameter types can be inferred, they can be omitted. So, the above expression with the parameter type would be:

Calculator<Integer, Integer> adder = (Integer a,Integer b) -> a + b;


Using Lambda Expressions

You've seen how inner class approximations can be replaced by lambda expressions, which capture their essential functional nature: Arguments mapped to outputs. Hence, the functions are now first-class citizens. So:

1. A lambda expression can be used as a regular class object to call the method. For example, adder can be used to call the calculate method as:

Integer sum = adder.calculate(3,4); // sum = 7


2. Lambda expressions can be passed as an argument and used to evaluate expressions as:

// ...
printSum(adder);
// ...

static void printSum(Calculator cal) {
    System.out.println(cal.calculate(4,5));
}


3. Lambda expressions can be returned as a return object:

// ...
Calculator<Integer, Integer> multiplier = getCalculatorFunc();
Integer result = multiplier.calculate(6,9));  // 54
// ...
static Calculator getCalculatorFunc() {
    Calculator<Integer, Integer> multiplier = (a, b) -> a * b;
    return multiplier;
}


Conclusion

Now, you can see how it is possible to reap the benefits of functional programming while maintaining the OO essence of the Java language as a whole. Lambda expressions are the fundamentals for functional programming and writing code concisely with Streams, which I want to continue in the next post. Until then, happy coding!

The source code for the examples presented above is available on GitHub.

Start automating your delivery right there on your own laptop, today! Get the open source Atomist Software Delivery Machine.

Topics:
java ,lambda expressions ,functional programming ,functional interfaces ,fp ,interfaces ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}