In real life, we do different things depending on the circumstances. For example, if it’s raining outside, I’ll probably grab an umbrella. If it’s sunny outside, I’ll grab my sunglasses. I do different things depending on the weather.
Similarly, we often need our code to do different things in different situations.
In this chapter, we’ll learn all about conditionals in Kotlin, which will allow us to change the way the code runs depending on circumstances!
Goldilocks and the Three Branches
You might have heard the fairy tale of Goldilocks and the Three Bears.
Papa Bear, Mama Bear, and Baby Bear lived in a quaint house nestled in the woods. One day, after preparing some porridge for breakfast, the three bears decided to go out for a leisurely stroll.
Meanwhile, a young girl named Goldilocks peeked in through the window and saw three bowls of porridge. Since she was hungry and saw nobody home, she decided to walk on inside and taste the porridge for herself.
- First, she tried Papa Bear’s porridge, and exclaimed, “It’s too hot!”
- Then she tried Mama Bear’s porridge, and complained, “It’s too cold!”
- Finally, she tried Baby Bear’s porridge, and found the temperature to be perfect. “It’s just right!” she said, and ate the entire bowl.
Let’s map out Goldilocks’ reaction to the three different bowls of porridge into a simple table:
Temperature | Goldilocks’ Reaction |
---|---|
Greater than 55°C | “It’s too hot!” |
Less than 40°C | “It’s too cold!” |
Anything else | “It’s just right!” |
Goldilocks responds differently depending on the temperature of the porridge.
- When it’s above 55°C, she says, “It’s too hot!”
- When it’s below 40°C, she complains, “It’s too cold!”
- But anything in between, and she’ll say, “It’s just right!”
We can write Kotlin code that will tell us which of these three things Goldilocks will say, based on the temperature of the porridge. In programming terms, the three different cases above - that is, the three different rows of the table - are called branches. If it helps, you can visualize the branches like you’d see on a tree:
So far, when we’ve run the code that we’ve written, every line of code has run. But now, we’re going to start writing code instead where only one of the branches will run each time. While your code is running, the path that is run - including the particular branch that it takes - is referred to as the execution path.
Here you can see the three possible execution paths that our Kotlin code could take, depending on the temperature:
Code constructs that choose between different branches (e.g., different responses from Goldilocks) based on some condition (e.g., the temperature) are called conditionals.
So how can we write Kotlin code that tells us how Goldilocks will respond to each bowl of porridge? Kotlin has a couple of conditionals that we can use. Let’s check ’em out!
Introduction to when
in Kotlin
Let’s look at that table again.
Temperature | Goldilocks’ Reaction |
---|---|
Greater than 55°C | “It’s too hot!” |
Less than 40°C | “It’s too cold!” |
Anything else | “It’s just right!” |
A table like this is easy to read and understand. We can just scan down the left-hand column, and when we find the temperature of the porridge that Goldilocks is eating, we look to the right to see how she will respond.
Kotlin gives us a powerful conditional called when
, which enables us to basically write that same table in our code. Here’s how it looks.
val temperature = 48 val reaction = when { temperature > 55 -> "It's too hot!" temperature < 40 -> "It's too cold!" else -> "It's just right!" }
Just to show how similar this is to our table, let’s add a little spacing and put the table next to it.
As you can see, this looks almost identical to our table above! Each line between the opening brace
{
and the closing brace}
is just a row from our table.The
reaction
variable will be assigned a different value depending on the value of thetemperature
variable:
- When the
temperature
is greater than 55, thenreaction
will be assigned"It's too hot!"
- When the
temperature
is less than 40, thenreaction
will be assigned"It's too cold!"
- Otherwise,
reaction
will be assigned"It's just right!"
To really understand when
, let’s look at the different parts:
- First, there’s
when
. This is a keyword that tells Kotlin that you want to do something different depending on the circumstances. Note thatwhen
is an expression, so it is evaluated and can be assigned to a variable. In this case, it will evaluate to a string, which will be assigned to thereaction
variable. - Next, there are
temperature > 55
andtemperature < 40
. These are called conditions. Conditions are expressions that evaluate to a Boolean.temperature > 55
just asks the question, “is thetemperature
variable is greater than 55?” If is indeed greater than 55, then it evaluates totrue
. Otherwise it evaluates tofalse
. When you need to compare numbers in Kotlin, you can use things like the greater-than sign>
or the less-than sign<
. The fancy term for these is comparison operators. See the chart below for more information. - When the condition evaluates to
true
, then thewhen
expression will evaluate to the value on the right side of the arrow .->
- At the bottom, we have
else
, which is a catch-all branch that’s used in case none of the conditions above it match.
The when
expression is quite helpful, and you’ll probably use it often. It also has some interesting characteristics. Let’s look at a few of them now.
The First True Condition Wins
Goldilocks just found some more porridge in the freezer, so let’s add another case for extremely cold temperatures:
val temperature = -5 val reaction = when { temperature > 55 -> "It's too hot!" temperature < 40 -> "It's too cold!" temperature < 0 -> "It's frigid!" else -> "It's just right!" }
In this code listing, because the
temperature
variable is set to-5
, you might expectreaction
to be set to"It's frigid!"
, but actually, it would be set to"It's too cold!"
.Why is that?
Because Kotlin works through the
when
cases from top to bottom.
- First,
temperature > 55
evaluates tofalse
, because -5 is not greater than 55.- Then,
temperature < 40
evaluates totrue
, because -5 is indeed less than 40.At this point, Kotlin uses
"It's too cold!"
, because it found a matching condition. So, the third case -temperature < 0
- is never evaluated.In other words, the first condition that evaluates to
true
will win.It’s easy to make sure that
"It's frigid"
is used when the temperature is below zero. Just put that case before the condition where the temperature is below 40 degrees, like this:val temperature = -5 val reaction = when { temperature > 55 -> "It's too hot!" temperature < 0 -> "It's frigid!" temperature < 40 -> "It's too cold!" else -> "It's just right!" }
Now, when you run this code, the
temperature < 0
case will run beforetemperature < 40
, soreaction
will be"It's frigid!"
.Exact Matches
Sometimes, instead of checking for a range of values (e.g., “anything greater than 55”, or “anything less than 40”) we only need to check for an exact match.
After the Three Bears discovered how much Goldilocks liked their porridge, they decided to write a cookbook that includes all of their family recipes. They opened an online store and began selling their books. Since the book is so popular, they wanted to give discounts to people who buy multiple copies of it.
Here’s the discount schedule:
Quantity Ordered Price Per Book 1 book $19.99 each 2 books $18.99 each 3 books $16.99 each 4 books $16.99 each 5 or more books $14.99 each We could write the
when
statement like this:val quantity = 3 val pricePerBook = when { quantity == 1 -> 19.99 quantity == 2 -> 18.99 quantity == 3 -> 16.99 quantity == 4 -> 16.99 else -> 14.99 }
However, Kotlin lets you shorten this up even more, by letting you specify a subject. Here’s how that looks:
val quantity = 3 val pricePerBook = when (quantity) { 1 -> 19.99 2 -> 18.99 3 -> 16.99 4 -> 16.99 else -> 14.99 }
In this example,
quantity
is called the subject of thewhen
expression. The subject can be any expression1, but here we just used the variablequantity
. Because we usedquantity
as the subject, we no longer had to putquantity ==
in each condition!There’s one more shortcut that Kotlin gives us, allowing us to make this even more concise. Since the price-per-book for 3 books is the same as that for 4 books, we can put those conditions on the same line, separated by a comma, like this:
val quantity = 3 val pricePerBook = when (quantity) { 1 -> 19.99 2 -> 18.99 3, 4 -> 16.99 else -> 14.99 }
Every Condition Must Be Accounted For
A
when
expression in Kotlin must include conditions for all possible values. For this reason, we say that awhen
expression must be exhaustive. This is also the reason that you usually need to include anelse
condition at the bottom.Sometimes you can be exhaustive even without an
else
condition. For example, consider a Boolean expression. As you recall, Booleans have only two possible values -true
andfalse
.Kotlin knows that a Boolean value can only ever be
true
orfalse
. So, as long as we have a branch for both of those cases, then we won’t need anelse
case.val isLightbulbOn = true val reaction = when (isLightbulbOn) { true -> "It's bright" false -> "I can't see" }
This isn’t the only occasion when you can omit the
else
condition. We’ll see this again when we learn about enum classes and sealed types.The
when
expression is powerful, and as a Kotlin developer, you’ll use it a lot! But it can be a bit heavy-handed for simple Boolean checks like for our lightbulb above. For these cases, Kotlin gives us a second kind of conditional.
if
ExpressionsWe can make our lightbulb example even more concise by using an
if
expression instead of awhen
expression.if
expressions are kind of likewhen
expressions, but they have a single condition, and two cases - one fortrue
and one forfalse
.Here’s how it looks:
val reaction = if (isLightbulbOn) "It's bright" else "I can't see"
And here are the different pieces:
if
is a keyword, likewhen
.isLightbulbOn
is the condition that is evaluated.
- If it evaluates to
true
, thenreaction
will be assigned"It's bright"
- If it evaluates to
false
, thenreaction
will be assigned"I can't see"
If you like, you may format this so that the branches are on different lines. For example:
val reaction = if (isLightbulbOn) "It's bright" else "I can't see"
You can also use braces
{
and}
around the branches. Doing so allows you to add statements to the branches, like this:var isLightbulbOn = true val reaction = if (isLightbulbOn) { isLightbulbOn = false "I just turned the light off." } else { isLightbulbOn = true "I just turned the light on." }
Generally, as a Kotlin programmer, if you’ve got a single condition to check, you use an
if
expression. If you’ve got multiple conditions to check, you use awhen
expression.It’s possible to use
if
for more than one condition. For example, remember our price-per-book lookup in Listing 3.5? We could rewrite it into anif
expression, like this:val pricePerBook = if (quantity == 1) 19.99 else if (quantity == 2) 18.99 else if (quantity == 3) 16.99 else if (quantity == 4) 16.99 else 14.99
If you find yourself doing this, stop!
Use a
when
expression instead!
when
andif
as StatementsSo far, we’ve used the
when
andif
conditionals as expressions, but you can also use them as statements. Here’s an example of using anif
statement in Kotlin:var wattage = 0 var lightbulbIsOn = true if (lightbulbIsOn) { wattage = wattage + 12 }
A few interesting things to note here:
- Unlike conditional expressions, conditional statements do not require an
else
branch. In the example above, iflightbulbIsOn
isfalse
, then the single branch that’s there (wattage = wattage + 12
) will simply never run.- We did not assign this
if
to a variable, because as you recall, you cannot assign a statement to a variable.Summary
In just three chapters, you’ve already learned a lot about Kotlin! You know about variables, types, expressions, statements, and functions. And in this chapter, you learned all about conditionals, including:
- What branches and conditions are.
- How the
when
expression can be used to pick a different value in different situations.- How an
if
expression can be a good fit for cases where you’ve only got two branches.- How you can use
when
andif
as statements.In this book, we’ve used a variety of types, such as integers, strings, and Booleans. In the next chapter, we’ll start putting variables and functions together to create our very own types, using classes and objects. These concepts will open many exciting possibilities for us to start writing more advanced programs. See you then!
Thanks to David Blanc, Raheel Naz, and Mohit for reviewing this chapter.
As of Kotlin 1.3, you can also capture the subject into a variable. ↩︎