Welcome to our exploration of Compound Data Structures in Kotlin. Having navigated through Maps
, Sets
, and Lists
, we'll delve into nested maps
and lists
. These structures enable us to handle complex and hierarchical data, which is typical in real-world scenarios. This lesson will guide you through a recap of the basics, the creation and modification of nested maps and lists, as well as common error handling.
Here's a simple example of a school directory that uses a map with grades as keys and lists of students as values:
Just like their non-nested versions, creating nested structures is straightforward. Kotlin's data classes can be leveraged for better organization when needed.
Nested Map:
Nested List:
Lists within a Map:
The retrieval of values from nested maps
or lists follows rules similar to those for their non-nested counterparts.
From Nested Map:
The notation used to access values from a nested map involves chaining the access operations. Here's a breakdown:
-
Accessing the Outer Map:
nestedMap["fruit"]
: This accesses the value associated with the key"fruit"
in the outer map. The value is another map (mapOf("apple" to "red", "banana" to "yellow")
).
-
Safe Call Operator (
?.
):?.
is used to safely access the inner map. If"fruit"
does not exist innestedMap
, the expression evaluates tonull
, preventing a null pointer exception.
-
Accessing the Inner Map:
.get("apple")
: This accesses the value associated with the key"apple"
in the inner map. The value is"red"
, which is then printed.
Overall, println(nestedMap["fruit"]?.get("apple"))
safely accesses and prints the color of the apple from the nested map structure, outputting "red".
From Nested List:
From Both:
The modification of nested lists
and maps
can be done using mutable structures; Kotlin provides mutable variants for altering data.
Kotlin provides try
/catch
blocks for error handling. Below is an example of handling potential null pointer exceptions when accessing nested collections.
In this code block, the try
/catch
mechanism is used to handle potential exceptions gracefully when accessing a non-existent key in a nested map. Here's how it works:
-
try
Block:- The
try
block encloses the code that might throw an exception. - In this case,
nestedMap["fruit"]?.get("mango")
attempts to access the color of "mango" from the inner map associated with the "fruit" key. - Because "mango" does not exist in the map, the expression evaluates to
null
.
- The
-
Elvis Operator (
?:
):?:
is used to handle the case where the expression on the left isnull
.- If the result of
nestedMap["fruit"]?.get("mango")
isnull
, the Elvis operator triggers the throwing of aNoSuchElementException
with the message "Key not found!".
-
catch
Block:- The
catch
block captures theNoSuchElementException
if it is thrown in thetry
block. - Within the
catch
block,println(e.message)
prints the exception message "Key not found!" to the console.
- The
Alternatively, you can use Kotlin's let
function combined with the Elvis operator for more elegant error handling:
In this second example, let
is employed to safely operate on the non-null color value. If the color is found, it prints a success message and returns the color. If the value is null, the Elvis operator with run
provides a fallback, printing an error message and returning a default value. This approach offers a functional way to handle potential null values while maintaining code readability.
This use of error handling allows the program to avoid crashing due to accessing non-existent keys and provides user-friendly feedback instead.
Bravo! You've made a journey through nested lists
and maps
, essential concepts in the data-intensive programming world. We've learned how to create, access, and modify values in these complex structures and how to handle errors.
Up next, we have hands-on practice sessions to solidify your understanding of these concepts. Hold on to your hats!
