Java Language


Lambda Expressions Java SE 8

Java SE 1.0
Java SE 1.1
Java SE 1.2
Java SE 1.3
Java SE 1.4
Java SE 5
Java SE 6
Java SE 7
Java SE 8
Java SE 9 (Early Access)

This draft deletes the entire topic.

inline side-by-side expand all collapse all

Examples

  • 24

    An interface with a single abstract method, that doesn't override a method in java.lang.Object, is known as a functional interface or SAM interface (Single Abstract Method). It can have any number of default or static methods. Nothing special needs to be done to the interface; as long as it only has one method it is considered to be functional. Optionally the @FunctionalInterface annotation can be used so that a compiler error will be generated if the interface is not a functional interface.

    The followings are all functional interfaces:

    interface Foo1 {
        void bar();
    }
    interface Foo2 {
        int bar(boolean baz);
    }
    interface Foo3 {
        String bar(Object baz, int mink);
    }
    interface Foo4 {
        default String bar() { // default so not counted
            return "baz";
        }
        void quux();
    }
    @FunctionalInterface
    interface Foo5 {
        void bar();
    }
    @FunctionalInterface
    interface Foo6 {
        void bar();
        boolean equals(Object obj); // overrides one of Object's method so not counted
    }
    

    This is not a functional interface, as it has more than one* method:

    interface BadFoo {
        void bar();
        void quux(); // <-- Second method prevents lambda: which one do we use?
    }
    

    *Conceptually, a functional interface has exactly one abstract method. But there is no restriction on the number of default methods.

    A lambda is simply a shorter way of writing an anonymous class that implements any functional interface. The body of the lambda is used as the body of the functional interface's single method. Thus, these two examples are equivalent:

    Foo1 longFoo = new Foo1() {
        @Override
        public void bar() {
            System.out.println("foo");
        }
    };
    Foo1 shortFoo = () -> System.out.println("foo");
    
    // Both of these print "foo":
    longFoo.bar();
    shortFoo.bar();
    

    Because a lambda is simply an implementation of an interface, nothing special needs to be done to make a method accept a lambda: any function which takes a functional interface can also accept a lambda.

    public void passMeALambda(Foo1 f);
    passMeALambda(() -> System.out.println("Lambda called"));
    
    Java SE 8

    Java 8 provides some functional interfaces out of the box, which can be found in the java.util.function package. Learning them will provide good in depth understanding on functional interfaces

    Note: Functional Interfaces still could have default/static methods which were introduced in Java 8.

  • 28

    Before Java 8, the developer needed to implement the java.util.Comparator interface as below to sort a collection:

    Collections.sort(personList, new Comparator<Person>(){
        public int compare(Person p1, Person p2){
            return p1.getFirstName().compareTo(p2.getFirstName());
        }
    });
    

    Starting with Java 8, this anonymous inner class can be replaced with a lambda expression:

    Collections.sort(personList, (Person p1, Person p2) -> p1.getFirstName().compareTo(p2.getFirstName()));
    

    The type information Person can be removed to simplify the declaration:

    Collections.sort(personList, (p1, p2) -> p1.getFirstName().compareTo(p2.getFirstName()));
    

    and it can be simplified even further with the use of Comparator.comparing:

    Collections.sort(personList, Comparator.comparing(Person::getFirstName));
    

    Using a static import can further improve the readability and conciseness:

    import static java.util.Comparator.comparing;
    //...
    Collections.sort(personList, comparing(Person::getFirstName));
    
  • 5

    Method references allow predefined static or instance methods that adhere to a compatible functional interface, to be passed as arguments instead of an anonymous lambda expression.

    List<String> strings = getStrings();
    

    Instance method reference (to an arbitrary instance)

    strings.stream().map(String::toString)
    

    The equivalent lambda

    strings.stream().map((s) -> s.toString())
    

    Here, a method reference to the instance method toString() of type String, is being passed. Since it's known to be of the collection type, the method on the instance (known later) will be invoked.


    Instance method reference (to a specific instance)

    strings.foreach(System.out::println);
    

    Since System.out is an instance of PrintStream, a method reference to the this specific instance is being passed as an argument.

    The equivalent lambda:

    strings.foreach((s) -> System.out.println(s));
    

    Static method reference

    strings.stream().map(String::valueOf)
    

    This example passes a reference to the static valueOf() method on the String type. Therefore the instance object in the collection is passed as an argument to valueOf().

    The equivalent lambda:

     strings.stream().map((s) -> String.valueOf(s))
    

    Reference to a constructor

    strings.stream().map(Integer::new)
    

    The single String argument constructor of the Integer type is being used here, to construct an integer given the string provided as the argument. In this case, as long as the string represents a number, the stream will be mapped to Integers. The equivalent lambda:

    strings.stream().map((s) -> new Integer(s));
    

