benjiPosted under Java.

What use is a method that just returns its input? Surprisingly useful. A surprising use is as a way to convert between types.

There’s a well known trick that’s often used to work around Java’s terrible array literals that you may have come across. If you have a method that takes an array as an argument

public static void foo(String[] anArray) { }

Invoking foo requires the ugly

foo(new String[]{"hello", "world"});

For some reason Java requires the redundant “new String[]” here, even though it can be trivially inferred. Fortunately we can work around this with the following method which at first glance might seem pointless.

public static <T> T[] array(T... input) {
    return input;
}

It just returns the input. However it is accepting an array of Type T in the form of a varargs, and returning that array. It becomes useful due as now Java will infer the types and create the array cleanly. We can now call foo like so.

foo(array("hello", "world"));

That is a neat trick, but it really becomes useful in Java 8 thanks to structural typing of lambdas/method references and implicit conversions between types. Here’s another example of a method that’s far more useful than it appears at first glance. It just accepts a function and returns the same function.

public static <T,R> Function<T,R> f(Function<T,R> f) {
    return f;
}

The reason it’s useful is we can pass it any structurally equivalent method reference and have it converted to a java.util.function.Function, which provides us some useful utility methods for function composition.

Here’s an example. Let’s say we have a list of Libraries (Collection of Collection of Books)

interface Library {
    List<Book> books();
    static Library library(Book... books) {
        return () -> asList(books);
    }
}
 
interface Book {
    String name();
    static Book book(String name) { return () -> name; }
}
 
List<Library> libraries = asList(
    library(book("The Hobbit"), book("LoTR")),
    library(book("Build Quality In"), book("Lean Enterprise"))
);

We can now print out the book titles thusly

libraries.stream()
    .flatMap(library -> library.books().stream()) // Stream of libraries to stream of books.
    .map(Book::name) // Stream of names
    .forEach(System.out::println);

But that flatMap call is upsetting, everything else is using a method reference, not a lambda expression. I’d really like to write the following, but it won’t compile because flatMap requires a function that returns a Stream, rather than a function that returns a List.

libraries.stream()
    .flatMap(Library::books) // Compile Error, wrong return type.
    .map(Book::name) 
    .forEach(System.out::println);

Here’s where our method that returns its input comes in again. This compiles fine.

libraries.stream()
    .flatMap(f(Library::books).andThen(Collection::stream)) 
    .map(Book::name) 
    .forEach(System.out::println);  
 
public static <T,R> Function<T,R> f(Function<T,R> f) {
    return f;
}

This works because Library::books is equivalent to a Function<Library, List<Book>>, so passing it to the f() method implicitly converts it to that type. java.util.function.Function provides an andThen method which returns a new function which composes the two functions.

Now in this trivial example it’s actually longer to write this than the equivalent lambda, but it can be useful when combining more complex examples.

We can do the same thing with other functional interfaces. For example to allow Predicate composition or negation.

Here we have a handy isChild() method implemented for us on Person, but we really want the inverse – isAdult() check to pass to the serveAlcohol method. This sort of thing comes up all the time.

interface Person {
    boolean isChild();
    static Person child() { return () -> true; }
    static Person adult() { return () -> false; }
}
 
public static void serveAlcohol(Person person, Predicate<Person> isAdult) {
    if (isAdult.test(person)) System.out.println("Serving alcohol");
}

If we want to reuse Person::isChild we can do the same trick. The p() method converts the method reference to a Predicate for us, and we can then easily negate it.

serveAlcohol(adult(), p(Person::isChild).negate());
 
public static <T> Predicate<T> p(Predicate<T> p) {
    return p;
}

Have you got any other good examples?

2 Responses to “Implicit Conversions with Identity Functions”

  1. Sebastian Millies

    Nice post.

    If you don’t restrict yourself to the syntactic form of identity functions, an even more useful version of your method p() would be:

    public static Predicate p(Function f) {
    return f::apply;
    }

    with which you could in addition do things like the following:

    Function isSevenLong = x -> x.length() == 7;
    System.out.println(p(isSevenLong).test(“1234567”));

    A little side note: I wouldn’t call this “implicit” conversion. It’s quite explicit, because one has to call a conversion method.

  2. Sebastian Millies

    with regard to my previous post: Of course, method p has a type parameter T which is the type over which the Predicate is defined, and the Function goes from T to Boolean. I didn’t expect the angular brackets in the code to be interpreted as HTML…

Leave a Reply

  • (will not be published)