Scala’s flow control is more advanced than Java.
Condition
Scala provides the same if/else
keywords as Java. They return a value, which is the value of the expression that is true after evaluation. For example,
val s = if (x > 0) 1 else -1
is the same as
if (x > 0) s = 1 else s = -1
In the first form, it can initialize a val
but in the second form s
needs to be a var
.
The expression is similar to ?:
operator in C++ and Java, but if/else in Scala can have statements inside.
An if
statement without the else
clause can yield a ()
if evaluation fails. So if (x > 0) 1
is equivalent to if (x > 0) 1 else ()
.
There are no switch
statement in Scala. Use pattern matching instead. @switch
can be applied to improve performance from decision tree to branch table at compile time, with a few constraints.
Loop
Scala has the same while
and do-while
loops as Java and C++:
while (n > 0) {
r = r * n
n -= 1
}
do {
r = r * n
n -= 1
} while (n > 0)
for
loop is more like Python:
for (i <- 1 to n)
r = r * i
Ranges created with the <-
symbol in for
loops are refereed to as generators. There are no break
and continue
keywords in Scala.
Note i to n
returns a Range
from 1 to n inclusive, and <-
makes i
traverse all values of the expression at its right side.
In Scala, it is possible to apply a function to all values in a sequence at once, reducing the use of loops.
Advanced for
Loop Usage
Multiple counters
Multiple generators of the form variable <- expression
separated by semicolon:
for (i <- 1 to 3; j <- 1 to 3) print(i + j)
It is preferred to write it in this form:
for {
i <- 1 to 3
j <- 1 to 3
} print(i + j)
Guard
Each generator can have a guard, a Boolean condition by if
:
for (i <- 1 to 3; j <- 1 to 3 if i != j) print(i + j)
No semicolon before the if
.
You can define variables to use in for
without the var
keyword:
for (i <- 1 to 3; from = 4 - i; j <- from to 3) print (i + j)
The content of a for
loop can be expressed in braces, replacing semicolons with newlines:
for { i <- 1 to 3
from = 4 - i
j <- from to 3
}
for
loop with counters (like Go): Scala collections offer a zipWithIndex
method that create a new collection with (elem, counter)
as elements.
for
Comprehensions
When the body of the for
loop starts with yield
keyword, then the for
loop constructs a collection of values. For example,
for {
i <- 1 to 3
square = i * i
} yield square
constructs a collection. Note variables inside for
loop don’t need a var
or val
quantifier. If the statement after yield
requires multiple lines, enclose them in {}
. In most cases, the for/yield
loop returns the same type of collections as input.
For comprehension is essentially the same as map
method available on Iterable
.
Patterns in for
expressions
for ((k, v) <- map) println(k + v)
traverses the maps and output keys and values bound to k
and v
. Match failures are silently ignored.
Guard can be applied, but it goes after the <-
symbol.
How Scala Compiler works with for
loops
- A simple
for
loop that iterates over a collection is translated to aforeach
method call on the collection. - A
for
loop with ayield
expression is translated to amap
call on the collection. - The guard is translated to one or more
withFilter
calls on the collection prior toforeach
ormap
call.
Thus it is more straightforward to avoid explicit for loop but use map
, foreach
, and filter
directly.
break
and continue
There are no break
and continue
keywords, but similar functionality can be implemented with scala.util.control.Breaks
. It offers two methods, break
and breakable
. break
will throw a BreakControl
exception and breakable
will catch it.
Break
breakable {
for (x <- xs) {
if (cond)
break
}
}
Continue
for (x <- xs) {
breakable {
if (cond)
break
}
}
Labeled Break
Breaks
object can be instantiated, and breakable
will only catch exception thown by break
in the same object.
Enumeration
Unlike Java, Scala does not have enumeration. Standard library provides an Enumeration
helper class.
Define enumeration as follow:
object TrafficLightColor extends Enumeration {
val Red, Yellow, Green = Value
}
Each gets an ID and name: ID defaults to one more than the previous one, starting from zero; name is the variable name.
So the enumeration can be accessed by TrafficLightColor.Red
, etc.
You can look up an enumeration value by its ID or name:
TrafficLightColor(0)
TrafficLightColor.withName("Red")
Exception
Scala exception works the same way as in Java. But Scala has no “checked” exceptions, i.e. you never have to declare a function of method might throw and exception. However, if you want, you can still do so, and it is required if the method will be called from Java code:
@throws(classOf[NumberFormatException])
def toInt(s: String) = s.toInt
A throw
expression has the special type Nothing
. If one branch in if/else
is Nothing
, the type of the if/else
is the type of the other branch.
The syntax of catch exceptions is modeled after the pattern matching syntax.
finally
clause is the same as in Java.