I am downvoting this example because it is...

Syntax

  • () -> { return expression; } // Zero-arity with function body to return a value.
  • () -> expression // Shorthand for the above declaration; there is no semicolon for expressions.
  • () -> { function-body } // Side-effect in the lambda expression to perform operations.
  • parameterName -> expression // One-arity lambda expression. In lambda expressions with only one argument, the parenthesis can be removed.
  • (Type parameterName, Type secondParameterName, ...) -> expression // lambda evaluating an expression with parameters listed to the left
  • (parameterName, secondParameterName, ...) -> expression // Shorthand that removes the parameter types for the parameter names. Can only be used in contexts that can be inferred by the compiler where the given parameter list size matches one (and only one) of the size of the functional interfaces expected.

Parameters

Parameters

Remarks

Pitfalls

Lambda expressions are relatively new (since Java SE 8 - released 2014-03-18), and as such, may not have been fully optimized. Depending on the number of lambdas used, the operations performed, and various other factors, lambdas may be slightly slower than traditional methods [source]. However, they are usually faster than anonymous classes, and may even perform as fast, or even faster than alternate solutions.

Also, keep in mind that lambda expressions can only be used in conjunction with functional interfaces.

Still have question about Lambda Expressions? Ask Question

Introduction to Java lambdas

24

An interface with a single abstract method, that doesn't override a method in java.lang.Object, is known as a functional interface or SAM interface (Single Abstract Method). It can have any number of default or static methods. Nothing special needs to be done to the interface; as long as it only has one method it is considered to be functional. Optionally the @FunctionalInterface annotation can be used so that a compiler error will be generated if the interface is not a functional interface.

The followings are all functional interfaces:

interface Foo1 {
    void bar();
}
interface Foo2 {
    int bar(boolean baz);
}
interface Foo3 {
    String bar(Object baz, int mink);
}
interface Foo4 {
    default String bar() { // default so not counted
        return "baz";
    }
    void quux();
}
@FunctionalInterface
interface Foo5 {
    void bar();
}
@FunctionalInterface
interface Foo6 {
    void bar();
    boolean equals(Object obj); // overrides one of Object's method so not counted
}

This is not a functional interface, as it has more than one* method:

interface BadFoo {
    void bar();
    void quux(); // <-- Second method prevents lambda: which one do we use?
}

*Conceptually, a functional interface has exactly one abstract method. But there is no restriction on the number of default methods.

A lambda is simply a shorter way of writing an anonymous class that implements any functional interface. The body of the lambda is used as the body of the functional interface's single method. Thus, these two examples are equivalent:

Foo1 longFoo = new Foo1() {
    @Override
    public void bar() {
        System.out.println("foo");
    }
};
Foo1 shortFoo = () -> System.out.println("foo");

// Both of these print "foo":
longFoo.bar();
shortFoo.bar();

Because a lambda is simply an implementation of an interface, nothing special needs to be done to make a method accept a lambda: any function which takes a functional interface can also accept a lambda.

public void passMeALambda(Foo1 f);
passMeALambda(() -> System.out.println("Lambda called"));
Java SE 8

Java 8 provides some functional interfaces out of the box, which can be found in the java.util.function package. Learning them will provide good in depth understanding on functional interfaces

Note: Functional Interfaces still could have default/static methods which were introduced in Java 8.

Declare a comparator

28

Before Java 8, the developer needed to implement the java.util.Comparator interface as below to sort a collection:

