Как стать автором
Обновить
743.06
OTUS
Цифровые навыки от ведущих экспертов

Почему вам следует полностью переходить на Kotlin

Время на прочтение6 мин
Количество просмотров31K
Автор оригинала: Magnus Vinther

Я хочу рассказать вам о языке программирования Kotlin и о том, почему вы должны рассмотреть его для своего следующего проекта. Раньше я предпочитал Java, но за прошедший год обнаружил, что кодирую на Kotlin при любой возможности, и сейчас я действительно не могу придумать ситуацию, в которой Java был бы лучшим выбором.

Он разработан компанией JetBrains, и тот факт, что именно эти люди стоят в создании такого набора IDE, как IntelliJ и ReSharper, в полной мере отражается и в Kotlin. Он прагматичен и лаконичен, делает кодирование приятным и эффективным занятием.

Хотя Kotlin компилируется как в JavaScript, а скоро и в машинный код, я сосредоточусь на его основной среде - JVM.

Итак, вот несколько причин, по которым вы должны полностью перейти на Kotlin (нумерация случайна, без определенного порядка):

0# Взаимодействие с Java

Kotlin на 100% совместим с Java. Вы можете в буквальном смысле продолжать работать над своими старыми Java-проектами, используя Kotlin. Все ваши любимые Java-фреймворки по-прежнему доступны, и любой фреймворк, который вы напишете на Kotlin, будет легко принят вашим упертым другом, любящим Java.

1# Знакомый синтаксис

Kotlin - это не какой-то необычный язык, рожденный в академических кругах. Его синтаксис знаком любому программисту, пришедшему из области ООП, и может быть более или менее понятен с самого начала. Конечно, есть некоторые отличия от Java, например, переработанные конструкторы или объявления переменных val var. В приведенном ниже сниппете представлена большая часть базового синтаксиса:

class Foo {

    val b: String = "b"     // val means unmodifiable
    var i: Int = 0          // var means modifiable

    fun hello() {
        val str = "Hello"
        print("$str World")
    }

    fun sum(x: Int, y: Int): Int {
        return x + y
    }

    fun maxOf(a: Float, b: Float) = if (a > b) a else b

}

2# Интерполяция строк

Это как если бы в язык была встроена более умная и читабельная версия функции String.format() из Java:

val x = 4
val y = 7
print("sum of $x and $y is ${x + y}")  // sum of 4 and 7 is 11

3# Вывод типов

Kotlin будет выводить ваши типы, если вы посчитаете, что это улучшит читабельность:

val a = "abc"                         // type inferred to String
val b = 4                             // type inferred to Int

val c: Double = 0.7                   // type declared explicitly
val d: List<String> = ArrayList()     // type declared explicitly

4# "Умные" преобразования. (Smart Casts)

Компилятор Kotlin отслеживает вашу логику и по возможности автоматически выполняет приведение типов, что означает избавление от проверок instanceof и явных преобразований:

if (obj is String) {
    print(obj.toUpperCase())     // obj is now known to be a String
}

5# Интуитивные равенства

Вы можете перестать явно вызывать equals(), потому что оператор == теперь проверяет структурное равенство:

val john1 = Person("John")
val john2 = Person("John")
john1 == john2    // true  (structural equality)
john1 === john2   // false (referential equality)

6# Аргументы по умолчанию

Нет необходимости определять несколько одинаковых методов с разными аргументами:

fun build(title: String, width: Int = 800, height: Int = 600) {
    Frame(title, width, height)
}

7# Именованные аргументы

В сочетании с аргументами по умолчанию именованные аргументы избавляют от необходимости использовать строителей (builders):

build("PacMan", 400, 300)                           // equivalent
build(title = "PacMan", width = 400, height = 300)  // equivalent
build(width = 400, height = 300, title = "PacMan")  // equivalent

8# Выражение When

В качестве замены оператору switch используется гораздо более удобное и гибкое выражение when:

when (x) {
    1 -> print("x is 1")
    2 -> print("x is 2")
    3, 4 -> print("x is 3 or 4")
    in 5..10 -> print("x is 5, 6, 7, 8, 9, or 10")
    else -> print("x is out of range")
}

Оно работает как выражение, и как оператор, с аргументом, и без него:

val res: Boolean = when {
    obj == null -> false
    obj is String -> true
    else -> throw IllegalStateException()
}

9# Свойства

К публичным полям может быть добавлено кастомное поведение set и get, что позволит нам остановить загромождение кода бессмысленными геттерами и сеттерами.

class Frame {
    var width: Int = 800
    var height: Int = 600

    val pixels: Int
        get() = width * height
}

10# Класс данных (Data Class)

Это POJO (Plain Old Java Object) с функциями toString(), equals(), hashCode() и copy(), и в отличие от Java он не занимает почти 100 строк кода:

data class Person(val name: String,
                  var email: String,
                  var age: Int)

val john = Person("John", "john@gmail.com", 112)

11# Перегрузка оператора

Предопределенный набор операторов может быть перегружен для улучшения читабельности:

data class Vec(val x: Float, val y: Float) {
    operator fun plus(v: Vec) = Vec(x + v.x, y + v.y)
}

val v = Vec(2f, 3f) + Vec(4f, 1f)

12# Объявления деструктуризации

Некоторые объекты могут быть деструктурированы, что, например, полезно для итерации карт:

