SlideShare a Scribd company logo
1 of 56
Download to read offline
Idiomatic Kotlin
Dmitry Jemerov <yole@jetbrains.com>
Expressions
Use ‘when’ as expression body
fun parseNum(number: String): Int? {
when (number) {
"one" -> return 1
"two" -> return 2
else -> return null
}
}
Use ‘when’ as expression body
fun parseNum(number: String): Int? {
when (number) {
"one" -> return 1
"two" -> return 2
else -> return null
}
}
fun parseNum(number: String) =
when (number) {
"one" -> 1
"two" -> 2
else -> null
}
Use ‘try’ as expression body
fun tryParse(number: String): Int? {
try {
return Integer.parseInt(number)
}
catch (e: NumberFormatException) {
return null
}
}
Use ‘try’ as expression body
fun tryParse(number: String): Int? {
try {
return Integer.parseInt(number)
}
catch (e: NumberFormatException) {
return null
}
}
fun tryParse(number: String) =
try {
Integer.parseInt(number)
}
catch (e: NumberFormatException) {
null
}
Use ‘try’ as expression
fun tryParse(number: String): Int? {
try {
return Integer.parseInt(number)
}
catch (e: NumberFormatException) {
return null
}
}
fun tryParse(number: String): Int? {
val n = try {
Integer.parseInt(number)
} catch (e: NumberFormatException) {
null
}
println(n)
return n
}
Use elvis with ‘return’ and ‘throw’
fun processPerson(person: Person) {
val name = person.name
if (name == null)
throw IllegalArgumentException(

"Named required")
val age = person.age
if (age == null) return
println("$name: $age")
}
class Person(val name: String?,
val age: Int?)
Use elvis with ‘return’ and ‘throw’
fun processPerson(person: Person) {
val name = person.name
if (name == null)
throw IllegalArgumentException(

"Named required")
val age = person.age
if (age == null) return
println("$name: $age")
}
fun processPerson(person: Person) {
val name = person.name ?:
throw IllegalArgumentException(
"Name required")
val age = person.age ?: return
println("$name: $age")
}
class Person(val name: String?,
val age: Int?)
Use range checks instead of comparison pairs
fun isLatinUppercase(c: Char) =
c >= 'A' && c <= 'Z'
Use range checks instead of comparison pairs
fun isLatinUppercase(c: Char) =
c >= 'A' && c <= 'Z'
fun isLatinUppercase(c: Char) =
c in 'A'..'Z'
Classes and Functions
Don’t create classes just to put functions in
class StringUtils {
companion object {
fun isPhoneNumber(s: String) =
s.length == 7 &&
s.all { it.isDigit() }
}
}
Don’t create classes just to put functions in
class StringUtils {
companion object {
fun isPhoneNumber(s: String) =
s.length == 7 &&
s.all { it.isDigit() }
}
}
object StringUtils {
fun isPhoneNumber(s: String) =
s.length == 7 &&
s.all { it.isDigit() }
}
Don’t create classes just to put functions in
class StringUtils {
companion object {
fun isPhoneNumber(s: String) =
s.length == 7 &&
s.all { it.isDigit() }
}
} fun isPhoneNumber(s: String) =
s.length == 7 &&
s.all { it.isDigit() }
object StringUtils {
fun isPhoneNumber(s: String) =
s.length == 7 &&
s.all { it.isDigit() }
}
Use extension functions copiously
fun isPhoneNumber(s: String) =
s.length == 7 &&
s.all { it.isDigit() }
Use extension functions copiously
fun isPhoneNumber(s: String) =
s.length == 7 &&
s.all { it.isDigit() }
fun String.isPhoneNumber() =
length == 7 &&
all { it.isDigit() }
Avoid using member extension functions 

(unless required for DSLs)
class PhoneBook {
fun String.isPhoneNumber() =
length == 7 &&
all { it.isDigit() }
}
Avoid using member extension functions 

(unless required for DSLs)
class PhoneBook {
fun String.isPhoneNumber() =
length == 7 &&
all { it.isDigit() }
}
class PhoneBook {
}
private fun
String.isPhoneNumber() =
length == 7 &&
all { it.isDigit() }
Don't use member extensions with 

containing class as the receiver
class PhoneBook {
fun PhoneBook.find(name: String)=
"1234567"
}
Don't use member extensions with 

containing class as the receiver
class PhoneBook {
fun PhoneBook.find(name: String)=
"1234567"
}
class PhoneBook {
fun find(name: String) =
"1234567"
}
Consider extracting non-essential API

of classes into extensions
class Person(val firstName: String,
val lastName: String) {
val fullName: String
get() = "$firstName $lastName"
}
Consider extracting non-essential API

of classes into extensions
class Person(val firstName: String,
val lastName: String) {
val fullName: String
get() = "$firstName $lastName"
}
class Person(val firstName: String,
val lastName: String)
val Person.fullName: String
get() = "$firstName $lastName"
Use default parameter values instead of overloads
wherever possible
class Phonebook {
fun print() {
print(",")
}
fun print(separator: String) {
}
}
fun main(args: Array<String>) {
Phonebook().print("|")
}
Use default parameter values instead of overloads
wherever possible
class Phonebook {
fun print() {
print(",")
}
fun print(separator: String) {
}
}
fun main(args: Array<String>) {
Phonebook().print("|")
}
class Phonebook {
fun print(

separator: String = ",") {
}
}
fun main(args: Array<String>) {
Phonebook().print(
separator = "|")
}
Use ‘lateinit’ for properties that can’t be initialised
in a constructor
class MyTest {
class State(val data: String)
var state: State? = null
@Before fun setup() {
state = State("abc")
}
@Test fun foo() {
Assert.assertEquals(

"abc", state!!.data)
}
}
Use ‘lateinit’ for properties that can’t be initialised
in a constructor
class MyTest {
class State(val data: String)
var state: State? = null
@Before fun setup() {
state = State("abc")
}
@Test fun foo() {
Assert.assertEquals(

"abc", state!!.data)
}
}
class MyTest {
class State(val data: String)
lateinit var state: State
@Before fun setup() {
state = State("abc")
}
@Test fun foo() {
Assert.assertEquals(

"abc", state.data)
}
}
Use type aliases for functional types and
collections
class EventDispatcher {
fun addClickHandler(

handler: (Event) -> Unit) {
}
fun removeClickHandler(
handler: (Event) -> Unit) {
}
}
Use type aliases for functional types and
collections
class EventDispatcher {
fun addClickHandler(

handler: (Event) -> Unit) {
}
fun removeClickHandler(
handler: (Event) -> Unit) {
}
}
typealias ClickHandler =
(Event) -> Unit
class EventDispatcher {
fun addClickHandler(
handler: ClickHandler) {
}
fun removeClickHandler(
handler: ClickHandler) {
}
}
Use type aliases for functional types and
collections
class EventDispatcher {
fun addClickHandler(

handler: (Event) -> Unit) {
}
fun removeClickHandler(
handler: (Event) -> Unit) {
}
}
typealias ClickHandler =
(Event) -> Unit
typealias HandlerMap =
Map<EventType, List<Event>>
Use data classes to return multiple values
fun namedNum(): Pair<Int, String> =
1 to "one"
fun main(args: Array<String>) {
val pair = namedNum()
val number = pair.first
val name = pair.second
}
Use data classes to return multiple values
fun namedNum(): Pair<Int, String> =
1 to "one"
fun main(args: Array<String>) {
val pair = namedNum()
val number = pair.first
val name = pair.second
}
data class NamedNumber(
val number: Int,
val name: String)
fun namedNum() =
NamedNumber(1, "one")
fun main(args: Array<String>) {
val (number, name) =

namedNum()
}
Use destructuring in loops
fun printMap(m: Map<String, String>) {
for (e in m.entries) {
println("${e.key} -> ${e.value}")
}
}
Use destructuring in loops
fun printMap(m: Map<String, String>) {
for (e in m.entries) {
println("${e.key} -> ${e.value}")
}
}
fun printMap(m: Map<String, String>) {
for ((key, value) in m) {
println("$key -> $value")
}
}
Use destructuring with lists
fun splitNameExt(fn: String): NameExt {
if ('.' in fn) {
val parts = fn.split('.', limit = 2)
return NameExt(parts[0], parts[1])
}
return NameExt(fn, null)
}
data class NameExt(val name: String,
val ext: String?)
Use destructuring with lists
fun splitNameExt(fn: String): NameExt {
if ('.' in fn) {
val parts = fn.split('.', limit = 2)
return NameExt(parts[0], parts[1])
}
return NameExt(fn, null)
}
fun splitNameExt(fn: String): NameExt {
if ('.' in fn) {
val (name, ext) =
fn.split('.', limit = 2)
return NameExt(name, ext)
}
return NameExt(fn, null)
}
data class NameExt(val name: String,
val ext: String?)
Use ‘copy’ method for data classes
class Person(val name: String,
var age: Int)
fun happyBirthday(person: Person) {
person.age++
}
Use ‘copy’ method for data classes
class Person(val name: String,
var age: Int)
fun happyBirthday(person: Person) {
person.age++
}
data class Person(val name: String,
val age: Int)
fun happyBirthday(person: Person) =
person.copy(
age = person.age + 1)
The Standard Library
Use ‘coerceIn’ to ensure a number is in range
fun updateProgress(value: Int) {
val newValue = when {
value < 0 -> 0
value > 100 -> 100
else -> value
}
}
Use ‘coerceIn’ to ensure a number is in range
fun updateProgress(value: Int) {
val newValue = when {
value < 0 -> 0
value > 100 -> 100
else -> value
}
}
fun updateProgress(value: Int) {
val newValue = 

value.coerceIn(0, 100)
}
Use ‘apply’ for object initialisation
fun createLabel(): JLabel {
val label = JLabel("Foo")
label.foreground = Color.RED
label.background = Color.BLUE
return label
}
Use ‘apply’ for object initialisation
fun createLabel(): JLabel {
val label = JLabel("Foo")
label.foreground = Color.RED
label.background = Color.BLUE
return label
}
fun createLabel() =
JLabel("Foo").apply {
foreground = Color.RED
background = Color.BLUE
}
Use ‘filterIsInstance’ to filter a list by object type
fun findStrings(objs: List<Any>) =
objs.filter { it is String }
Use ‘filterIsInstance’ to filter a list by object type
fun findStrings(objs: List<Any>) =
objs.filter { it is String }
fun findStrings(objs: List<Any>) =
obs.filterIsInstance<String>()
Use ‘mapNotNull’ to apply a function and select
items for which it returns a non-null value
fun listErrors(

results: List<Result>) =
results
.map { it.error }
.filterNotNull()
data class Result(val data: Any?,
val error: String?)
Use ‘mapNotNull’ to apply a function and select
items for which it returns a non-null value
fun listErrors(

results: List<Result>) =
results
.map { it.error }
.filterNotNull()
fun listErrors(
results: List<Result>) =
results.mapNotNull { 

it.error
}
data class Result(val data: Any?,
val error: String?)
Use ‘compareBy’ for multi-step comparisons
fun sortPersons(persons: List<Person>) =
persons.sortedWith(
Comparator<Person> { p1, p2 ->
val rc =
p1.name.compareTo(p2.name)
if (rc != 0)
rc
else
p1.age - p2.age
})
class Person(val name: String,
val age: Int)
Use ‘compareBy’ for multi-step comparisons
fun sortPersons(persons: List<Person>) =
persons.sortedWith(
Comparator<Person> { p1, p2 ->
val rc =
p1.name.compareTo(p2.name)
if (rc != 0)
rc
else
p1.age - p2.age
})
fun sortPersons(persons: List<Person>) =
persons.sortedWith(
compareBy(Person::name,
Person::age))
class Person(val name: String,
val age: Int)
Use ‘groupBy’ to group items in a collection
fun analyzeLog(log: List<Request>) {
val map = mutableMapOf<String,
MutableList<Request>>()
for (request in log) {
map.getOrPut(request.url)
{ mutableListOf() }
.add(request)
}
}
class Request(val url: String,
val remoteIP: String,
val timestamp: Long)
Use ‘groupBy’ to group items in a collection
fun analyzeLog(log: List<Request>) {
val map = mutableMapOf<String,
MutableList<Request>>()
for (request in log) {
map.getOrPut(request.url)
{ mutableListOf() }
.add(request)
}
}
fun analyzeLog(log: List<Request>) {
val map = log.groupBy(Request::url)
}
class Request(val url: String,
val remoteIP: String,
val timestamp: Long)
Use String methods for string parsing
val pattern = Regex("(.+)/([^/]*)")
fun splitPath(path: String): PathParts {
val match = pattern.matchEntire(path)
?: return PathParts("", path)
return PathParts(match.groupValues[1],
match.groupValues[2])
}
data class PathParts(val dir: String,
val name: String)
Use String methods for string parsing
val pattern = Regex("(.+)/([^/]*)")
fun splitPath(path: String): PathParts {
val match = pattern.matchEntire(path)
?: return PathParts("", path)
return PathParts(match.groupValues[1],
match.groupValues[2])
}
fun splitPath(path: String) =
PathParts(
path.substringBeforeLast('/', ""),
path.substringAfterLast(‘/'))
data class PathParts(val dir: String,
val name: String)
Idiomatic Kotlin
Idiomatic Kotlin
Q&A
yole@jetbrains.com
@intelliyole

More Related Content

What's hot

From Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfFrom Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfJosé Paumard
 
Kotlin scope functions
Kotlin scope functionsKotlin scope functions
Kotlin scope functionsWaheed Nazir
 
Exception Handling
Exception HandlingException Handling
Exception HandlingSunil OS
 
An Introduction to JUnit 5 and how to use it with Spring boot tests and Mockito
An Introduction to JUnit 5 and how to use it with Spring boot tests and MockitoAn Introduction to JUnit 5 and how to use it with Spring boot tests and Mockito
An Introduction to JUnit 5 and how to use it with Spring boot tests and Mockitoshaunthomas999
 
Introduction to kotlin coroutines
Introduction to kotlin coroutinesIntroduction to kotlin coroutines
Introduction to kotlin coroutinesNAVER Engineering
 
Java Collections
Java CollectionsJava Collections
Java Collectionsparag
 
Java Threads and Concurrency
Java Threads and ConcurrencyJava Threads and Concurrency
Java Threads and ConcurrencySunil OS
 
Java Basics
Java BasicsJava Basics
Java BasicsSunil OS
 
Py.test
Py.testPy.test
Py.testsoasme
 
Java Input Output and File Handling
Java Input Output and File HandlingJava Input Output and File Handling
Java Input Output and File HandlingSunil OS
 
Java 8 - CJ
Java 8 - CJJava 8 - CJ
Java 8 - CJSunil OS
 
Threads V4
Threads  V4Threads  V4
Threads V4Sunil OS
 
Kotlin for Android Development
Kotlin for Android DevelopmentKotlin for Android Development
Kotlin for Android DevelopmentSpeck&Tech
 
Introduction to Kotlin coroutines
Introduction to Kotlin coroutinesIntroduction to Kotlin coroutines
Introduction to Kotlin coroutinesRoman Elizarov
 
A quick and fast intro to Kotlin
A quick and fast intro to Kotlin A quick and fast intro to Kotlin
A quick and fast intro to Kotlin XPeppers
 
Java 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional InterfacesJava 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional InterfacesGanesh Samarthyam
 

What's hot (20)

From Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfFrom Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdf
 
Kotlin scope functions
Kotlin scope functionsKotlin scope functions
Kotlin scope functions
 
Exception Handling
Exception HandlingException Handling
Exception Handling
 
An Introduction to JUnit 5 and how to use it with Spring boot tests and Mockito
An Introduction to JUnit 5 and how to use it with Spring boot tests and MockitoAn Introduction to JUnit 5 and how to use it with Spring boot tests and Mockito
An Introduction to JUnit 5 and how to use it with Spring boot tests and Mockito
 
Introduction to kotlin coroutines
Introduction to kotlin coroutinesIntroduction to kotlin coroutines
Introduction to kotlin coroutines
 
JDBC
JDBCJDBC
JDBC
 
Java Collections
Java CollectionsJava Collections
Java Collections
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
 
Java Threads and Concurrency
Java Threads and ConcurrencyJava Threads and Concurrency
Java Threads and Concurrency
 
Java Basics
Java BasicsJava Basics
Java Basics
 
Py.test
Py.testPy.test
Py.test
 
Java Input Output and File Handling
Java Input Output and File HandlingJava Input Output and File Handling
Java Input Output and File Handling
 
Java 8 - CJ
Java 8 - CJJava 8 - CJ
Java 8 - CJ
 
Threads V4
Threads  V4Threads  V4
Threads V4
 
Kotlin for Android Development
Kotlin for Android DevelopmentKotlin for Android Development
Kotlin for Android Development
 
Java 8 lambda
Java 8 lambdaJava 8 lambda
Java 8 lambda
 
Introduction to Kotlin coroutines
Introduction to Kotlin coroutinesIntroduction to Kotlin coroutines
Introduction to Kotlin coroutines
 
A quick and fast intro to Kotlin
A quick and fast intro to Kotlin A quick and fast intro to Kotlin
A quick and fast intro to Kotlin
 
Java 8 Lambda and Streams
Java 8 Lambda and StreamsJava 8 Lambda and Streams
Java 8 Lambda and Streams
 
Java 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional InterfacesJava 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional Interfaces
 

Similar to Idiomatic Kotlin

かとうの Kotlin 講座 こってり版
かとうの Kotlin 講座 こってり版かとうの Kotlin 講座 こってり版
かとうの Kotlin 講座 こってり版Yutaka Kato
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kirill Rozov
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldBTI360
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kirill Rozov
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to SwiftGiordano Scalzo
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기진성 오
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Baruch Sadogursky
 
여자개발자모임터 6주년 개발 세미나 - Scala Language
여자개발자모임터 6주년 개발 세미나 - Scala Language여자개발자모임터 6주년 개발 세미나 - Scala Language
여자개발자모임터 6주년 개발 세미나 - Scala LanguageAshal aka JOKER
 

Similar to Idiomatic Kotlin (20)

かとうの Kotlin 講座 こってり版
かとうの Kotlin 講座 こってり版かとうの Kotlin 講座 こってり版
かとうの Kotlin 講座 こってり版
 
Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2Kotlin Basics - Apalon Kotlin Sprint Part 2
Kotlin Basics - Apalon Kotlin Sprint Part 2
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Benefits of Kotlin
Benefits of KotlinBenefits of Kotlin
Benefits of Kotlin
 
Scala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 WorldScala vs Java 8 in a Java 8 World
Scala vs Java 8 in a Java 8 World
 
SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Scala taxonomy
Scala taxonomyScala taxonomy
Scala taxonomy
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
 
Kotlin
KotlinKotlin
Kotlin
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
 
A swift introduction to Swift
A swift introduction to SwiftA swift introduction to Swift
A swift introduction to Swift
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
 
Scala
ScalaScala
Scala
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
 
Scala introduction
Scala introductionScala introduction
Scala introduction
 
여자개발자모임터 6주년 개발 세미나 - Scala Language
여자개발자모임터 6주년 개발 세미나 - Scala Language여자개발자모임터 6주년 개발 세미나 - Scala Language
여자개발자모임터 6주년 개발 세미나 - Scala Language
 

More from intelliyole

Kotlin: Why Do You Care?
Kotlin: Why Do You Care?Kotlin: Why Do You Care?
Kotlin: Why Do You Care?intelliyole
 
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)intelliyole
 
From Renamer Plugin to Polyglot IDE
From Renamer Plugin to Polyglot IDEFrom Renamer Plugin to Polyglot IDE
From Renamer Plugin to Polyglot IDEintelliyole
 
How to Build Developer Tools on Top of IntelliJ Platform
How to Build Developer Tools on Top of IntelliJ PlatformHow to Build Developer Tools on Top of IntelliJ Platform
How to Build Developer Tools on Top of IntelliJ Platformintelliyole
 
The Kotlin Programming Language
The Kotlin Programming LanguageThe Kotlin Programming Language
The Kotlin Programming Languageintelliyole
 
IntelliJ IDEA: Life after Open Source
IntelliJ IDEA: Life after Open SourceIntelliJ IDEA: Life after Open Source
IntelliJ IDEA: Life after Open Sourceintelliyole
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLsintelliyole
 
Implementing Refactorings in IntelliJ IDEA
Implementing Refactorings in IntelliJ IDEAImplementing Refactorings in IntelliJ IDEA
Implementing Refactorings in IntelliJ IDEAintelliyole
 
IntelliJ IDEA Architecture and Performance
IntelliJ IDEA Architecture and PerformanceIntelliJ IDEA Architecture and Performance
IntelliJ IDEA Architecture and Performanceintelliyole
 

More from intelliyole (9)

Kotlin: Why Do You Care?
Kotlin: Why Do You Care?Kotlin: Why Do You Care?
Kotlin: Why Do You Care?
 
Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)Feel of Kotlin (Berlin JUG 16 Apr 2015)
Feel of Kotlin (Berlin JUG 16 Apr 2015)
 
