KotlinCS 124 LogoJava

Throwing Exceptions

class Container(size: Int) {
init {
require(size >= 0)
}
private var values = Array<Int>(size) { 0 }
}
val good = Container(8)
val ohnoes = Container(-1)

Next we’ll continue exploring Kotlin exceptions. First, we’ll look at how we can throw our own exceptions. Next, we’ll discuss the different types of Kotlin exceptions and how they are used. Aren’t errors fun? Let’s do this.

throw
throw

Last time we looked at try-catch, Kotlin’s syntax for handling exceptions. But where do exceptions come from?

Some exceptions are generated directly by Kotlin. For example, executing this code will generate a NullPointerException:

val o: Any? = null
println(o!!.hashCode())

However, Kotlin also provides a way for us to throw exceptions directly—the throw keyword! Let’s see how that works.

// throw

When to throw
When to throw

Kotlin has several built-in exceptions that you may find useful in your own code. throw is particularly useful when there is no valid way to continue. Maybe your method has received bad input, or encounters a situation that it is unprepared to handle. We’ll discuss this more in future lessons.

We’ve already seen one convenient way to throw exceptions in Kotlin: require. require throws an IllegalArgumentException, but provides syntax that is somewhat more convenient that throwing directly. Let’s look at an example:

// When to throw

Practice: Return an Exception

Created By: Geoffrey Challen
/ Version: 2020.11.0

Create method exceptionable accepting a single Int as a parameter. You should require that the int is between 0 and 3, inclusive.

If the Int is 0, you should return an IllegalStateException. If it's 1, you should return a NullPointerException. If it's 2, you should return a ArithmeticException. And if it's 3, you should return a IllegalArgumentException.

Errors
Errors

In Kotlin the Throwable class is the superclass of all objects that can be thrown, either using throw or in case of an error like a null pointer exception. Throwable has two subclasses that are handled differently. We’ve been discussing exceptions so far.

The second category is errors. These are serious problems that you should not try to handle. According to the documentation:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.

However, it is worth noting that assert generates an error. It is also possible to generate errors through programming errors, like this one:

fun add(value: Int) {
return add(value)
}
println(add(1))

This generates a StackOverflowError. You may get much more familiar with this kind of error soon…

Checked Exceptions
Checked Exceptions

For those of you familiar with Java, you may remember that the Java compiler forces you to handle certain types of exceptions, known as checked exceptions.

Kotlin differs from Java in this regard. Kotlin does not have checked exceptions. It does not force you to handle any exceptions. There are reasons for this design choice, which you can start reading more about here if you are interested.

Practice: Restaurant Capacity Manager

Created By: Geoffrey Challen
/ Version: 2021.9.0

Create a class CapacityManager to manage restaurant dining capacity. You should provide a primary constructor that allows the capacity of the restaurant to be set as an Int when the CapacityManager is created. You don't need to provide either a getter or a setter for the capacity, which will not change.

Provide two methods: enter and leave. Each accepts a count of guests (as an Int) that are either arriving (enter) or departing (leave) from the restaurant. Both should return the number of guests after the operation completes as an Int. If the count is negative or zero, both methods should throw an IllegalArgumentException. enter should also throw a IllegalStateException if the new party would exceed the capacity of the restaurant. This restaurant also refuses to admit parties larger than 8, and if one arrives enter should throw a PartyTooLarge exception, which you can create without importing:

leave should also throw an IllegalStateException if a party leaves that is larger than 8, or if the leave would cause the number of diners to fall below zero, since both represent mistakes in our enter code.

In both enter and leave, if an exception is thrown, the number of diners should not be changed.

When you are finished, here is how your class should work:

Do not use assert to solve this problem! However, you can still use require and check to generate some (but not all) of the exceptions mentioned above.

Homework: Location Visit Tracker

Created By: Geoffrey Challen
/ Version: 2022.10.0

Let's create a program to allow us to track visits to different locations. Create a class TrackVisits with a single primary constructor accepting a List of Strings, each identifying a place that you should track visits for. If the list passed the constructor is empty, throw an IllegalArgumentException. (As a reminder, you can do this using require in Kotlin.)

Also provide two instance methods:

  1. countVisit accepts a String and increments the visit count for that location
  2. getVisitCount accepts a String and returns the visit count for that location

If the String passed to either method was not passed to the constructor, throw a PlaceNotFound exception, which you can create without importing:

You must use a Map to solve this problem, and should not declare any other fields.

CS People: Timnit Gebru
CS People: Timnit Gebru

Timnit Gebru’s is the co-founder of Black in AI and the founder of the Distributed Artificial Intelligence Research Institute. Her work identifying bias in artificial intelligence and leadership drawing attention to ethical issues in AI prompted her abrupt departure from Google, specifically due to work that she and co-authors hoped to publish drawing attention to weaknesses and biases inherent in large langauge models. That work seems even more relevant today, with the rise of GPT-3, ChatGPT, and the growing use of large language models in other contexts and for a wide variety of purposes.

In the video below, she discusses one component of her work, specifically improving the understanding of the datasets used to train and generate AI models:

More Practice

Need more practice? Head over to the practice page.