Collections.sort(personList, new Comparator<Person>(){
    public int compare(Person p1, Person p2){
        return p1.getFirstName().compareTo(p2.getFirstName());
    }
});

Starting with Java 8, this anonymous inner class can be replaced with a lambda expression:

Collections.sort(personList, (Person p1, Person p2) -> p1.getFirstName().compareTo(p2.getFirstName()));

The type information Person can be removed to simplify the declaration:

Collections.sort(personList, (p1, p2) -> p1.getFirstName().compareTo(p2.getFirstName()));

and it can be simplified even further with the use of Comparator.comparing:

Collections.sort(personList, Comparator.comparing(Person::getFirstName));

Using a static import can further improve the readability and conciseness:

import static java.util.Comparator.comparing;
//...
Collections.sort(personList, comparing(Person::getFirstName));

Method References

5

Method references allow predefined static or instance methods that adhere to a compatible functional interface, to be passed as arguments instead of an anonymous lambda expression.

List<String> strings = getStrings();

Instance method reference (to an arbitrary instance)

strings.stream().map(String::toString)

The equivalent lambda

strings.stream().map((s) -> s.toString())

Here, a method reference to the instance method toString() of type String, is being passed. Since it's known to be of the collection type, the method on the instance (known later) will be invoked.


Instance method reference (to a specific instance)

strings.foreach(System.out::println);

Since System.out is an instance of PrintStream, a method reference to the this specific instance is being passed as an argument.

The equivalent lambda:

strings.foreach((s) -> System.out.println(s));

Static method reference

strings.stream().map(String::valueOf)

This example passes a reference to the static valueOf() method on the String type. Therefore the instance object in the collection is passed as an argument to valueOf().

The equivalent lambda:

 strings.stream().map((s) -> String.valueOf(s))

Reference to a constructor

strings.stream().map(Integer::new)

The single String argument constructor of the Integer type is being used here, to construct an integer given the string provided as the argument. In this case, as long as the string represents a number, the stream will be mapped to Integers. The equivalent lambda:

strings.stream().map((s) -> new Integer(s));

Currying

4

Currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument.

This is normally useful when for example:

  1. different arguments of a function are calculated at different times. (Example 1)
  2. different arguments of a function are calculated by different tiers of the application. (Example 2)

Here's a generic utility of currying a 2-argument function:

class FunctionUtils {

    public static <A,B,C> Function<A,Function<B,C>> curry(BiFunction<A, B, C> f) {
        return a -> b -> f.apply(a,b);
    }

}

The above returned curried lambda expression can also be viewed/written as:

a -> ( b -> f.apply(a,b) );

Example 1

Let's assume that the total yearly income is a function composed by the income and a bonus:

BiFunction<Integer,Integer,Integer> totalYearlyIncome = (income,bonus) -> income + bonus;

Let's assume that the yearly income portion is known in advance:

Function<Integer,Integer> partialTotalYearlyIncome = FunctionUtils.curry(totalYearlyIncome).apply(10000);

And at some point down the line the bonus is known:

partialTotalYearlyIncome.apply(100);

Example 2

Let's assume that the car manufacturing involves the application of car wheels and car body:

BiFunction<String,String,String> carManufacturing = (wheels,body) -> wheels.concat(body);

These parts are applied by different factories:

class CarWheelsFactory {
    public Function<String,String> applyCarWheels(BiFunction<String,String,String> carManufacturing) {
        return FunctionUtils.curry(carManufacturing).apply("applied wheels..");
    }
}

class CarBodyFactory {
    public String applyCarBody(Function<String,String> partialCarWithWheels) {
        return partialCarWithWheels.apply("applied car body..");
    }
}

Notice that the CarWheelsFactory above curries the car manufacturing function and only applies the wheels.

The car manufacturing process then will take the below form:

CarWheelsFactory carWheelsFactory = new CarWheelsFactory();
CarBodyFactory   carBodyFactory   = new CarBodyFactory();

BiFunction<String,String,String> carManufacturing = (wheels,body) -> wheels.concat(body);

Function<String,String> partialCarWheelsApplied = carWheelsFactory.applyCarWheels(carManufacturing);
String carCompleted = carBodyFactory.applyCarBody(partialCarWheelsApplied);

Iterating through a HashMap using a BiConsumer

2

HashMap has the forEach method that accepts a BiConsumer. BiConsumer is a functional interface which contains one method, public void accept(T t, U u), where T and U are parameterized types.

The following examples are for printing out the Key-Value pairs for a HashMap<String,String>; however, the concept still applies elsewhere.

Assume that a HashMap<String, String> is stored in variable hm, and that java.util.HashMap is imported for all of the following examples.

Without a lambda expression:

public class StringBiConsumer implements BiConsumer<String, String> {
    public void apply(String str1, String str2) {
        //Your code here
        System.out.println(str1 + ": " + str2);
    }
}

hm.forEach(new StringBiConsumer());

We can improve this a little bit without using lambda expressions by writing an anonymous class:

hm.forEach(new BiConsumer<String, String>() {
    public void apply(String str1, String str2) {
        System.out.println(str1 + ": " + str2);
    }
});

A bit more concise, but still bulky. We can do better.

Since functional interfaces (such as BiConsumer) only contain one unimplemented method, the designers of java guessed that with these types of interfaces, you probably only want to override just that one method. When you write a lambda expression, the "method" that the lambda expression represents automatically overrides the single unimplemented method of the lambda target (in this example, the lambda target is BiConsumer), which must be a functional interface. With that in mind, let's rewrite this as a lambda expression:

hm.forEach((String str1, String str2)->{ 
    //The -> operator tells java that you are writing a lambda expression.
    //Note that the parameter types are the same as a BiConsumer<String, String>
    System.out.println(str1+ ": " + str2);
    //If the return type isn't void, you need a return statement
});

Java can also inference the parameter types (since HashMap<String, String> only accepts a BiConsumer<? super String, ? super String>, java infers that you are creating a BiConsumer<String, String>). Let's see this in action:

hm.forEach((str1, str2)->{
    System.out.println(str1 + ": " + str2);
});

Since this isn't a particularly complicated statement, this can be shortened even further:

hm.forEach((str1, str2)->System.out.println(str1 + ": " + str2));

Alternatively, you can reuse the lambda expression:

BiConsumer<String, String> exampleConsumer= (str1, str2)->System.out.println(str1 + ": " + str2);
hm.forEach(exampleConsumer);
someOtherHm.forEach(exampleConsumer);

If you have a method elsewhere that matches the parameter and return types of the lambda target, you can use a method reference. This code is valid:

public class ExampleClass {
    
    public static void someRandomMethod(String str1, String str2) {
        System.out.println(str1 + ": " str2);
    }

    public static void processMap(HashMap<String, String> hm) {
        hm.forEach(ExampleClass::someRandomMethod);
    }
}

This code is equivalent to:

hm.forEach((String s1, String s2)->ExampleClass.someRandomMethod(s1, s2));

This can also extend to non-static methods, as long as the parameter and return types still match:

hm.forEach(anObject::anotherMethod);

One final note: for all of the examples where the code doesn't directly mention BiConsumer by name, there is no need to import java.util.function.BiConsumer.

`return` only returns from the lambda, not the outer method

1

The return method only returns from the lambda, not the outer method.

Beware that this is different from Scala and Kotlin!

void threeTimes(IntConsumer r) {
  for (int i = 0; i < 3; i++) {
    r.accept(i);
  }
}

void demo() {
  threeTimes(i -> {
    System.out.println(i);
    return; // Return from lambda to threeTimes only!
  });
}

This can lead to unexpected behavior when attempting to write own language constructs, as in builtin constructs such as for loops return behaves differently:

void demo2() {
  for (int i = 0; i < 3; i++) {
    System.out.println(i);
    return; // Return from 'demo2' entirely
  }
}

In Scala and Kotlin, demo and demo2 would both only print 0. But this is not more consistent. The Java approach is consistent with refactoring and the use of classes - the return in the code at the top, and the code below behaves the same:

void demo3() {
  threeTimes(new MyIntConsumer());
}

class MyIntConsumer implements IntConsumer {
  public void accept(int i) {
    System.out.println(i);
    return;
  }
}

Therefore, the Java return is more consistent with class methods and refactoring, but less with the for and while builtins, these remain special.