From Renamer Plugin to Polyglot IDE
From Renamer Plugin to Polyglot IDEFrom Renamer Plugin to Polyglot IDE
From Renamer Plugin to Polyglot IDE
 
How to Build Developer Tools on Top of IntelliJ Platform
How to Build Developer Tools on Top of IntelliJ PlatformHow to Build Developer Tools on Top of IntelliJ Platform
How to Build Developer Tools on Top of IntelliJ Platform
 
The Kotlin Programming Language
The Kotlin Programming LanguageThe Kotlin Programming Language
The Kotlin Programming Language
 
IntelliJ IDEA: Life after Open Source
IntelliJ IDEA: Life after Open SourceIntelliJ IDEA: Life after Open Source
IntelliJ IDEA: Life after Open Source
 
Smoothing Your Java with DSLs
Smoothing Your Java with DSLsSmoothing Your Java with DSLs
Smoothing Your Java with DSLs
 
Implementing Refactorings in IntelliJ IDEA
Implementing Refactorings in IntelliJ IDEAImplementing Refactorings in IntelliJ IDEA
Implementing Refactorings in IntelliJ IDEA
 
IntelliJ IDEA Architecture and Performance
IntelliJ IDEA Architecture and PerformanceIntelliJ IDEA Architecture and Performance
IntelliJ IDEA Architecture and Performance
 

