Kotlin Flow Control
Previous | Table of Contents | Next |
Kotlin Operators and Expressions | An Overview of Kotlin Functions and Lambdas |
Regardless of the programming language used, application development is largely an exercise in applying logic, and much of the art of programming involves writing code that makes decisions based on one or more criteria. Such decisions define which code gets executed, how many times it is executed and, conversely, which code gets by-passed when the program is executing. This is often referred to as flow control since it controls the flow of program execution. Flow control typically falls into the categories of looping control (how often code is executed) and conditional flow control (whether or not code is executed). This chapter is intended to provide an introductory overview of both types of flow control in Kotlin.
Looping Flow Control
This chapter will begin by looking at flow control in the form of loops. Loops are essentially sequences of Kotlin statements which are to be executed repeatedly until a specified condition is met. The first looping statement we will explore is the for loop.
The Kotlin for-in Statement
The for-in loop is used to iterate over a sequence of items contained in a collection or number range.
The syntax of the for-in loop is as follows:
for variable name in collection or range { // code to be executed }
In this syntax, variable name is the name to be used for a variable that will contain the current item from the collection or range through which the loop is iterating. The code in the body of the loop will typically use this name as a reference to the current item in the loop cycle. The collection or range references the item through which the loop is iterating. This could, for example, be an array of string values, a range operator or even a string of characters.
Consider, for example, the following for-in loop construct:
for (index in 1..5) { println("Value of index is $index") }
The loop begins by stating that the current item is to be assigned to a constant named index. The statement then declares a closed range operator to indicate that the for loop is to iterate through a range of numbers, starting at 1 and ending at 5. The body of the loop simply prints out a message to the console indicating the current value assigned to the index constant, resulting in the following output:
Value of index is 1 Value of index is 2 Value of index is 3 Value of index is 4 Value of index is 5
The for-in loop is of particular benefit when working with collections such as arrays. In fact, the for-in loop can be used to iterate through any object that contains more than one item. The following loop, for example, outputs each of the characters in the specified string:
for (index in "Hello") { println("Value of index is $index") }
The operation of a for-in loop may be configured using the downTo and until functions. The downTo function causes the for loop to work backwards through the specified collection until the specified number is reached. The following for loop counts backwards from 100 until the number 90 is reached:
for (index in 100 downTo 90) { print("$index.. ") }
When executed, the above loop will generate the following output:
100.. 99.. 98.. 97.. 96.. 95.. 94.. 93.. 92.. 91.. 90..
The until function operates in much the same way with the exception that counting starts from the bottom of the collection range and works up until (but not including) the specified end point (a concept referred to as a half closed range):
for (index in 1 until 10) { print("$index.. ") }
The output from the above code will range from the start value of 1 through to 9:
1.. 2.. 3.. 4.. 5.. 6.. 7.. 8.. 9..
The increment used on each iteration through the loop may also be defined using the step function as follows:
for (index in 0 until 100 step 10) { print("$index.. ") }
The above code will result in the following console output:
0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90..
The while Loop
The Kotlin for loop described previously works well when it is known in advance how many times a particular task needs to be repeated in a program. There will, however, be instances where code needs to be repeated until a certain condition is met, with no way of knowing in advance how many repetitions are going to be needed to meet that criteria. To address this need, Kotlin includes the while loop.
Essentially, the while loop repeats a set of tasks while a specified condition is met. The while loop syntax is defined as follows:
while condition { // Kotlin statements go here }
In the above syntax, condition is an expression that will return either true or false and the // Kotlin statements go here comment represents the code to be executed while the condition expression is true. For example:
var myCount = 0 while (myCount < 100) { myCount++ println(myCount) }
In the above example, the while expression will evaluate whether the myCount variable is less than 100. If it is already greater than 100, the code in the braces is skipped and the loop exits without performing any tasks.
If, on the other hand, myCount is not greater than 100 the code in the braces is executed and the loop returns to the while statement and repeats the evaluation of myCount. This process repeats until the value of myCount is greater than 100, at which point the loop exits.
The do ... while loop
It is often helpful to think of the do ... while loop as an inverted while loop. The while loop evaluates an expression before executing the code contained in the body of the loop. If the expression evaluates to false on the first check then the code is not executed. The do ... while loop, on the other hand, is provided for situations where you know that the code contained in the body of the loop will always need to be executed at least once. For example, you may want to keep stepping through the items in an array until a specific item is found. You know that you have to at least check the first item in the array to have any hope of finding the entry you need. The syntax for the do ... while loop is as follows:
do { // Kotlin statements here } while conditional expression
In the do ... while example below the loop will continue until the value of a variable named i equals 0:
var i = 10 do { i-- println(i) } while (i > 0)
Breaking from Loops
Having created a loop, it is possible that under certain conditions you might want to break out of the loop before the completion criteria have been met (particularly if you have created an infinite loop). One such example might involve continually checking for activity on a network socket. Once activity has been detected it will most likely be necessary to break out of the monitoring loop and perform some other task.
For the purpose of breaking out of a loop, Kotlin provides the break statement which breaks out of the current loop and resumes execution at the code directly after the loop. For example:
var j = 10 for (i in 0..100) { j += j if (j > 100) { break } println("j = $j") }
In the above example the loop will continue to execute until the value of j exceeds 100 at which point the loop will exit and execution will continue with the next line of code after the loop.
The continue Statement
The continue statement causes all remaining code statements in a loop to be skipped, and execution to be returned to the top of the loop. In the following example, the println function is only called when the value of variable i is an even number:
var i = 1 while (i < 20) { i += 1 if (i % 2 != 0) { continue } println("i = $i") }
The continue statement in the above example will cause the println call to be skipped unless the value of i can be divided by 2 with no remainder. If the continue statement is triggered, execution will skip to the top of the while loop and the statements in the body of the loop will be repeated (until the value of i exceeds 19).
Break and Continue Labels
Kotlin expressions may be assigned a label by preceding the expression with a label name followed by the @ sign. This label may then be referenced when using break and continue statements to designate where execution is to resume. This is particularly useful when breaking out of nested loops. The following code contains a for loop nested within another for loop. The inner loop contains a break statement which is executed when the value of j reaches 10:
for (i in 1..100) { println("Outer loop i = $i") for (j in 1..100) { println("Inner loop j = $j") if (j == 10) break } }
As currently implemented, the break statement will exit the inner for loop but execution will resume at the top of the outer for loop. Suppose, however, that the break statement is required to also exit the outer loop. This can be achieved by assigning a label to the outer loop and referencing that label with the break statement as follows:
outerloop@ for (i in 1..100) { println("Outer loop i = $i") for (j in 1..100) { println("Inner loop j = $j") if (j == 10) break@outerloop } }
Now when the value assigned to variable j reaches 10 the break statement will break out of both loops and resume execution at the line of code immediately following the outer loop.
Conditional Flow Control
In the previous chapter we looked at how to use logical expressions in Kotlin to determine whether something is true or false. Since programming is largely an exercise in applying logic, much of the art of programming involves writing code that makes decisions based on one or more criteria. Such decisions define which code gets executed and, conversely, which code gets by-passed when the program is executing.
Using the if Expressions
The if expression is perhaps the most basic of flow control options available to the Kotlin programmer. Programmers who are familiar with C, Swift, C++ or Java will immediately be comfortable using Kotlin if statements, although there are some subtle differences.
The basic syntax of the Kotlin if expression is as follows:
if (boolean expression) { // Kotlin code to be performed when expression evaluates to true }
Unlike some other programming languages, it is important to note that the braces are optional in Kotlin if only one line of code is associated with the if expression. In fact, in this scenario, the statement is often placed on the same line as the if expression.
Essentially if the Boolean expression evaluates to true then the code in the body of the statement is executed. If, on the other hand, the expression evaluates to false the code in the body of the statement is skipped.
For example, if a decision needs to be made depending on whether one value is greater than another, we would write code similar to the following:
val x = 10 if (x > 9) println("x is greater than 9!")
Clearly, x is indeed greater than 9 causing the message to appear in the console panel.
At this point it is important to notice that we have been referring to the if expression instead of the if statement. The reason for this is that unlike the if statement in other programming languages, the Kotlin if returns a result. This allows if constructs to be used within expressions. As an example, a typical if expression to identify the largest of two numbers and assign the result to a variable might read as follows:
if (x > y) largest = x else largest = y
The same result can be achieved using the if within an expression using the following syntax:
variable = if (condition) return_val_1 else return_val_2
The original example can, therefore be re-written as follows:
val largest = if (x > y) x else y <pre> The technique is not limited to returning the values contained within the condition. The following example is also a valid use of if in an expression, in this case assigning a string value to the variable: <pre> val largest = if (x > y) "x is greatest" else "y is greatest" println(largest)
For those familiar with programming languages such as Java, this feature allows code constructs similar to ternary statements to be implemented in Kotlin.
Using if ... else … Expressions
The next variation of the if expression allows us to also specify some code to perform if the expression in the if expression evaluates to false. The syntax for this construct is as follows:
if (boolean expression) { // Code to be executed if expression is true } else { // Code to be executed if expression is false }
The braces are, once again, optional if only one line of code is to be executed.
Using the above syntax, we can now extend our previous example to display a different message if the comparison expression evaluates to be false:
val x = 10 if (x > 9) println("x is greater than 9!") else println("x is less than 9!")
In this case, the second println statement will execute if the value of x was less than 9.
Using if ... else if ... Expressions
So far we have looked at if statements which make decisions based on the result of a single logical expression. Sometimes it becomes necessary to make decisions based on a number of different criteria. For this purpose, we can use the if ... else if ... construct, an example of which is as follows:
var x = 9 if (x == 10) println("x is 10") else if (x == 9) println("x is 9") else if (x == 8) println("x is 8") else println("x is less than 8") }
Using the when Statement
The Kotlin when statement provides a cleaner alternative to the if ... else if ... construct and uses the following syntax:
when (value) { match1 -> // code to be executed on match match2 -> // code to be executed on match . . else -> // default code to executed if no match }
Using this syntax, the previous if ... else if ... construct can be rewritten to use the when statement:
when (x) { 10 -> println ("x is 10") 9 -> println("x is 9") 8 -> println("x is 8") else -> println("x is less than 8") }
The when statement is similar to the switch statement found in many other programming languages.
Summary
The term flow control is used to describe the logic that dictates the execution path that is taken through the source code of an application as it runs. This chapter has looked at the two types of flow control provided by Kotlin (looping and conditional) and explored the various Kotlin constructs that are available to implement both forms of flow control logic.
Previous | Table of Contents | Next |
Kotlin Operators and Expressions | An Overview of Kotlin Functions and Lambdas |