a class without modifying it Better alternative to creating *Util classes They are statically resolved, there’s no patching of the original classes Works with final classes, e.g. String Kotlin also has extension properties which are similar 4
): Int { ... } Inside the fun you can reference the instance with this Even works with nullable types (this will be null) Extension property: val SomeType.empty: Boolean get() = size == 0 5
you need to call the static method directly If your EFs are in a file called foo.kt Kotlin will generate the class FooKt with static methods First argument is the receiver object (this) 6
you need to call the static method directly If your EFs are in a file called foo.kt Kotlin will generate the class FooKt with static methods First argument is the receiver object (this) Example extensions.kt: fun Int.toBigInteger () = BigInteger.valueOf(this.toLong ()) Java: ExtensionsKt.toBigInteger (10); 6
its argument and returns its result. public inline fun <T, R> T.let (block: (T) -> R): R = block(this) Example: class C { var d: D? = null fun f() { d?.let { it.g() } } } Use to capture variable if smart cast not possible due to mutability. 9
its receiver and returns its result. public inline fun <T, R> T.run (block: T.() -> R): R = block () Example: val x = y.run() { a = 1 // refers to y.a b = 2 // refers to y.b compute () // refers to y.compute () } Use if you want to access multiple members of an instance without repeating yourself but you want to return something different. Might also be useful to execute multiple methods of an instance with a null check by using ?.run(..). 10
its receiver and returns this value. public inline fun <T> T.apply (block: T.() -> Unit ): T { block (); return this } Example: val bean = MyBean (). apply { a = 1 b = 2 c = true } Use to instantiate instances and set some values. 11
its argument and returns this value. public inline fun <T> T.also (block: (T) -> Unit ): T { block(this ); return this } Example: fun MyBean.copy () = MyBean (). also { it.a = a // it refers to new instance it.b = b // implicit this refers to outer } 12
that public infix fun <A, B> A.to(that: B): Pair <A, B> = Pair(this , that) Useful for creating map entries with less verbosity: val m = mapOf("foo" to 23, "bar" to 42) 13
or null, if it doesn’t. public inline fun <T> T.takeIf (predicate: (T) -> Boolean ): T? = if (predicate(this )) this else null Example: val x = foo.takeIf { it.p() } ?: return true Like filter for a single value. 14
given predicate or null, if it does. public inline fun <T> T.takeUnless (predicate: (T) -> Boolean ): T? = if (! predicate(this )) this else null Same as a negated takeIf. 15
all arrays in the given array. fun <T> Array <out Array <out T>>. flatten (): List <T> unzip: Returns a pair of lists, where first list is built from the first values of each pair from this array, second list is built from the second values of each pair from this array. fun <T, R> Array <out Pair <T, R>>. unzip (): Pair <List <T>, List <R>> 17
all collections in the given collection. fun <T> Iterable <Iterable <T>>. flatten (): List <T> unzip: Returns a pair of lists, where first list is built from the first values of each pair from this collection, second list is built from the second values of each pair from this collection. fun <T, R> Iterable <Pair <T, R>>. unzip (): Pair <List <T>, List <R>> { 18
the empty list otherwise. inline fun <T> List <T>?. orEmpty (): List <T> = this ?: emptyList () binarySearch: Searches this list or its range for the provided element using the binary search algorithm. fun <T: Comparable <T>> List <T?>. binarySearch ( element: T?, fromIndex: Int = 0, toIndex: Int = size ): Int 19
the result of the defaultValue function if there was no entry for the given key. inline fun <K, V> Map <K, V>. getOrElse( key: K, defaultValue: () -> V ): V = get(key) ?: defaultValue () 20
the result of the defaultValue function if there was no entry for the given key. inline fun <K, V> Map <K, V>. getOrElse( key: K, defaultValue: () -> V ): V = get(key) ?: defaultValue () Alternative to using ?: val v = map.getOrElse(k) { myDefaultValue } val w = map[k] ?: myDefaultValue 20
If the key is not found in the map, calls the defaultValue function, puts its result into the map under the given key and returns it. inline fun <K, V> MutableMap <K, V>. getOrPut( key: K, defaultValue: () -> V ): V 21
If the key is not found in the map, calls the defaultValue function, puts its result into the map under the given key and returns it. inline fun <K, V> MutableMap <K, V>. getOrPut( key: K, defaultValue: () -> V ): V Easy way to get a value out of a cache and if it doesn’t exist compute it and put it in the cache val v = cache.getOrPut(key) { computeValue(key) } 21
comparator defined them equal. It uses the function to transform value to a Comparable instance for comparison. inline fun <T> Comparator <T>. thenBy( crossinline selector: (T) -> Comparable <*>? ): Comparator <T> { 23
comparator defined them equal. It uses the function to transform value to a Comparable instance for comparison. inline fun <T> Comparator <T>. thenBy( crossinline selector: (T) -> Comparable <*>? ): Comparator <T> { Allows chaining of multiple comparators list.sortedWith( compareBy <User > { it.shoeSize }. thenBy { it.age } ) 23
returns its value. inline fun <T> Lock.withLock( action: () -> T ): T Allows easier lock usage: lock.withLock () { doSomething () } Also has read and write EFs for ReentrantReadWriteLock 24
and then closes it down correctly whether an exception is thrown or not. inline fun <T : Closeable?, R> T.use( block: (T) -> R ): R Works like try-with-resources in Java but is not a language feature stream.use { readFrom(it) } 25
EFs in your code: Add methods to classes which you don’t control Add methods to classes depending on the context toDTO in REST layer toJPA in storage layer Make 3rd party libraries more Kotlin like 27
= objs.any { it == this } Allows compact syntax for comparing a value to multiple possibilities. Avoid repetition of the value if it’s a complex expression. if (foo.bar (). buz (). isIn (23, 42, 404)) { doSomething () } 29
to feel more like a native type with operator EFs: operator fun MonetaryAmount .plus( other: MonetaryAmount ): MonetaryAmount = this.add(other) operator fun MonetaryAmount .times( other: Number ): MonetaryAmount = this.multiply(other) 30
to feel more like a native type with operator EFs: operator fun MonetaryAmount .plus( other: MonetaryAmount ): MonetaryAmount = this.add(other) operator fun MonetaryAmount .times( other: Number ): MonetaryAmount = this.multiply(other) Allows use of arithmetic symbols: val a = Money.of(30, "EUR") val b = Money.of(50, "EUR") val c = a + b * 2 30
MonetaryAmount get() = Money.of(this , "EUR") Then you could write assertThat(calculation ()). isEqualTo (30. EUR) I wouldn’t recommend this for production code but for unit tests it might be handy. 31
handy to have functions for data types to convert from/to remote types. fun LocalDate.format () = format( DateTimeFormatter .ISO_DATE) fun MonetaryAmount .convert (): BigDecimal = number.numberValue(BigDecimal :: class.java) .multiply(BigDecimal.valueOf (100)) fun XMLGregorianCalendar .toLocalDate () = toGregorianCalendar () . toZonedDateTime () .toLocalDate () Make sure to mark them private or internal to avoid polluting the namespace. 32
need to repeat the try-finally block all the time Looks more like a language feature Allows usage of Duration instead of milliseconds as Long You can set default values for waitTime and leaseTime redisson.lock("my -lock") { doSomethingInLock () } 34
fun (() -> Any). time (): Long { val start = System. currentTimeMillis () this () return System. currentTimeMillis () - start } val t = { computeSomething () }. time () 35
fun (() -> Any). time (): Long { val start = System. currentTimeMillis () this () return System. currentTimeMillis () - start } val t = { computeSomething () }. time () Haven’t found a good use case for that but it’s good to know nonetheless. :) 35
make your code more concise Can be used to “extend” the language (e.g. use is a language feature in Java) Even though you can define the same EFs multiple times it’s best not to pollute the namespace for common types 37