Recently uploaded

Webinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptWebinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptkinjal48
 
Why Choose Brain Inventory For Ecommerce Development.pdf
Why Choose Brain Inventory For Ecommerce Development.pdfWhy Choose Brain Inventory For Ecommerce Development.pdf
Why Choose Brain Inventory For Ecommerce Development.pdfBrain Inventory
 
eAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionseAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionsNirav Modi
 
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdfARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdfTobias Schneck
 
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...OnePlan Solutions
 
IA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeIA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeNeo4j
 
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine HarmonyLeveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmonyelliciumsolutionspun
 
Kawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies
 
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.Sharon Liu
 
Enterprise Document Management System - Qualityze Inc
Enterprise Document Management System - Qualityze IncEnterprise Document Management System - Qualityze Inc
Enterprise Document Management System - Qualityze Incrobinwilliams8624
 
Deep Learning for Images with PyTorch - Datacamp
Deep Learning for Images with PyTorch - DatacampDeep Learning for Images with PyTorch - Datacamp
Deep Learning for Images with PyTorch - DatacampVICTOR MAESTRE RAMIREZ
 
AI Embracing Every Shade of Human Beauty
AI Embracing Every Shade of Human BeautyAI Embracing Every Shade of Human Beauty
AI Embracing Every Shade of Human BeautyRaymond Okyere-Forson
 
