Last Updated: February 25, 2016
·
6.937K
· benburton

Functional Programming in Java from a Scala Addict

I've been doing quite a bit of Scala development at work lately. Like many organizations that have started using Scala, ours has traditionally been a Java shop. The reasons we've been able to use Scala alongside Java is that both languages run on the JVM, and Scala has good interoperability with Java. These two features make it a reasonably easy sell to managers over other, similar languages. When you add Scala to your Java stack, work will typically be split between maintaining existing legacy applications written in Java in addition to working on the shiny, new stuff written in Scala. Although I believe that any good developer should have little trouble contextually switching between the two languages, there can be a bit of a rub between their different paradigms. Java is a traditional object-oriented language, whereas Scala blends object-oriented programming with functional programming. There are also a number of convenient language features in Scala (such as type inference, implicit type conversions, and for comprehensions) that can make Scala code much more concise and expressive than Java. It's easy to get used to writing things in a "Scala way," which can be a bit of a problem if you're not disciplined when you go back to writing Java in legacy systems. For example, it's not uncommon for me to write something resembling the following in Scala:

val activeUserIds = userService.getByGroupId(12).filter(_.isActive).map(_.id)

A verbose explanation of this code is that it obtains a collection of users for group id = 12, filters out those that are inactive, and assigns their ids to the activeUserIds value. If we assume that the id property of user is of type Int, then the resultant type of the value should be Seq[Int], a sequence of Scala integers. In Java, the code is usually quite different. In an imperative Java style, you'd probably be accustomed to writing something like this:

Collection<Integer> activeUserIds = new ArrayList<Integer>();

for (User user : userService.getByGroupId(12)) {
  if (user.isActive()) {
    activeUserIds.add(user.getId());
  }
}

It's my contention that despite your instincts, writing your code in this manner is better than trying to retrofit functional idioms into your Java code. When coming back to Java after a few weeks in Scala, my initial reaction was to try and appropriate the map and filter functions that I'd become accustomed to in functional programming. Google's Guava library does a really good job of providing this type of functionality. Predicate and Function objects describe the lambdas used above to specify criteria for mapping and filtering the values, and there are static Collections2#filter and Collections2#transform methods that can apply them to collections. Using Guava, writing out Java code in a functional style would look something like this:

Collection<Integer> activeUserIds = Collections2.transform(
  Collections2.filter(userService.getByGroupId(12),
    new Predicate<User>() {
      @Override
      public boolean apply(User user) {
        return user.isActive();
      }
    }), 
  new Function<User, Integer>() {
    @Override
    public Integer apply(User user) {
      return user.getId();
    }
  });

The the Java code is much more verbose than the Scala code, and it's also more verbose than the imperative Java code. This is chiefly because the language doesn't have first-class object definitions for lambda expressions. As a result, _.isActive in our Scala needs to be expressed as

new Predicate<User>() {
  @Override
  public boolean apply(User user) {
    return user.isActive();
  }
}

in our corresponding Java. The added syntactic information provides little value, and demonstrates the lack of the language's support for functional-style programming idioms. A big problem with this code is also that it's difficult to grok exactly what's going on; the anonymous class declarations for the lambda functions used in mapping and filtering are all crammed into the same expression. You can work around this by making local instance variables to hold them, and then putting the references into the calls to Collections2#filter and Collections2#transform:

Predicate<User> activeUserPredicate = new Predicate<User>() {
  @Override
  public boolean apply(User user) {
    return user.isActive();
  }
};

Function<User, Integer> userToUserIdFunction = new Function<User, Integer>() {
  @Override
  public Integer apply(User user) {
    return user.getId();
  }
};

Collection<Integer> activeUserIds = Collections2.transform(Collections2.filter(userService.getByGroupId(12), activeUserPredicate), userToUserIdFunction);

This reads a little bit better than before, but it's still not perfect. The problem with having a static method to apply filter and maps in the Collections2 class means that we need to pass collections around via nested function calls. Above, we don't naturally parse that the filter occurs before the transform, because the code doesn't read left-to-right as does this fragment from the Scala code:

users.filter(_.isActive).map(_.id)

Here it's much more obvious that the filter occurs before the map. It's possible that we could solve this problem by including filter and map functions on a Collection utility class:

public class FunctionalCollection<T> {

  private Collection<T> collection;

    public FunctionalCollection(Collection<T> collection) {
      this.collection = collection;
    }

    public FunctionalCollection<T> filter(Predicate<T> predicate) {
      Collection<T> filteredCollection = new ArrayList<T>(collection.size());
      for (T element : collection) {
        if (predicate.apply(element)) {
          filteredCollection.add(element);
        }
      }
      return new FunctionalCollection<T>(filteredCollection);
    }

    public <R> FunctionalCollection<R> map(Function<T, R> function) {
      Collection<R> mappedCollection = new ArrayList<R>(collection.size());
      for (T element : collection) {
        mappedCollection.add(function.apply(element));
      }
      return new FunctionalCollection<R>(mappedCollection);
    }

    public Collection<T> getCollection() {
      return collection;
    }
}

utilizing this, the syntax becomes:

Collection<Integer> activeUserIds =
  new FunctionalCollection<User>(userService.getByGroupId(12))
    .filter(activeUserPredicate)
    .map(userToUserIdFunction)
    .getCollection();

This does read a little better, but we still have the problem that the logic for the filter and map functions is still hidden away in Function and Predicate instance variables, and their behavior isn't obvious from the code unless we pick expressive variable names. Unfortunately, this isn't the only problem. The Guava team actually recommends NOT using the map and filter transformations unless you can be absolutely sure that the functional version results in fewer lines of code overall, and does not have a performance impact (reference: http://code.google.com/p/guava-libraries/wiki/FunctionalExplained)

So where does this leave us? Unfortunately, it means that we're back to square one. You shouldn't try to impose functional paradigms to Java code unless you have demonstrable performance gains. Using imperative style is also a bit better because it's idiomatic Java, which means that it should be readable by any competent Java developer. Unfortunately, Java as a language wasn't written with functional programming in mind. Although you might impulsively want apply functional programming practices to your Java code, it's not a good idea.

4 Responses
Add your response

What about lambdaj? http://code.google.com/p/lambdaj
It should be something like:

Collection<User> activeUsers = filter(havingValue(on(User.class).isActive()), userService.getByGroupId(12));
Collection<Integer> activeUserIds = extract(activeUsers, on(User.class).getId());

(Yes, it is still kind of ugly...)

over 1 year ago ·

@superfav Interesting. I hadn't heard of that when I wrote this. It does look a bit better, but I wonder if there are performance implications.

over 1 year ago ·

I'm also curious about trying Java Lambdas, which will be in JDK8 this year. The code for the above would be (I think):

userService.getByGroupId(12).filter(e -> e.isActive()).map(e -> e.getId());

This is very similar to the Scala version, without the _ shorthand. I don't know how this will compare in performance, but it does have the advantage of generating a lazy result.

over 1 year ago ·

I guess it's not possible to write the code directly in scala... writing it in java looks like a hack whatever we try and it looks alien to any java programmer...

over 1 year ago ·