Lambda functions are nothing new in the programming world, after first being introduced in LISP all those years ago. They are (relatively) new to the Java ecosystem however, having been introduced with the release of Java 8 in 2014.
They don’t really allow you to do anything that you couldn’t do pre-Java 8, rather they give you a new (some would say cleaner and more expressive) way to implement an anonymous interface. Mostly this is syntactic sugar, but anything that allows us to pare down the infamously verbose Java language is a welcome addition to the development environment.
Lambda expression do differ in one important way from anonymous interface implementations, in that lambdas cannot have state (member variables) where anonymous interfaces can have state. This makes sense when thinking of lambda expressions as a form of functional programming, rather than Object Oriented.
Object Oriented languages like Java are designed to encapsulate code and data in an…object (duh). When you write a class you’re essentially making a template for creating an object, and those classes have names so you can invoke them wherever you like. You would only make a template for something that you’d want to create over and over again as many times as you’d like.
Anonymous classes are unnamed, and thus can’t be invoked or used anywhere but where they’re defined. Thus anonymous classes are useful if you have the need to do a small amount of functionality that doesn’t rise to the level of needing its own template (class). Lambda expressions are merely a more concise way to invoke these anonymous functions, which we’ll see when we get to the code example at the end of this post.
Before we do that though let’s quickly clarify some of the terms that we’ll be using in the explanation.
- Lambda function: Lambda (uppercase Λ, lowercase λ) is just the 11th letter of the Greek alphabet. It has numerous definitions based on the given context, but in computer science they’re used to represent anonymous functions.
- Anonymous functions: a function that isn’t bound to a name/variable. In Java it means a function that doesn’t belong to a class, but rather one that’s implemented as defined by an implementation in a functional interface.
- Functional interface: A Java interface is a grouping of related methods but with blank method bodies. A functional interface is the same concept, but they only define a single method (again with a blank body). One of the most common functional interfaces in Java is the Runnable interface, which defines a single, abstract method,
run(), with no method body, as seen below:
Implementing a functional interface (or any interface for that matter) appropriately uses the
Lambda expressions are created by instantiating an interface (which, if there are any Java compilers reading this, don’t freak out just yet) with an anonymous method body.
As mentioned above, Lambda expressions offer us a concise way to implement functionality that already existed before their introduction. In practice (so I’m told) these expressions are often used to quickly override a method without using the typical solutions of inheritance or composition. For our examples we’re first going to explore how we would have done this before lambda expressions, and end with the concise lambda version.
InheritanceExample.main() in the above example, we would get the message “Override original method functionality”, since we created a subclass
OriginalClassInheritor that creates a new definition of
show() which overrides the definition provided in
OriginalClass. Below we’ll achieve the same outcome as this class, but we’re going to replace inheritance with an anonymous inner class.
Replace Inheritance with Anonymous Inner Class
In the above example we’ve also overridden
show() as defined by
OriginalClass but we’ve done it without inheritance. We did this through introducing an anonymous inner class on line 9, where we injected a code block before the semicolon (now on line 14) that terminates our instantiation of
Rather than using inheritance like in the first example, we can provide new forms of functionality by using interfaces. As defined above an interface defines methods without bodies, and classes that implement interfaces define the actual method body.
Replace Interface Implementations with Anonymous Inner Class
The above snippet does the same thing as the interface example before, but we don’t have to create a new class that implements the interface. We do the same thing that we did when we replaced our inheritance example with an anonymous class. Before the semicolon that terminates the instantiation of the interface (at the end of line 9) you inject a code block that defines the method defined in your original interface, before the semicolon (now on line 13).
Lambda Expression Example
Finally on to the good stuff — lambda expressions. Below we’re achieving the same functionality as the preceding example, but we don’t have to write
new OriginalInterface or even write the method name that we’re implementing.
() to the right of the
= sign on line 9 in the above example is where we would pass argument parameters, if the method in our interface stated that it accepted parameters. The
-> is a new operator for lambda expressions, and it can sort of be thought of as a “becomes” symbol. The parameters (or lack thereof) on the left of the arrow “becomes” the expression to the right of the arrow. This is wrapped up in our variable
object on line 9, and since we’ve given
object the type of
OriginalInterface , which only has one method, we don’t have to explicitly say that we’re defining
show() after the
->, but we can still call it normally like we do on line 10 above.
So as long as the functional interface has only one abstract method, the parameters of the lambda expression match the parameters of the interface’s method, and the return type of the lambda expression is the same as well, the lambda can be matched to the correct interface without being as explicit as we normally would have to be. I think this is more readable, and definitely more concise, than using an anonymous interface implementation, and I’m all for anything that makes Java projects more readable and straightforward to develop.