OpenChain Webinar: Universal CVSS Calculator
OpenChain Webinar: Universal CVSS CalculatorOpenChain Webinar: Universal CVSS Calculator
OpenChain Webinar: Universal CVSS CalculatorShane Coughlan
 
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/MLBig Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/MLAlluxio, Inc.
 
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageSales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageDista
 
Growing Oxen: channel operators and retries
Growing Oxen: channel operators and retriesGrowing Oxen: channel operators and retries
Growing Oxen: channel operators and retriesSoftwareMill
 
JS-Experts - Cybersecurity for Generative AI
JS-Experts - Cybersecurity for Generative AIJS-Experts - Cybersecurity for Generative AI
JS-Experts - Cybersecurity for Generative AIIvo Andreev
 
How Does the Epitome of Spyware Differ from Other Malicious Software?
How Does the Epitome of Spyware Differ from Other Malicious Software?How Does the Epitome of Spyware Differ from Other Malicious Software?
How Does the Epitome of Spyware Differ from Other Malicious Software?AmeliaSmith90
 
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...Jaydeep Chhasatia
 

Recently uploaded (20)

Webinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.pptWebinar_050417_LeClair12345666777889.ppt
Webinar_050417_LeClair12345666777889.ppt
 
Why Choose Brain Inventory For Ecommerce Development.pdf
Why Choose Brain Inventory For Ecommerce Development.pdfWhy Choose Brain Inventory For Ecommerce Development.pdf
Why Choose Brain Inventory For Ecommerce Development.pdf
 
eAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspectionseAuditor Audits & Inspections - conduct field inspections
eAuditor Audits & Inspections - conduct field inspections
 
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdfARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
ARM Talk @ Rejekts - Will ARM be the new Mainstream in our Data Centers_.pdf
 
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
Transforming PMO Success with AI - Discover OnePlan Strategic Portfolio Work ...
 
