1-888-310-4540 (main) / 1-888-707-6150 (support) info@spkaa.com
Select Page

Exploring Java 8’s New Feature: Lambda Expressions

Published by SPK Blog Post
on May 12, 2014

Recently, Oracle announced the release of Java 8. This latest edition has some interesting new features, most notably the inclusion of lambda expressions and the ability to do multiple inheritance through default methods.

We’ll spend the bulk of this article exploring lambda expressions and how they can be useful for engineering — but first, let’s take a quick overview of what’s been added in this release of the language and some notes about getting started with it.

Java 8’s Distinctly New Features:

  • Default methods in Interfaces (which make multiple inheritance possible)
  • Lambda expressions
  • A JavaScript runtime which allows developers to embed JavaScript within applications
  • Annotations on Java Types
  • Unsigned integer arithmetic
  • Repeating annotations
  • Date and Time API
  • Statically linked JNI libraries
  • Launch JavaFX applications

Notes On Getting Started

There are a couple of things to be aware of when downloading Java 8. The first of which is Java 8’s incompatibility with Windows XP. That said, there is a way around this if using Java 8 on Windows XP is necessary. You can do a forced installation by directly unzipping from the installation executable

A second piece of information that may be helpful is at the time of this writing, the Eclipse IDE does not support Java 8 out of the box — you will need to install a feature patch to make this happen. To do so, navigate to Help > Install New Software… and enter “http://download.eclipse.org/eclipse/updates/4.3-P-builds/” into the “Work with” field. Select category “Eclipse Java 8 Support (for Kepler SR2)” and complete the download/install process.

The newest version of Eclipse (Luna) is scheduled for release on June 25th, at which point Java 8 will be supported without any special updates.

New Feature: Lambda Expressions

In essence, a lambda expression is an anonymous method — a method that can be defined without being bound to an identifier.

Lambda expressions have been around since the late 50’s in LISP and have been incorporated into mainstream languages such as JavaScript, Perl, Python, Ruby, and C#, but until this release they were not possible in Java.

According to Oracle, the reasons for their inclusion in Java are that “[Lambda expressions] provide a clear and concise way to represent [a] one method interface using an expression. Lambda expressions also improve the Collection libraries making it easier to iterate through, filter, and extract data from a Collection”. These one method interfaces are also officially known as “Functional Interfaces”. For example, the ActionListenter interface is a Functional Interface because it defines the actionPerformed method and no others.

In the previous versions of Java, using functional interfaces with anonymous inner classes was a common pattern. Despite getting the job done, there are some downsides to using them this way. In particular, there is what’s known as “The Vertical Problem”. Writing an anonymous inner class typically results in an awkward block of code that spans multiple lines in order to accomplish something that is conceptually very straight-forward. When all we want to say is “Execute this method when I click this button” We end up writing “When the user clicks this button, create an instance of class X which specifies the Y method and inside that Y method I want method Z to execute”.

The following code will illustrate this point:

/* Old style, using anonymous inner classes */

JButton button = new JButton("Click Me!");

button.addActionListener( new ActionListener() {

        @Override

               public void actionPerformed( ActionEvent e ) {

                               printButtonLabel( button.getText() );

               }

} );

This isn’t horrible, but imagine creating 20 buttons and assigning them various kinds of behaviors. You can probably imagine the code would grow very large and would become more challenging to follow.

Now see how this could be done with a lambda expression.

/* New style, using lambda expressions */

JButton button = new JButton("Click Me!");

button.addActionListener( e -> printButtonLabel( button.getText() ) );

This is much more concise. It saves several lines of code and makes the behavior of the button very clear. This works because ActionListener is a functional interface and defines only one method. Java knows that when we call the addActionListener method of the JButton class, that there can only be one type of object passed in and that object has only one method that can possibly be called, so it essentially allows us to use a shorthand. In the case above, the parameter e is the ActionEvent object passed to the actionPerformed method and the content to the right of the arrow token is the body of the actionPerformed method. Our example executes only one method call, however, an arbitrarily long block of code can be inserted if placed between curly braces “{ …. }”.

Syntax of A Lambda Expression

The syntax of a lambda expression is composed of three parts

        Argument List                    Arrow Token                     Body

        (int x, int y)                          ->                                           x + y

The argument list contains the parameters required by the method define inside the functional interface. The parentheses themselves are optional if the method has one or more parameters and object type is optional as well. As a result, the following are all valid expressions, given that they conform to the interfaces:

() -> System.out.println(“No paramerts”);

