This post is the first of a series covering the implementation of the home work for this MOOC by Oracle. The course is about Lambdas and Streams on Java 8, but I felt compelled to implement them also in Scala, and compare both implementations. On this post and the next two, I’ll try to explain the main differences between these implementations and the way both languages empower you to use high order functions as part of a functional programming way of solving problems.
Exercise 1: Create a string that consists of the first letter of each word in the list of Strings provided. HINT: Use a StringBuilder to construct the result.
Through Arrays.asList(“alpha“, “bravo“, “charlie“, “delta“, “echo“, “foxtrot“), we create a List object with the elements passed. In this case, we’re interested in the first letter of every word on the list, so for every element of the list, we extract its first character, appending it to a previously declared and initialised StringBuilder object. This object is used to capture the result, as advised.
It’s important to talk about the forEach method here, which is inherited by the List interface from Iterable. It’s not quite the same as the Stream#forEach method… in both cases, though, they receive an object implementing the Consumer interface as a parameter. As you may have guessed, Consumer is a functional interface, making it possible to replace it with a Lambda expression. In our case, our Lambda will be word –> result.append(word.charAt(0)), with word being the lambda parameter and result.append(word.charAt(0)) its body. This body is far from ideal though, since it’s being used to alter an external (to the lambda) object. In this case we can do it without losing determinism in the result, since the order of execution is guaranteed when calling Iterable#forEach, but the same can’t be said about Stream#forEach. When possible, we should aim to avoid side effects in our lambdas.
The problem begins sooner than the lambda, though. The semantics of the operation forEach comes with
SIDE EFFECTS, since a Consumer, by definition, takes something and returns nothing: whatever it does while consuming its input will have a
side effect, whether it’s on the input itself or on another entities is the discussion. But I digress…
Let’s see a possible implementation of this first exercise in Scala:
Let me say this first: this is terrible Scala code. You wouldn’t do this in Scala normally, but I am trying to keep it close to the way we solved the exercise in Java (as we were requested to use a StringBuilder to accumulate the result). Again, you wouldn’t do this unless you have a very powerful reason to do so.
About the code… in Scala, you can create and initialise collections on the fly, and that’s what we’re doing in line 4. You also don’t need to specify which implementation you want for the list, as you have to in Java (ie ArrayList). By default, Scala lists are immutable, although you could create a mutable one, as we’ll see in the next exercise. As in the Java example, for every element of the list, we extract the first character of the word (Scala strings don’t exist per se, Java ones are used directly by Scala) and we append it to the StringBuilder to construct the string we’ve been asked for. Let’s move on, nothing special here.
Exercise 2: Remove the words that have odd lengths from the list. HINT: Use one of the new methods from JDK 8.
The creation of the list is pretty straight forward, as in the example before, with the only difference of having to capture the list object in a variable, to illustrate the fact that we will be removing the elements from that very same list, rather than building a new one. This obeys to an strict (if you want) interpretation of the problem wording. Any Java collection contains a default implementation for the method removeIf. It takes a Predicate, and it will remove the elements of the collection for which the Predicate holds. And yes, Predicate is another functional interface, that’s why we can pass a lambda there. About the lambda itself, not much to say, it should be self-explanatory: it will hold for words with odd length.
I must confess I spent some time looking for a method which would allow me removing elements from a mutable list in Scala, but I couldn’t find it. I won’t be using the same approach as in the Java solution here, relaxing the interpretation of the problem enunciate. From our list of words, we filter the elements which length is even. The fact that we’re doing it with filterNot is just to annoy people, since it’s a bit counterintuitive. But in fact it’s quite trivial, really: just a negation of the condition passed to filter.
And, by the way, in case you’re puzzled by the function that we’re passing to the filterNot method, more specifically by the underscore, don’t worry too much. You’ll get a hold of it as soon as you relax and sit back. It’s just a placeholder. This…
_.length % 2 != 0
…is equivalent to…
word => word.length % 2 != 0
There are a lot more places where the underscore may appear, but I wouldn’t worry too much about it for now, if you’re not familiar with Scala.
Exercise 3: Replace every word in the list with its upper case equivalent. HINT: Again, use one of the new methods from JDK 8.
Any Java List contains a default implementation for the method replaceAll. It takes a UnaryOperator, which will operate on an operand and produce a result, being operand and result from the same type. And yes, UnaryOperator is also a functional interface, subsequently we can pass a lambda there too. The lambda will make every string in the list go uppercase, though a call to the appropriate method of the String class. When a lambda just calls a method, it’s known as a method reference lambda.
In this case, though, I found a method on the MutableList interface (inherited from SeqLike) which allows us to replace all the elements of a list with different versions of themselves, in the very same (mutable) list, rather than generating a new one on the fly. This method is transform. We don’t need to drop elements from the mutable list this time, which seemed to be the no game factor for the Scala mutable lists (unless I’m missing something, which may very well be the case). Through transform, every word in the list will be replaced or transformed by itself in uppercase. If we have a look at its prototype:
def transform(f: (A) ⇒ A)
In Scala, functions are first class citizens. I never really understood this sentence until I didn’t see how functions have been introduced in Java. In the case of transform, it receives a function from A to A as a parameter. This is pretty much equivalent to the Java UnaryOperator functional interface. After every word is transformed to its uppercase equivalent, the list position that it used to be on is updated with the new version of the word.
In Scala, when a method does not receive any parameters, you can just ignore the parenthesis when calling it.
Exercise 4: Convert every key-value pair of the map into a string and append them all into a single string, in iteration order. HINT: Again, use a StringBuilder to construct the result String. Use one of the new JDK 8 methods for Map.
Not a lot to say from lines 2 to 6: just create a map and initialise it with a few values. As in exercise 1, we’re asked to accumulate results in an StringBuilder, and we do so. Map.entrySet returns a set (unsurprisingly) of Map.Entry‘s. Being a set, it allows us to do our already seen Iterable#forEach, where we can specify what we want to do on every element of the iterable through a lambda. This lambda will just extract every entry key and value, appending them to our StringBuilder accumulator.
On line 3, we create and initialise our TreeMap in Scala. On line 6, we map every element of the map. Don’t get confused by the unfortunate use of the word map in two different places. The map object will hold a TreeMap map. The map method has nothing to do with it. Map is a method which can be applied to any Scala Collection, and which will receive a function and apply to the elements of the collection, transforming them. It’s the same concept as in the previous exercise, with the subtle difference of allowing us to transform every element of the collection into anything, really, rather than into something of the same type. In this case, we’re concatenating the key and the value of every entry, and the resulting collection would contain, rather than entries, words conformed by the key and the value of every entry. That resulting collection gets invoked by the foreach, which gets every word and appends it into our accumulator.
Map elements in Scala are tuples, which allow accessing its elements through tuple._1 and tuple._2 syntax. More on Scala tuples, in case you’re interested.
Exercise 5: Create a new thread that prints the numbers from the list. HINT: This is a straightforward Lambda expression.
Creating a new Thread object in Java requires you to pass a Runnable. An interface in Java doesn’t get more functional than this one: its only method enables us to use a lambda where a Runnable is expected. In this case, we’re using what it’s known as a Supplier lambda expression, in which the lambda parameter section is empty, but something is happening on its body.
This something is just a list, which elements we iterate though and print in no special fashion. We’ve seen this all before in the above exercises.
After creating the Thread object, we start it and we’re done here.
The Scala implementation of this exercise is pretty much the same as in Java, but we’re kind of limited by interoperability issues, so we can’t use Java lambdas when writing Scala. That forces us to create an anonymous inner class on the fly to define our Runnable. Inside it, though, in its run method, we use the Scala List foreach method, to print them. As stated before, functions being first-class citizens in Scala allows us to pass them as parameters, so we can pass the print function to the foreach method, which will be reflected on every element of the collection being printed. Effectively, it’s pretty much the same as the method reference lambdas.