This post is an excerpt from the Scala Cookbook. (This is the introduction to Chapter 10, Collections.)
The Scala collection classes are rich, deep, and differ significantly from the Java collections, all of which makes learning them a bit of a speed bump for developers coming to Scala from Java.
When a Java developer first comes to Scala, she might think, “Okay, I’ll use lists and arrays, right?” Well, not really. The Scala List
class is very different from the Java List
classes -- including the part where it’s immutable -- and although the Scala Array
is an improvement on the Java array
in most ways, it’s not even recommended as the “go to” sequential collection class.
Because there are many collections classes to choose from, and each of those classes offers many methods, a goal of this chapter (and the next) is to help guide you through this plethora of options to find the solutions you need. Recipes in these chapters will help you decide which collections to use in different situations, and also choose a method to solve a problem. To help with this, the methods that are common to all collections are shown in this chapter, and methods specific to collections like List
, Array
, Map
, and Set
are shown in Chapter 11.
Three important concepts
There are a few important concepts to know when working with the methods of the Scala collection classes:
- What a predicate is
- What an anonymous function is
- Implied loops
A predicate is simply a method, function, or anonymous function that takes one or more parameters and returns a Boolean
value. For instance, the following method returns true
or false
, so it’s a predicate:
def isEven (i: Int) = if (i % 2 == 0) true else false
That’s a simple concept, but you’ll hear the term so often when working with collection methods that it’s important to mention it.
The concept of an anonymous function is also important. They’re described in depth in Recipe 9.1, but here’s an example of the long form for an anonymous function:
(i: Int) => i % 2 == 0
As shown in Recipe 9.1, that long form can be reduced to the following shorter form:
_ % 2 == 0
That doesn’t look like much by itself, but when it’s combined with the filter
method on a collection, it makes for a lot of power in just a little bit of code:
// create a list scala> val list = List.range(1, 10) list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9) // get only the even values from the list scala> val evens = list.filter(_ % 2 == 0) events: List[Int] = List(2, 4, 6, 8)
This is a nice lead-in into the third topic: implied loops. As you can see from that example, the filter
method contains a loop that applies your function to every element in the collection and returns a new collection. You could live without the filter
method and write equivalent code like this:
for { e <- list if e % 2 == 0 } yield e
but I think you’ll agree that the filter
approach is both more concise and easier to read.
Collection methods like filter
, foreach
, map
, reduceLeft
, and many more have loops built into their algorithms. As a result, you’ll write far fewer loops when writing Scala code than with another language like Java.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |