TenMinuteTutor

Coding, maths and art

Functional interfaces and lambdas

Traditionally, in Java, functions didn’t really exist as a thing in their own right. The only existed as methods in a class or interface. To emulate functional programming, it was often necessary to define a class to contain the function - or maybe use an interface and anonymous classes. Either way the syntax was clunky.

As of Java 8, there is better support for functional programming, including functional interfaces and lambda functions. Here we will look at the traditional method, then see how the new syntax makes life easier.

Previous Java solution

Suppose we have a list of strings, and we would like to sort it. We would like to sort the strings in a particular way - we want the sort order to be case insensitive. Here is how you might have done this in the days before lambda expressions:

package com.tenminutetutor.com;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class ComparisonExample {

    public static void main(String[] args) {

        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("pear");
        fruits.add("Banana");
        fruits.sort(new CompareFruits());
        System.out.println(fruits);
    }

    private static class CompareFruits implements Comparator<String> {

        @Override
        public int compare(String s1, String s2) {
            return s1.compareToIgnoreCase(s2);
        }
    }

}

The List.sort function takes an object parameter which controls the sort order. The object must implement the Comparator interface, which means that it must provide a compare method. This method compares 2 values and returns -1, 0 or +1 to indicate if the first is less than, equal to or greater than the second. This should all be fairly familiar to you if you have used earlier versions of Java.

Using anonymous classes

The code above is a little long-winded. You will typically use an anonymous class instead of actually creating a named class like CompareFruits. Here is an example:

package com.tenminutetutor.com;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class ComparisonExample {

    public static void main(String[] args) {

        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("pear");
        fruits.add("Banana");
        fruits.sort(new Comparator<String>() {

            @Override
            public int compare(String s1, String s2) {
                return s1.compareToIgnoreCase(s2);
            }
        }
        );
        System.out.println(fruits);
    }

}

Functional interfaces

The reason we looked at the original, long-winded solution, is that Java 8 has introduced a new term, the functional interface. A functional interface is simply any interface that contains exactly one abstract method. Comparator is an example of a functional interface. Our class CompareFruits is an implementation of that functional interface.

private static class CompareFruits implements Comparator<String> {

    @Override
    public int compare(String s1, String s2) {
        return s1.compareToIgnoreCase(s2);
    }
}

Lambda expressions

In Java 8, and alternative way to implement a functional interface is to use a lambda expression. Here is what our CompareFruits class would look like expressed as a lambda:

(a, b) -> a.compareToIgnoreCase(b)

Placing this in our original code we have:

package com.tenminutetutor.com;

import java.util.ArrayList;
import java.util.List;

public class ComparisonExample {

    public static void main(String[] args) {

        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("pear");
        fruits.add("Banana");

        fruits.sort( (a, b) -> a.compareToIgnoreCase(b) );

        System.out.println(fruits);
    }

}

This is much shorter than our previous code, and more to the point it is easier to read, because we have removed all the redundant clutter. Lets look at what we have removed, and why:

  • We don’t need the class name, CompareFruits (Java has always allowed us to use an anonymous class).
  • We don’t actually need specify the interface, Comparator. We know that the sort method of List<String> requires a function with the signature int compare(String a, String b)
  • In fact, we don’t really care what the function is called. We are already using an anonymous class, but we can also use an anonymous method.
  • We don’t need to specify that the function parameters are Strings, we can infer that, again because the sort method requires a function that takes two string arguments.
  • Finally, we don;t need to specify the return type, once again we can infer that an int is required.

Removing all the unnecessary junk leaves us with just:

(a, b) -> a.compareToIgnoreCase(b)