type | layout | title | description | partof | overview-name | num | outof | previous-page | next-page | new-version |
---|---|---|---|---|---|---|---|---|---|---|
section | multipage-overview | Anonymous Functions | This page shows how to use anonymous functions in Scala, including examples with the List class 'map' and 'filter' functions. | scala_book | Scala Book | 34 | 54 | set-class | collections-methods | /scala3/book/fun-anonymous-functions.html |
Earlier in this book you saw that you can create a list of integers like this:
valints=List(1,2,3)
When you want to create a larger list, you can also create them with the List
class range
method, like this:
valints=List.range(1, 10)
That code creates ints
as a list of integers whose values range from 1 to 10. You can see the result in the REPL:
scala>valints=List.range(1, 10) x:List[Int] =List(1, 2, 3, 4, 5, 6, 7, 8, 9)
In this lesson we’ll use lists like these to demonstrate a feature of functional programming known as anonymous functions. It will help to understand how these work before we demonstrate the most common Scala collections methods.
An anonymous function is like a little mini-function. For example, given a list like this:
valints=List(1,2,3)
You can create a new list by doubling each element in ints
, like this:
valdoubledInts= ints.map(_ *2)
This is what that example looks like in the REPL:
scala>valdoubledInts= ints.map(_ *2) doubledInts:List[Int] =List(2, 4, 6)
As that shows, doubledInts
is now the list, List(2, 4, 6)
. In this example, this code is an anonymous function:
_ *2
This is a shorthand way of saying, “Multiply an element by 2.”
Once you’re comfortable with Scala, this is a common way to write anonymous functions, but if you prefer, you can also write them using longer forms. Besides writing that code like this:
valdoubledInts= ints.map(_ *2)
you can also write it like this:
valdoubledInts= ints.map((i: Int) => i *2) valdoubledInts= ints.map(i => i *2)
All three lines have exactly the same meaning: Double each element in ints
to create a new list, doubledInts
.
The
_
character in Scala is something of a wildcard character. You’ll see it used in several different places. In this case it’s a shorthand way of saying, “An element from the list,ints
.”
Before going any further, it’s worth mentioning that this map
example is the equivalent of this Java code:
List<Integer> ints = newArrayList<>(Arrays.asList(1, 2, 3)); // the `map` processList<Integer> doubledInts = ints.stream() .map(i -> i * 2) .collect(Collectors.toList());
The map
example shown is also the same as this Scala code:
valdoubledInts=for (i <- ints) yield i *2
Another good way to show anonymous functions is with the filter
method of the List
class. Given this List
again:
valints=List.range(1, 10)
This is how you create a new list of all integers whose value is greater than 5:
valx= ints.filter(_ >5)
This is how you create a new list whose values are all less than 5:
valx= ints.filter(_ <5)
And as a little more complicated example, this is how you create a new list that contains only even values, by using the modulus operator:
valx= ints.filter(_ %2==0)
If that’s a little confusing, remember that this example can also be written in these other ways:
valx= ints.filter((i: Int) => i %2==0) valx= ints.filter(i => i %2==0)
This is what the previous examples look like in the REPL:
scala>valx= ints.filter(_ >5) x:List[Int] =List(6, 7, 8, 9) scala>valx= ints.filter(_ <5) x:List[Int] =List(1, 2, 3, 4) scala>valx= ints.filter(_ %2==0) x:List[Int] =List(2, 4, 6, 8)
The key points of this lesson are:
- You can write anonymous functions as little snippets of code
- You can use them with methods on the
List
class likemap
andfilter
- With these little snippets of code and powerful methods like those, you can create a lot of functionality with very little code
The Scala collections classes contain many methods like map
and filter
, and they’re a powerful way to create very expressive code.
You may be wondering how the map
and filter
examples work. The short answer is that when map
is invoked on a list of integers — a List[Int]
to be more precise — map
expects to receive a function that transforms one Int
value into another Int
value. Because map
expects a function (or method) that transforms one Int
to another Int
, this approach also works:
valints=List(1,2,3) defdouble(i: Int):Int= i *2//a method that doubles an IntvaldoubledInts= ints.map(double)
The last two lines of that example are the same as this:
valdoubledInts= ints.map(_ *2)
Similarly, when called on a List[Int]
, the filter
method expects to receive a function that takes an Int
and returns a Boolean
value. Therefore, given a method that’s defined like this:
deflessThanFive(i: Int):Boolean=if (i <5) trueelsefalse
or more concisely, like this:
deflessThanFive(i: Int):Boolean= (i <5)
this filter
example:
valints=List.range(1, 10) valy= ints.filter(lessThanFive)
is the same as this example:
valy= ints.filter(_ <5)