11.3. Example: Named Class vs. Lambda Expression

Below is an example that illustrates the difference between using a named class and a lambda expression when implementing Consumer, a functional interface that comes with Java (its one abstract method is void accept(T t)).

NAMED CLASS:

// Shouter.java (assume proper package and import statements)
public class Shouter implements Consumer<String>() {

    @Override
    public void accept(String t) {
        System.out.println(t.toUpperCase());
    } // accept

} // Shouter
// Driver.java (assume proper package and import statements)
public class Driver {

    public static void forEach(String[] strings, Consumer<String> consumer) {
        for (int i = 0; i < strings.length; i++) {
            String str = strings[i];
            consumer.accept(str);
        } // for
    } // forEach

    public static void main(String[] args) {
        Consumer<String> shout = new Shouter();
        Driver.forEach(args, shout);
    } // main

} // Driver

Compile two files, then run:

java Driver hello world how are you?
HELLO
WORLD
HOW
ARE
YOU?

USING A LAMBDA EXPRESSION:

In Driver.java (We no longer need a separate named class to implement Consumer!
public class Driver {

    public static void forEach(String[] strings, Consumer<String> consumer) {
        for (int i = 0; i < strings.length; i++) {
            String str = strings[i];
            consumer.accept(str);
        } // for
    } // forEach

    public static void main(String[] args) {
        Consumer<String> shout = (String t) -> System.out.println(t.toUpperCase());
        Driver.forEach(args, shout);
    } // main

} // Driver
# compile one file, then run:

$ java Driver hello world how are you?
HELLO
WORLD
HOW
ARE
YOU?

In the second example that utilizes the lambda expression syntax, we didn’t create an additional file for a class that implements the interface, but we did define a class that implements the interface and make an object out of that class. It all happened on one line:

Consumer<String> shout = (String t) -> System.out.println(t.toUpperCase());

11.3.1. Explaining the Example

Let’s break it down:

Consumer<String> shout = (String t) -> System.out.println(t.toUpperCase());
// -------------------|-|-------------------------------------------------|
//         1          |3|                       2                         |
//                                    the lambda expression
  1. First, a reference variable named shout is declared with the type Consumer<String>;

  2. A lambda expression is used to create an object that has one method by defining what that method should do. In this case, we want the method’s type layout to match the abstract method accept in Consumer<String>, and it does.

  3. Assign the object’s reference to the variable.

Since we didn’t define the object’s method in some named class, it is considered an object of an unnamed class. That’s okay, so long we don’t need multiple objects of that class.

Test Yourself

  • Compile and run the example above!