Java 8 Series: Lambda Expressions

In my daily work I often switch from the development on JavaScript-based frontends to Java-based backends. Thereby it occasionally happens that I intentionally start to write function() {... at places where actually anonymous classes are required. Thanks to Java 8 such functional language syntax will be a valid option. Namely you will be able to substitute anonymous classes with lambda expressions in cases where you actually just want to pass functionality.

The end of detours!

To illustrate this let’s consider the following example where we want to filter all configuration directories and files (all starting with .) within a home directory:

Actually the filename.startsWith(".") evaluation expression is all we want to pass to the list(FilenameFilter filenameFilter) method. But instead we must go a cumbersome detour over the implementation of the FilenameFilter interface in the form of an anonymous class. Until now…

Lambdas to the rescue!

Java 8 will allow us to write lambda expressions at places where functional interfaces are demanded. Such functional interfaces are characterized by the existence of a single method declaration and optionally by the @FunctionalInterface annotation above the interface declaration (more on that in the next part of this series).

FilenameFilter is such a functional interface and hence we can pass a lambda expression to the list(FilenameFilter filenameFilter) method:

Not only does the lambda expression eliminate some lines and on the whole improve the readability of the code, but also appears more elegant and naturally compared to the cumbersome anonymous class.

The next section gives a compact overview of the lambda expression syntax.

Syntax Rules

A lambda expression has the following syntax:

LAMBDA PARAMETER LIST -> LAMBDA BODY

That is: A list of zero or multiple parameters, followed by the arrow token, and a lambda body consisting of one expression or multiple statements (statement block).

Lambda Parameter List

The lambda parameter list can be empty,

can contain one

or multiple parameters

which may also be explicitly typed:

In case there is only one untyped parameter the braces can be left out:

However, braces are obligatory if

  • there is none parameter
  • a type is specified for the one and only parameter
  • there are at least two parameters

And: Either all parameters are typed or neither. Therefore the following parameter lists are not allowed:

Lambda Body

The lambda body can consist of one expression or of a statement block. An expression does not need to be enclosed by curly braces

while a statement block must be surrounded by them:

Return statements also require curly braces:

However, if the lambda body only returns an expression then return and the curly braces can be omitted:

Finally a lambda body must not contain break and continue statements at the top level:

Variable Capturing

The below code snippet shows a lambda expression and variables that can be captured by it:

As we can see the following kinds of variables can be captured from the lambda expression’s enclosing scope:

  • class and instance variables (foo, bar and baz)
  • parameter variables of the enclosing method(additionalFilter)
  • variables within the body of the enclosing method (bla)
  • parameter variables of the lambda expression (dirToFilter and filename)
  • variables within the body of the lambda expression (yetAnotherFilter)

However, all variables that get used within the lambda body must either carry the final modifier or at least be effectively final. That means: Their value must not change after their initialization. Hence in the above example only the qux instance variable in line 6 can not be captured because it is not initialized yet.

The this Pointer

In short, this points to everything it would point outside the lambda expression. To pick up the example from the previous section, this points to all variables and methods outside the doFilter() method.

Conclusion

As a good friend of JavaScript I naturally welcome the adoption of functional language features in Java. I’m wondering why we had to wait until the eighth version of Java and instead struggle with detours over one-method-classes.

In the next part of this series we will learn which Java types can hold lambda expressions and in which contexts they can be used.

Other Posts in this Series

References