(String x) -> System.out.println(“One parameter” + x);

(x, y) -> System.out.println(“Two parameters” + x + “ and “ + y);

x -> System.out.println(“Parentheses are optional”);

The arrow token separates the argument list from the code body.

The body can either be a single expression or a statement block. In the expression form, the body is simply evaluated and returned. In the block form, the body is evaluated like a method body and a return statement returns control to the caller of the anonymous method. The break and continue keywords are illegal at the top level, but are permitted within loops. If the body produces a result, every control path must return something or throw an exception.

Java 8 provides a new annotation to label an interface as a functional interface.

Just precede the interface declaration statement with “@FunctionalInterface”.  This isn’t required, but provides some extra information to the compiler to help keep things consistent by enforcing the rule that the interface only define one method. This new annotation is similar to the @Override annotation in earlier versions of Java.

Using Lambdas to Write Dispatch Tables

In addition to reducing the amount of typing necessary, lambda expressions make it easy to code things like dispatch tables for processing things like keyboard input (such as you might need to do if you’re a creating a game).

In my dabbling with game programming, almost every example I’ve seen of processing keyboard input usually involves a long string of if statements that attempts to handle all the valid key inputs. I’ve never liked the way this looks, but I didn’t know what to do about it. The following example, I hope, shows a much simpler way to process something of this nature.

import java.awt.BorderLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import javax.swing.JFrame;
import javax.swing.JTextField;

public class Test {

    @FunctionalInterface
    interface KeyAction {
        public void doAction();
    }

    public static void main( String[] args) {

        HashMap<Integer, KeyAction> keyDispatcher = new HashMap<Integer, KeyAction>();

        keyDispatcher.put(KeyEvent.VK_W, () -> moveUp());
        keyDispatcher.put(KeyEvent.VK_S, () -> moveDown());
        keyDispatcher.put(KeyEvent.VK_A, () -> moveLeft());
        keyDispatcher.put(KeyEvent.VK_D, () -> moveRight()); 

        // Using a JTextField out of simplicity
        JTextField field = new JTextField();
        field.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent arg0) {
                try{

                    keyDispatcher.get(arg0.getKeyCode()).doAction();

                } catch (NullPointerException e) {
                    System.out.println("That button doesn't do anything yet...");
                }
            }
        });

        JFrame frame = new JFrame("Listener Frame");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(field, BorderLayout.NORTH);
        frame.pack();
        frame.setVisible(true);
    }

    private static void moveUp() {
        System.out.println("Moving up");
    }
    private static void moveDown() {
        System.out.println("Moving down");
    }
    private static void moveLeft() {
        System.out.println("Moving left");
    }
    private static void moveRight() {
        System.out.println("Moving right");
    }
}

The thing to note about this example is how clearly the input value is associated with the desired action and how efficiently the desired action is performed due to the constant lookup time of the hash table.

To do the above in prior versions of Java would require some clunky anonymous inner classes or some questionable use of Java’s reflection library. See this StackOverflow article for an example.

Hopefully, this article has provided a decent introduction to one of the more exciting additions to the Java language. If you want to pursue the subject further, I recommend the following resources:

Next Steps:

David Hubbell
Software Engineer
SPK and Associates

Latest White Papers

Atlassian Cloud: Understanding Zero Trust Security

Atlassian Cloud: Understanding Zero Trust Security

Where To Start & Why It Matters What is the Atlassian Cloud Zero Trust Security model? Well, for decades, enterprise security controls were built to protect a large, single perimeter around a corporation. Often described as castle-and-moat security, This approach...

Related Resources

Why Process Automation Is Critical For Engineering

Why Process Automation Is Critical For Engineering

Process automation releases your engineers for the work their brains are intended for. That work is creativity and problem-solving.  By implementing process automation, you improve the team’s morale. Firstly, they get more focus time for deep work and designing better...

CloudBees SDA:  Software Delivery Without Silos

CloudBees SDA:  Software Delivery Without Silos

Tired of missing deadlines, and only measuring performance of departments, but not of your entire software delivery organization? This blog will show you how CloudBees Software Delivery Automation (CloudBees SDA) can break down silos, drive DevOps mentality and...

Deep Work Improves Engineers’ Productivity

Deep Work Improves Engineers’ Productivity

In this blog we'll explore how the principle of Deep Work by Cal Newport can improve your engineers productivity. Does it feel harder for you to focus on your creative, technical work? When I speak to engineers or management staff and ask this question, the answer...