Because of this, the following two are equivalent in Java:

IntStream.range(1, 4)
    .map(x -> x * x)
    .forEach(System.out::println);
IntStream.range(1, 4)
    .map(x -> { return x * x; })
    .forEach(System.out::println);

Furthermore, the use of try-with-resources is safe in Java:

class Resource implements AutoCloseable {
  public void close() { System.out.println("close()"); }
}

void executeAround(Consumer<Resource> f) {
  try (Resource r = new Resource()) {
    System.out.print("before ");
    f.accept(r);
    System.out.print("after ");
  }
}

void demo4() {
  executeAround(r -> {
    System.out.print("accept() ");
    return; // Does not return from demo4, but frees the resource.
  });
}

will print before accept() after close(). In the Scala and Kotlin semantics, the try-with-resources would not be closed, but it would print before accept() only.

Implementing multiple interfaces

1

Sometimes you may want to have a lambda expression implementing more than one interface. This is mostly useful with marker interfaces (such as java.io.Serializable) since they don't add abstract methods.

For example, you want to create a TreeSet with a custom Comparator and then serialize it and send it over the network. The trivial approach:

TreeSet<Long> ts = new TreeSet<>((x, y) -> Long.compare(y, x));

doesn't work since the lambda for the comparator does not implement Serializable. You can fix this by using intersection types and explicitly specifying that this lambda needs to be serializable:

TreeSet<Long> ts = new TreeSet<>(
    (Comparator<Long> & Serializable) (x, y) -> Long.compare(y, x));

If you're frequently using intersection types (for example, if you're using a framework such as Apache Spark where almost everything has to be serializable), you can create empty interfaces and use them in your code instead:

public interface SerializableComparator extends Comparator<Long>, Serializable {}

public class CustomTreeSet {
  public CustomTreeSet(SerializableComparator comparator) {}
}

This way you're guaranteed that the passed comparator will be serializable.

Lambdas and Execute-around Pattern

1

There are several good examples of using lambdas as a FunctionalInterface in simple scenarios. A fairly common use case that can be improved by lambdas is what is called the Execute-Around pattern. In this pattern, you have a set of standard setup/teardown code that is needed for multiple scenarios surrounding use case specific code. A few common example of this are file io, database io, try/catch blocks.

interface DataProcessor {
    void process( Connection connection ) throws SQLException;;
}

public void doProcessing( DataProcessor processor ) throws SQLException{
    try (Connection connection = DBUtil.getDatabaseConnection();) {
        processor.process(connection);
        connection.commit();
    } 
}

Then to call this method with a lambda it might look like:

public static void updateMyDAO(MyVO vo) throws DatabaseException {
    doProcessing((Connection conn) -> MyDAO.update(conn, ObjectMapper.map(vo)));
}

This is not limited to I/O operations. It can apply to any scenario where similar setup/tear down tasks are applicable with minor variations. The main benefit of this Pattern is code re-use and enforcing DRY (Don't Repeat Yourself).

Using lambda expression with your own functional interface

1

Lambdas are meant to provide inline implementation code for single method interfaces and the ability to pass them around as we have been doing with normal variables. We call them Functional Interface.

For example, writing a Runnable in anonymous class and starting a Thread looks like:

//Old way
new Thread(
        new Runnable(){
            public void run(){
                System.out.println("run logic...");
            }
        }
).start();

//lambdas, from Java 8
new Thread(
        ()-> System.out.println("run logic...")
).start();

Now, in line with above, lets say you have some custom interface:

interface TwoArgInterface {
    int operate(int a, int b);
}

How do you use lambda to give implementation of this interface in your code? Same as Runnable example shown above. See the driver program below:

public class CustomLambda {
    public static void main(String[] args) {

        TwoArgInterface plusOperation = (a, b) -> a + b;
        TwoArgInterface divideOperation = (a,b)->{
            if (b==0) throw new IllegalArgumentException("Divisor can not be 0");
            return a/b;
        };

        System.out.println("Plus operation of 3 and 5 is: " + plusOperation.operate(3, 5));
        System.out.println("Divide operation 50 by 25 is: " + divideOperation.operate(50, 25));

    }
}

Topic Outline