IA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG timeIA Generativa y Grafos de Neo4j: RAG time
IA Generativa y Grafos de Neo4j: RAG time
 
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine HarmonyLeveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
Leveraging DxSherpa's Generative AI Services to Unlock Human-Machine Harmony
 
Kawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in TrivandrumKawika Technologies pvt ltd Software Development Company in Trivandrum
Kawika Technologies pvt ltd Software Development Company in Trivandrum
 
Salesforce AI Associate Certification.pptx
Salesforce AI Associate Certification.pptxSalesforce AI Associate Certification.pptx
Salesforce AI Associate Certification.pptx
 
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
20240319 Car Simulator Plan.pptx . Plan for a JavaScript Car Driving Simulator.
 
Enterprise Document Management System - Qualityze Inc
Enterprise Document Management System - Qualityze IncEnterprise Document Management System - Qualityze Inc
Enterprise Document Management System - Qualityze Inc
 
Deep Learning for Images with PyTorch - Datacamp
Deep Learning for Images with PyTorch - DatacampDeep Learning for Images with PyTorch - Datacamp
Deep Learning for Images with PyTorch - Datacamp
 
AI Embracing Every Shade of Human Beauty
AI Embracing Every Shade of Human BeautyAI Embracing Every Shade of Human Beauty
AI Embracing Every Shade of Human Beauty
 
OpenChain Webinar: Universal CVSS Calculator
OpenChain Webinar: Universal CVSS CalculatorOpenChain Webinar: Universal CVSS Calculator
OpenChain Webinar: Universal CVSS Calculator
 
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/MLBig Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
Big Data Bellevue Meetup | Enhancing Python Data Loading in the Cloud for AI/ML
 
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales CoverageSales Territory Management: A Definitive Guide to Expand Sales Coverage
Sales Territory Management: A Definitive Guide to Expand Sales Coverage
 
Growing Oxen: channel operators and retries
Growing Oxen: channel operators and retriesGrowing Oxen: channel operators and retries
Growing Oxen: channel operators and retries
 
JS-Experts - Cybersecurity for Generative AI
JS-Experts - Cybersecurity for Generative AIJS-Experts - Cybersecurity for Generative AI
JS-Experts - Cybersecurity for Generative AI
 
How Does the Epitome of Spyware Differ from Other Malicious Software?
How Does the Epitome of Spyware Differ from Other Malicious Software?How Does the Epitome of Spyware Differ from Other Malicious Software?
How Does the Epitome of Spyware Differ from Other Malicious Software?
 
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
Optimizing Business Potential: A Guide to Outsourcing Engineering Services in...
 