for ((key, value) in map) {
    print("Key: $key")
    print("Value: $value")
}

13# Диапазоны

Для улучшения читабельности:

for (i in 1..100) { ... } 
for (i in 0 until 100) { ... }
for (i in 2..10 step 2) { ... } 
for (i in 10 downTo 1) { ... } 
if (x in 1..10) { ... }

14# Функции расширения

Помните, когда вам впервые понадобилось отсортировать List в Java? Вы не могли найти функцию sort() и вам в результате пришлось узнать о Collections.sort(). А позже, когда вам нужно было написать String с заглавной буквы, то это привело к написанию собственной вспомогательной функции, потому что вы не знали о StringUtils.capitalize().

Если бы только существовал способ добавить новые функции в старые классы; тогда ваша IDE смогла бы помочь вам найти нужную функцию при автоматическом дополнении кода. В Kotlin вы можете сделать именно это:

fun String.replaceSpaces(): String {
    return this.replace(' ', '_')
}

val formatted = str.replaceSpaces()

Стандартная библиотека расширяет функциональность оригинальных типов Java, что особенно требовалось для String:

str.removeSuffix(".txt")
str.capitalize()
str.substringAfterLast("/")
str.replaceAfter(":", "classified")

15# Null безопасность

Java - это то, что мы должны назвать почти статически типизированным языком. В нем переменная типа String не гарантированно ссылается на String - она может ссылаться на null. Несмотря на то, что мы привыкли к этому, это сводит на нет безопасность статической проверки типов, и в результате разработчикам Java приходится жить в постоянном страхе перед ошибкой NPE (NullPointerException).

Kotlin решает эту проблему, проводя различие между ненулевыми (non-null) и  обнуляемыми (nullable) типами. Типы по умолчанию являются non-null, и их можно сделать nullable, добавив ? как, например:

var a: String = "abc"
a = null                // compile error

var b: String? = "xyz"
b = null                // no problem

Kotlin заставляет вас защищаться от NPE всякий раз, когда вы обращаетесь к nullable-типу:

val x = b.length        // compile error: b might be null

И хотя это может показаться громоздким, на самом деле все просто благодаря нескольким особенностям Kotlin. У нас все еще есть умное приведение, которое преобразует nullable типы в non-null везде, где это возможно:

if (b == null) return
val x = b.length        // no problem

Мы также можем использовать безопасный вызов ?., который производит проверку на нулевое значение вместо того, чтобы выбрасывать NPE:

val x = b?.length       // type of x is nullable Int

Безопасные вызовы можно объединять в цепочки, чтобы избежать вложенных проверок if-not-null (если-не-ноль), которые мы иногда пишем в других языках, и если нам нужно значение по умолчанию, отличное от null, то используем elvis-оператор ?::

val name = ship?.captain?.name ?: "unknown"

Если ничего из этого вам не подходит, и необходимость в NPE крайне велика, то скажите об этом явно:

val x = b?.length ?: throw NullPointerException()  // same as below
val x = b!!.length                                 // same as above

16# Улучшенные лямбды

Это хорошая система лямбд - она идеально сбалансирована между читабельностью и сложностью, благодаря продуманному дизайну, с простым синтаксисом:

val sum = { x: Int, y: Int -> x + y }   // type: (Int, Int) -> Int
val res = sum(4,7)                      // res == 11

А вот и толковые решения:

  1. Скобки метода могут быть перемещены или опущены, если лямбда идет последней либо является единственным аргументом метода.

  2. Если мы решили не объявлять аргумент одноаргументной лямбды, он будет неявно объявлен под именем it.

Эти факты в совокупности делают следующие три строки эквивалентными:

numbers.filter({ x -> x.isPrime() })
numbers.filter { x -> x.isPrime() }
numbers.filter { it.isPrime() }

И это позволяет нам писать лаконичный функциональный код - только посмотрите на эту красоту:

persons
    .filter { it.age >= 18 }
    .sortedBy { it.name }
    .map { it.email }
    .forEach { print(it) }

Система лямбд Kotlin в сочетании с функциями расширения делает его идеальным для создания DSL. Взгляните на Anko в качестве примера DSL, который призван улучшить разработку Android:

verticalLayout {
    padding = dip(30)
    editText {
        hint = “Name”
        textSize = 24f
    }
    editText {
        hint = “Password”
        textSize = 24f
    }
    button(“Login”) {
        textSize = 26f
    }
}

17# Поддержка IDE

У вас есть несколько вариантов, если вы собираетесь начать работу с Kotlin, но я настоятельно рекомендую использовать IntelliJ, который поставляется в комплекте с Kotlin - его возможности продемонстрируют все преимущество того, что и язык, и IDE разрабатываются одними и теми же людьми.

В качестве небольшого, но показательного примера, вот что всплыло, когда я впервые попытался скопипастить Java-код со Stack Overflow:

IntelliJ заметит, если вы вставите Java-код в файл Kotlin


Завтра состоится открытое занятие «Основы классов и объектов», на котором мы посмотрим на принципы проектирования классов и их реализации в Kotlin. Поймем, как объектно-ориентированное программирование работает изнутри, создадим свои структуры и посмотрим на возможности языка Kotlin. Спроектируем объектную модель данных. Регистрируйтесь по ссылке.

Теги:
Хабы:
+12
Комментарии58

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS