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:
@evolvable @gbougeard It would be nicer if you’d update the code to use Java 8. Plus I don’t agree, but that’s a different case 😉
— Erik Pragt (@epragt) August 4, 2014
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…
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…
what EXACTLY does Scala offer that Java 8 doesn’t?
Why would anyone choose the extra overhead of Scala when they can just do it in Java?
I’m more partial to Kotlin than Scala these days, but the many answers to this questions are here:
https://www.grahamlea.com/2013/02/a-new-java-library-for-amazing-productivity/
(And most of what that highlights as advantages of Scala are in Kotlin, too.)
Pingback: Why Your Company Should Let You Use Scala at Work - Evolvable MeEvolvable Me
Pingback: INTERESTING FINDS WEEK OF SEPTEMBER 7, 2014 | Stack Trace
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
Java 8 provides Lamda which is a functional programming equivalent to Scala, why one would use Scala when you are using Java 8. Its additional burden.
As Java 8 developer/Manager I don’t recommend using Scala as you can achieve the same functionality through JAVA 8.
“Lamda which is a functional programming equivalent to Scala” ?!!
Really? Is that what you think of Functional Programming? Just lambdas? You mean the result of all the efforts of multitude of computer scientists in the last couple of decades is just lambdas? Oh no! It’s a lot more than that, believe me.
Have you explored scala first?
Make your judgement after exploring the language thoroughly.
There is lot more in scala.
What i feel that semantic sugar is at the back burner but syntax/typo sugar are at the forefront without real tangible benefit and somehow it is drying out the essence of programmers who does not believe in memorization . of libraries or syntax sugars ( Ultimately Compiler generates the verbose code which the interpreter can understand ).
Thread safe architecture,immutability , function as first class should have been the priority instead all kinds of silly things i.e. instead of language it is trying to become a tool .
Tell me How Scala improves upon that when Java 8 with Default methods, functional interface , paralleled and thread safe collection with some verbosity better it ?? Those so called sugars .
Any practical Production Environment is constrained by I/O,Mem,Network Bandwidth/maintenance ( Visual/ verbose comments/verbose physical implementation without redundancy as much as possible as Business Analysis,Management /quality management and politics takes away 70% time).
I am a data modeler in traditional sense i.e. mostly worked with Traditional RDBMs and PL/SQl .
Trying to explore both java ,Scala as well as Big data spectrum and i must say mostly Pr and Sugar coating except java 8. Spark RDD except iterative processing for Mlib is it that great or cost effective i doubt .
Rest NO SQL DBs are single minded . so everyday with good backing of a new promoter a New Db is created.
Pingback: Java 8 Improvements | Jian Zhou
Pingback: Top 10 Reasons Java Programs Envy Scala (From The Archive) - Evolvable Me
Scala targets Java so the whole argument is mute. It’s like asking yourself should I use Microsoft Notepad or Wordpad. Both target mutability but Java has lambdas and Scala doesn’t oh well just drop one for the other when the job requires it, if doesn’t just use both and live with it. There’s also Clojure and Frege just thought I would throw that out there.
You’ve given a very ‘specific’ example of “something Scala debatably does more consicely … for now” – you’ve not answered the real question which is
DOES JAVA LAMDAS MAKE SCALA OBSOLETE
Not pithy one-off examples, but is there any BIG generalised classes of algorithm Java can not handle now but Scala does? To my mind, Scala (I hope) has a more intelligent FP engine than Java, but that is only because Java have just implemented FP. In future I would expect Java to destroy Scala in terms of efficiency
Fair call. After the test of time, now being surrounded by colleagues who’ve worked extensively in both Kotlin (which is quite similar to Scala in this respect) and Java 8+, I think the consensus is that the way Java 8+ forces developers into streams to make use of lambdas with collections is very clunky compared to the alternative languages. Lambdas in other usage scenarios are much more straightforward, but the ugliness of this pretty common use case has made a lot of people unenthusiastic about lambdas in Java 8+.