В этой статье я дам несколько советов с примерами, как сделать код на Kotlin более понятным для чтения.
Другие полезные статьи на тему Kotlin:
- Шпаргалка по коллекциям Kotlin
- Хорошие и плохие приемы программирования на Kotlin
- Основы функционального программирования на Kotlin
Используйте require и check:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
require(arg.length < 10) { "message" } val result = checkNotNull(bar(arg)) { "message" } /// вместо /// if (arg.length < 10) { throw IllegalArgumentException("message") } val result = bar(arg) ?: throw IllegalStateException("message") |
Используйте функции вместо комментариев:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
val user = getUser(id) validate(user) activate(user) private fun validate(user: User) { // код валидации } private fun activate(user: User) { // код активации } /// вместо /// val user = getUser(id) /* * Validate user */ // код валидации /* * Activate user */ // код активации |
А лучше — функции-расширения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private fun User.validate(): User { // код валидации return this } private fun User.activate(): User { // код активации return this } ... val user = getUser(id) .validate() .activate() |
Инфиксные функции делают код более легким для чтения:
1 2 3 4 5 6 7 8 9 |
val x = mapOf(1 to "a") val range = 1 until 10 val loop = listOf(...) zip listOf(...) /// вместо /// val x = mapOf(1.to("a")) val range = 1.until(10) val loop = listOf(...).zip(listOf(...)) |
Делайе функции инфиксными, если:
- функция не имеет побочных эффектов;
- имеет простую логику;
- имеет короткое имя;
- используется в местах, где скобки будут мешать чтению.
Используйте функции with, apply и also:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
...какой-то код... with(foo.id) { LOGGER.info("id is $this") doSomething() // method of id doSomethingElse(this) } ...какой-то код... /// вместо /// ...какой-то код... val id = foo.id LOGGER.info("id is $id") id.doSomething() doSomethingElse(id) ...какой-то код... |
Не указывайте тип там, где его можно не указывать:
1 2 3 4 5 6 7 |
val x = "a" override fun foo() = 1 /// вместо /// val x: String = "a" override fun foo(): Int = 1 |
Исключения:
- возвращаемый функцией тип слишком сложный, например
Map<Int, Map<String, String>>
; - когда вызываешь функции, не имеющие nullable-аннотации (например, обычные функции Java).
Используйте присваивание при создании функции, состоящей из одного выражения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
fun foo(id: Int) = getFoo(id) .chain1() .chain2() .chain3() .chain4 { // лямбда } /// вместо /// fun foo(id: Int): Bar { return getFoo(id) .chain1() .chain2() .chain3() .chain4 { // лямбда } } |
Typealias упростит работу со сложными типами:
1 2 3 4 5 6 7 8 9 10 |
typealias CustomerId = Int typealias PurchaseId = String typealias StoreName = String typealias Report = Map<CustomerId, Map<PurchaseId, StoreName>> fun(report: Report) = // ... /// вместо /// fun(report: Map<Int, Map<String, String>>) = // ... |
Используйте метки точности для уточнения типа присваиваемого значения:
1 2 3 4 5 6 7 |
val x = 1L val y = 1.2f /// вместо /// val x: Long = 1 val y: Float = 1.2 |
Пользуйтесь подчеркиванием, чтобы сделать длинные числа более читаемыми:
1 2 3 4 5 |
val x = 1_000_000 /// вместо /// val x = 1000000 |
Применяйте интерполяцию строк, чтобы сделать их более читаемыми:
1 2 3 4 5 6 7 |
val x = "customer $id bought ${purchases.count()} items" val y = """He said "I’m tired"""" /// вместо /// val x = "customer " + id + " bought " + purchases.count() + " items" val y = "He said \"I’m tired\"" |
Используйте оператор ? для возврата управления:
1 2 3 4 5 6 7 8 9 |
val user = getUser() ?: return 0 /// вместо /// val user = getUser() if (user == null) { return 0 } |
Применяйте тип Sequence для оптимизации обработки очень длинных списков (более 1000 элементов):
1 2 3 4 5 6 7 8 9 10 11 |
listOf(1).asSequence() .filter { ... } .map { ... } .maxBy { ... } /// вместо /// listOf(1) .filter { ... } .map { ... } .maxBy { ... } |
Используйте обратные кавычки при написании имен тестов:
1 2 3 4 5 |
fun `test foo - when foo increases by 3% - returns true`() { ... } /// вместо /// fun testFoo_whenFooIncreasesBy3Percent_returnsTrue() { ... } |
Write fluent code in Kotlin — полная английская статья с советами о том, как написать чистый код на Kotlin.