From Java to Kotlin - Exceptions & Collections

Exceptions

In Kotlin there’s no difference between checked and unchecked exceptions. Everything’s unchecked so you don’t need to specify any throws or handle any exceptions.

Try as an expressions

Just like if and when, try introduces an expression.
The returned value is either the last expression in the try block or the last expression in the catch block(s).

val a: Int? = try { parseInt(input) } catch(e: NumberFormatException) { null }

Collections

Kotlin has the same collection interfaces as Java, but it adds two new options.

Queue a collection used to hold multiple elements prior to processing (FIFO with the exception of priority queue)
Deque a collection used to hold multiple elements prior to processing (FIFO or LIFO)

Interfaces Hash table impl. Resizable Array Impl. Tree Impl. Linked List Impl. Hash table + Lined List Impl.
Set HashSet   TreeSet   LinkedHashSet
List   ArrayList   LinkedList  
Queue          
Deque   ArrayDeque      
Map HashMap   TreeMap   LinkedHashMap

Kotlin Collection Classes

Kotlin relies fully on Java standard library classes, extending them with additional functions.

Immutable and Mutable Collections

A mutable collection can be updated in place by adding, removing or replacing an element.

An immutable collection, while it provides the same operations-addition, removal or replacement via the operator functions, will end up producing a brand-new collection, leaving the original one untouched.

The most basic interface for working with collections is kotlin.Collection (List, Set)
The kotlin.MutableCollection interface allows you to modify the data in a collection.

Benefits of Mutable vs Immutable

You should try to use read-only interfaces everywhere in your code. Use the mutable variants only if you need it.

Sequences

A sequence returns values through an iterator. They’re great for scenarios when the size of the collection is not known in advance. It’s like a list that goes on and on.
You can convert any collection to a sequence as such

people.asSequence()
		.map(Person::name)
		.filter { it.startsWith("A") }
		.toList()

Lists

Kotlin doesn’t have dedicated syntax constructs for creating lists or sets

Collection Type Read-only Mutable
List listOf() arrayListOf();
Set setOf() HashSetOf(); linkedSetOf(); sortedSetOf();
Map mapOf() hashMapOf(); linkedMapOf(); sortedMapOf();

List extension functions that doesn’t exist in Java

val planets = listOf(...)
planets.first()
planets.last()
planets.asReversed()
planets.elementAtOrNull(9)

Sometimes you have a mutable list and you want to return a snapshot of a collection at a particular point in time, that’s guaranteed not to change.

class Controller {
  private val _items = mutableListOf<String>()
  val items: List<String> get() = _items.toList()
}

Read-only view of mutable collections

Any changes made to the underlying collection would be reflected in the view automatically.

val carManufacturers: MutableList<String> = mutableListOf(...)
// creating a read-only view
val carsView: List<String> = carManufacturers
println("cars view: $carsView")

Sets

LinkedHashSet defines the iteration ordering, which is the order in which elements were inserted
HashSet does not guarantee that the order will remain constant over time
TreeSet elements are ordered using their natural ordering, or by a comparator

// contains 1,21,2,6,3
val intSet: Set<Int> = setOf(1, 21, 21, 2, 6, 3, 2)

// contains 0,8,9,11
val sortedInts: java.util.TreeSet<Int> = sortedSetOf(11,0,9,11,9,8)  

// contains a,x,z
val charSet: java.util.LinkedhashSet<Char> = linkedSetOf('a', 'x', 'a', 'z', 'a')

Set extension functions

val intSet: Set<Int> = setOf(1, 21, 2, 6, 3)
// 6.6
intSet.average()

Manipulating Collections

Filter

The filter function transforms a collection and filters out elements that don’t satisty the given predicate. The result is a new collection that contains only the elements from the input collection that satisfy the predicate.
It cannot filter, it can only modify.

data class Person(val name: String, val age: Int)
val people = listOf(Person("Alice", 29), Person("Bob", 31))
people.filter { it.age > 30 }

Map

The map function applies the given function to each element in the collection and collects the results into a new collection.

val list = listOf(1,2,3,4)
list.map { it * it } // 1, 4, 9, 16

There’re also the methods filterKeys() / mapKeys() & filterValues() / mapValues().

Quantifiers

All, Any, Count & Find

A common task is to check whether all or some elements in a collection match a certain condition.
Here’s a predicate that will check whether a person is 27 or younger

val people = listOf(Person("Alice", 27), Person("Bob", 31))  
val canBeInClub27 = { p: Person -> p.age <= 27 }  

println(people.all(canBeInClub27)) // false
println(people.any(canBeInClub27)) // true
println(people.count(canBeInClub27)) // 1  

// a synonym of find is firstOrNull
println(people.find(canBeInClub27)) // Person(name=Alice, age=27)

count vs size. count only tracks the number of matching elements, not all the elements.