Does Java 8′s lambda capability make Scala obsolete?

Share Button

How does using Java 8's lambdas compare to writing Scala?I didn’t think anyone would seriously ask this question. However, after yesterday’s post about why your company should let you use Scala at work, which used a simple example showing the use of lambdas in Scala, I had someone write in the comments:

“java 8 equivalent of your example would be identical, no need for Scala…”

and someone else commented on Twitter:

The call to compare against Java 8 is a fair one, so here we go…

Scala Lambda Example Converted to Java 8

So here’s the original imperative Java code example:

    private int balanceFor(String customerName, String accountName,
                           List<CustomerSummaryDTO> result) {
        for (CustomerSummaryDTO customer : result) {
            if (customer.getName().equals(customerName)) {
                for (AccountSummaryDTO account : customer.getAccounts()) {
                    if (account.getName().equals(accountName)) {
                        return account.getBalance();
                    }
                }
            }
        }
        throw new NoSuchElementException("Account not found");
    }

And here’s the original Scala translation that I published in 2010:

def balanceFor(customerName: String, accountName: String,
               result: Iterable[CustomerSummaryDTO]) =
    result.find(_.getName == customerName).get
      .getAccounts().find(_.getName == accountName).get
      .getBalance

Now, here’s a Java 8 translation of the above (you’ll have to scroll!):

private int balanceFor(String customerName, String accountName,
                     List<CustomerSummaryDTO> result) {
  return result.stream().filter(c -> c.getName().equals(customerName)).findFirst().get()
    .getAccounts().stream().filter(a -> a.getName().equals(accountName)).findFirst().get()
    .getBalance();
}

You can see that, even in this very simple example, there is a lot of difference between the Java and Scala. They’re certainly not “identical”.

The biggest difference is that Java 8 has not implemented combinators (map(), filter(), etc.) on Collections. Instead, you have to explicitly convert a collection into a Stream before you can start to use lambdas to work on collections in a functional style. (Collection inherits the Iterable.forEach() method, but it’s hard to argue that that’s a functional style when it returns void.) The design of the Stream API, in particular the way it separates transformation operations from terminal operations, also means that the task here of “get me the first object that matches this predicate” requires two method calls: filter(predicate) followed by findFirst(), while Scala’s collections API combines these two into a single method: find(predicate).

There are other subtleties that make a differences, as well. Scala allows the creation of functions with anonymous parameters that are used once (the underscore), but Java 8 always requires a parameter list. This can make a big difference in noise when you make heavy use of lambdas. Scala’s use of == to test object equality rather than equals() is not only shorter, but also null-safe. If either of the getName() calls above could result in a null, that Java 8 code would be wrong and the correct code would be a whole lot gnarlier.

flatMap() to the rescue?

I dropped an update in the middle of yesterday’s “From the Archives” post saying I wouldn’t actually write Scala like the above today, but would have written it using a for comprehension, and returning the Option:

def balanceFor(customerName: String, accountName: String,
               result: Iterable[CustomerSummaryDTO]): Option[Int] = {
  (for {
    customer <- result if customer.getName == customerName
    account <- customer.getAccounts if account.getName == accountName
  } yield account.getBalance)
  .headOption
}

Part of the reason the earlier examples are complicated is because they are operating on one collection that may return a result, then map that (optional) result to child collection and filter to possibly get a result. For comprehensions in Scala are designed to handle just such algorithms (which occur more frequently than you might think). For comprehensions are in fact just syntactic sugar, though, with the compiler translating them into map, filter and flatMap calls.

Java 8 Streams also have flatMap, so I thought it fair to investigate with it could be used to simplify the Java 8 code from above. Let’s see…

private Optional<Integer> balanceFor(String customerName, String accountName,
                     List<CustomerSummaryDTO> result) {
  return result.stream().filter(c -> c.getName().equals(customerName))
    .flatMap(c -> c.getAccounts().stream())
    .filter(a -> a.getName().equals(accountName)).findFirst()
    .map(AccountSummaryDTO::getBalance);
}

Okay, that looks a bit better than what we had before. We’ve even benefited a bit from the fact that Optional has some combinators defined (that last map() is Optional.map, not Stream.map).

Observe, though, that flatMap() is still complicated by the fact that everything is Stream-oriented. If flatMap() were able to receive a Collection as the result of lambda instead of demanding a Stream, we could have actually used the method reference CustomerSummaryDTO::getAccounts here, which would have been beautiful. Instead, to make good use of lambdas with collections in Java 8, you have to continually step into and out of the Stream abstraction, which is a real shame. I thought the default methods added to Java 8 were going to allow all kinds of fancy new methods to be added to existing collection types, but instead they’ve gone down this road of pushing everything into Stream. I would guess this decision wasn’t made lightly, but I’m disappointed nonetheless.

Just in case you think that’s it…

Maybe you’re looking at the above code and thinking, “Hey, that Java 8 has come pretty close to the Scala in some examples.” I guess that’s true. The thing is, though, that Scala was never just Java + lambdas (even if I might have naively presented it as such 4 years ago). It has a whole bunch of other language features that are supremely useful and which Java doesn’t have. Just to name three of my favourites:

  • pattern matching
  • literal syntax for tuples
  • named and default parameters

And the thing you find with Scala is that, the more you use it, the more you learn how to use these features together and how they combine really well to make simple, readable programs that do powerful things with relatively little code.

Want to learn more?

If you want to find out more about the other features of Scala, I did a presentation a few years ago called ‘Top 10 Reasons Java Programs Envy Scala‘ that gives a nice overview.

If you’re convinced that now’s the time to start learning Scala, you might want to get one of these…

Share Button

4 thoughts on “Does Java 8′s lambda capability make Scala obsolete?

  1. The only thing that can make Scala absolutely obsolete is a better Scala (another language with the same features, but implemented better). I don’t see that happening any time soon.

    But the question is if Java8 will prevent adoption from developers who otherwise would have switched to Scala *only* because of lambdas. I fear that the answer is: yes. Many developers will stay in Java8 for years to come, either because they don’t need anything else or because their managers won’t let them try other languages.

    For some others Java8 will be an eye-opener and maybe “hungry for more” they will discover Scala. We’ll see…

  2. Pingback: Why Your Company Should Let You Use Scala at Work - Evolvable MeEvolvable Me

  3. Pingback: INTERESTING FINDS WEEK OF SEPTEMBER 7, 2014 | Stack Trace

  4. I think the error here comes in at looking at things at a top down level (a sociological thesis in itself) At the lower levels what is the difference between the scala byte-codes and the java byte-codes running in the JVM?

    personally I like the newer server side chrome v8 runtimes as I like this idea of mutating run-time objects, scala gives me the chance to do this (I think)

    JavaFx2 is a great framework for rich desktop applications, and if ever there was a overly verbose framework vastly improved by a scala re write check out scalaFx

    the big push for java came with the productivity improvement of a strongly typed language, that is you can look at java classes in a schematic sense, this meant we could easily understand each others code as opposed to languages like C++

    the biggest problem with scala is going to be poor functional coding with little documentation

    with great power comes great responsibility

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>