Idiomatic Kotlin

  • 1. Idiomatic Kotlin Dmitry Jemerov <yole@jetbrains.com>
  • 3. Use ‘when’ as expression body fun parseNum(number: String): Int? { when (number) { "one" -> return 1 "two" -> return 2 else -> return null } }
  • 4. Use ‘when’ as expression body fun parseNum(number: String): Int? { when (number) { "one" -> return 1 "two" -> return 2 else -> return null } } fun parseNum(number: String) = when (number) { "one" -> 1 "two" -> 2 else -> null }
  • 5. Use ‘try’ as expression body fun tryParse(number: String): Int? { try { return Integer.parseInt(number) } catch (e: NumberFormatException) { return null } }
  • 6. Use ‘try’ as expression body fun tryParse(number: String): Int? { try { return Integer.parseInt(number) } catch (e: NumberFormatException) { return null } } fun tryParse(number: String) = try { Integer.parseInt(number) } catch (e: NumberFormatException) { null }
  • 7. Use ‘try’ as expression fun tryParse(number: String): Int? { try { return Integer.parseInt(number) } catch (e: NumberFormatException) { return null } } fun tryParse(number: String): Int? { val n = try { Integer.parseInt(number) } catch (e: NumberFormatException) { null } println(n) return n }
  • 8. Use elvis with ‘return’ and ‘throw’ fun processPerson(person: Person) { val name = person.name if (name == null) throw IllegalArgumentException(
 "Named required") val age = person.age if (age == null) return println("$name: $age") } class Person(val name: String?, val age: Int?)
  • 9. Use elvis with ‘return’ and ‘throw’ fun processPerson(person: Person) { val name = person.name if (name == null) throw IllegalArgumentException(
 "Named required") val age = person.age if (age == null) return println("$name: $age") } fun processPerson(person: Person) { val name = person.name ?: throw IllegalArgumentException( "Name required") val age = person.age ?: return println("$name: $age") } class Person(val name: String?, val age: Int?)
  • 10. Use range checks instead of comparison pairs fun isLatinUppercase(c: Char) = c >= 'A' && c <= 'Z'
  • 11. Use range checks instead of comparison pairs fun isLatinUppercase(c: Char) = c >= 'A' && c <= 'Z' fun isLatinUppercase(c: Char) = c in 'A'..'Z'
  • 13. Don’t create classes just to put functions in class StringUtils { companion object { fun isPhoneNumber(s: String) = s.length == 7 && s.all { it.isDigit() } } }
  • 14. Don’t create classes just to put functions in class StringUtils { companion object { fun isPhoneNumber(s: String) = s.length == 7 && s.all { it.isDigit() } } } object StringUtils { fun isPhoneNumber(s: String) = s.length == 7 && s.all { it.isDigit() } }
  • 15. Don’t create classes just to put functions in class StringUtils { companion object { fun isPhoneNumber(s: String) = s.length == 7 && s.all { it.isDigit() } } } fun isPhoneNumber(s: String) = s.length == 7 && s.all { it.isDigit() } object StringUtils { fun isPhoneNumber(s: String) = s.length == 7 && s.all { it.isDigit() } }
  • 16. Use extension functions copiously fun isPhoneNumber(s: String) = s.length == 7 && s.all { it.isDigit() }
  • 17. Use extension functions copiously fun isPhoneNumber(s: String) = s.length == 7 && s.all { it.isDigit() } fun String.isPhoneNumber() = length == 7 && all { it.isDigit() }
  • 18. Avoid using member extension functions 
 (unless required for DSLs) class PhoneBook { fun String.isPhoneNumber() = length == 7 && all { it.isDigit() } }
  • 19. Avoid using member extension functions 
 (unless required for DSLs) class PhoneBook { fun String.isPhoneNumber() = length == 7 && all { it.isDigit() } } class PhoneBook { } private fun String.isPhoneNumber() = length == 7 && all { it.isDigit() }
  • 20. Don't use member extensions with 
 containing class as the receiver class PhoneBook { fun PhoneBook.find(name: String)= "1234567" }
  • 21. Don't use member extensions with 
 containing class as the receiver class PhoneBook { fun PhoneBook.find(name: String)= "1234567" } class PhoneBook { fun find(name: String) = "1234567" }
  • 22. Consider extracting non-essential API
 of classes into extensions class Person(val firstName: String, val lastName: String) { val fullName: String get() = "$firstName $lastName" }
  • 23. Consider extracting non-essential API
 of classes into extensions class Person(val firstName: String, val lastName: String) { val fullName: String get() = "$firstName $lastName" } class Person(val firstName: String, val lastName: String) val Person.fullName: String get() = "$firstName $lastName"
  • 24. Use default parameter values instead of overloads wherever possible class Phonebook { fun print() { print(",") } fun print(separator: String) { } } fun main(args: Array<String>) { Phonebook().print("|") }
  • 25. Use default parameter values instead of overloads wherever possible class Phonebook { fun print() { print(",") } fun print(separator: String) { } } fun main(args: Array<String>) { Phonebook().print("|") } class Phonebook { fun print(
 separator: String = ",") { } } fun main(args: Array<String>) { Phonebook().print( separator = "|") }
  • 26. Use ‘lateinit’ for properties that can’t be initialised in a constructor class MyTest { class State(val data: String) var state: State? = null @Before fun setup() { state = State("abc") } @Test fun foo() { Assert.assertEquals(
 "abc", state!!.data) } }
  • 27. Use ‘lateinit’ for properties that can’t be initialised in a constructor class MyTest { class State(val data: String) var state: State? = null @Before fun setup() { state = State("abc") } @Test fun foo() { Assert.assertEquals(
 "abc", state!!.data) } } class MyTest { class State(val data: String) lateinit var state: State @Before fun setup() { state = State("abc") } @Test fun foo() { Assert.assertEquals(
 "abc", state.data) } }
  • 28. Use type aliases for functional types and collections class EventDispatcher { fun addClickHandler(
 handler: (Event) -> Unit) { } fun removeClickHandler( handler: (Event) -> Unit) { } }
  • 29. Use type aliases for functional types and collections class EventDispatcher { fun addClickHandler(
 handler: (Event) -> Unit) { } fun removeClickHandler( handler: (Event) -> Unit) { } } typealias ClickHandler = (Event) -> Unit class EventDispatcher { fun addClickHandler( handler: ClickHandler) { } fun removeClickHandler( handler: ClickHandler) { } }
  • 30. Use type aliases for functional types and collections class EventDispatcher { fun addClickHandler(
 handler: (Event) -> Unit) { } fun removeClickHandler( handler: (Event) -> Unit) { } } typealias ClickHandler = (Event) -> Unit typealias HandlerMap = Map<EventType, List<Event>>
  • 31. Use data classes to return multiple values fun namedNum(): Pair<Int, String> = 1 to "one" fun main(args: Array<String>) { val pair = namedNum() val number = pair.first val name = pair.second }
  • 32. Use data classes to return multiple values fun namedNum(): Pair<Int, String> = 1 to "one" fun main(args: Array<String>) { val pair = namedNum() val number = pair.first val name = pair.second } data class NamedNumber( val number: Int, val name: String) fun namedNum() = NamedNumber(1, "one") fun main(args: Array<String>) { val (number, name) =
 namedNum() }
  • 33. Use destructuring in loops fun printMap(m: Map<String, String>) { for (e in m.entries) { println("${e.key} -> ${e.value}") } }
  • 34. Use destructuring in loops fun printMap(m: Map<String, String>) { for (e in m.entries) { println("${e.key} -> ${e.value}") } } fun printMap(m: Map<String, String>) { for ((key, value) in m) { println("$key -> $value") } }
  • 35. Use destructuring with lists fun splitNameExt(fn: String): NameExt { if ('.' in fn) { val parts = fn.split('.', limit = 2) return NameExt(parts[0], parts[1]) } return NameExt(fn, null) } data class NameExt(val name: String, val ext: String?)
  • 36. Use destructuring with lists fun splitNameExt(fn: String): NameExt { if ('.' in fn) { val parts = fn.split('.', limit = 2) return NameExt(parts[0], parts[1]) } return NameExt(fn, null) } fun splitNameExt(fn: String): NameExt { if ('.' in fn) { val (name, ext) = fn.split('.', limit = 2) return NameExt(name, ext) } return NameExt(fn, null) } data class NameExt(val name: String, val ext: String?)
  • 37. Use ‘copy’ method for data classes class Person(val name: String, var age: Int) fun happyBirthday(person: Person) { person.age++ }
  • 38. Use ‘copy’ method for data classes class Person(val name: String, var age: Int) fun happyBirthday(person: Person) { person.age++ } data class Person(val name: String, val age: Int) fun happyBirthday(person: Person) = person.copy( age = person.age + 1)
  • 40. Use ‘coerceIn’ to ensure a number is in range fun updateProgress(value: Int) { val newValue = when { value < 0 -> 0 value > 100 -> 100 else -> value } }
  • 41. Use ‘coerceIn’ to ensure a number is in range fun updateProgress(value: Int) { val newValue = when { value < 0 -> 0 value > 100 -> 100 else -> value } } fun updateProgress(value: Int) { val newValue = 
 value.coerceIn(0, 100) }
  • 42. Use ‘apply’ for object initialisation fun createLabel(): JLabel { val label = JLabel("Foo") label.foreground = Color.RED label.background = Color.BLUE return label }
  • 43. Use ‘apply’ for object initialisation fun createLabel(): JLabel { val label = JLabel("Foo") label.foreground = Color.RED label.background = Color.BLUE return label } fun createLabel() = JLabel("Foo").apply { foreground = Color.RED background = Color.BLUE }
  • 44. Use ‘filterIsInstance’ to filter a list by object type fun findStrings(objs: List<Any>) = objs.filter { it is String }
  • 45. Use ‘filterIsInstance’ to filter a list by object type fun findStrings(objs: List<Any>) = objs.filter { it is String } fun findStrings(objs: List<Any>) = obs.filterIsInstance<String>()
  • 46. Use ‘mapNotNull’ to apply a function and select items for which it returns a non-null value fun listErrors(
 results: List<Result>) = results .map { it.error } .filterNotNull() data class Result(val data: Any?, val error: String?)
  • 47. Use ‘mapNotNull’ to apply a function and select items for which it returns a non-null value fun listErrors(
 results: List<Result>) = results .map { it.error } .filterNotNull() fun listErrors( results: List<Result>) = results.mapNotNull { 
 it.error } data class Result(val data: Any?, val error: String?)
  • 48. Use ‘compareBy’ for multi-step comparisons fun sortPersons(persons: List<Person>) = persons.sortedWith( Comparator<Person> { p1, p2 -> val rc = p1.name.compareTo(p2.name) if (rc != 0) rc else p1.age - p2.age }) class Person(val name: String, val age: Int)
  • 49. Use ‘compareBy’ for multi-step comparisons fun sortPersons(persons: List<Person>) = persons.sortedWith( Comparator<Person> { p1, p2 -> val rc = p1.name.compareTo(p2.name) if (rc != 0) rc else p1.age - p2.age }) fun sortPersons(persons: List<Person>) = persons.sortedWith( compareBy(Person::name, Person::age)) class Person(val name: String, val age: Int)
  • 50. Use ‘groupBy’ to group items in a collection fun analyzeLog(log: List<Request>) { val map = mutableMapOf<String, MutableList<Request>>() for (request in log) { map.getOrPut(request.url) { mutableListOf() } .add(request) } } class Request(val url: String, val remoteIP: String, val timestamp: Long)
  • 51. Use ‘groupBy’ to group items in a collection fun analyzeLog(log: List<Request>) { val map = mutableMapOf<String, MutableList<Request>>() for (request in log) { map.getOrPut(request.url) { mutableListOf() } .add(request) } } fun analyzeLog(log: List<Request>) { val map = log.groupBy(Request::url) } class Request(val url: String, val remoteIP: String, val timestamp: Long)
  • 52. Use String methods for string parsing val pattern = Regex("(.+)/([^/]*)") fun splitPath(path: String): PathParts { val match = pattern.matchEntire(path) ?: return PathParts("", path) return PathParts(match.groupValues[1], match.groupValues[2]) } data class PathParts(val dir: String, val name: String)
  • 53. Use String methods for string parsing val pattern = Regex("(.+)/([^/]*)") fun splitPath(path: String): PathParts { val match = pattern.matchEntire(path) ?: return PathParts("", path) return PathParts(match.groupValues[1], match.groupValues[2]) } fun splitPath(path: String) = PathParts( path.substringBeforeLast('/', ""), path.substringAfterLast(‘/')) data class PathParts(val dir: String, val name: String)