Что такое Котлин? Объяснение альтернативы Java

Kotlin - это универсальный бесплатный «прагматический» язык программирования с открытым исходным кодом, статически типизированный, изначально разработанный для JVM (виртуальная машина Java) и Android, который сочетает в себе функции объектно-ориентированного и функционального программирования. Он ориентирован на совместимость, безопасность, ясность и поддержку инструментов. Версии Kotlin, ориентированные на JavaScript ES5.1 и собственный код (с использованием LLVM) для ряда процессоров, также находятся в разработке.

Kotlin возник в JetBrains, компании, стоящей за IntelliJ IDEA, в 2010 году и работает с открытым исходным кодом с 2012 года. В настоящее время команда Kotlin насчитывает более 90 постоянных членов JetBrains, а проект Kotlin на GitHub насчитывает более 300 участников. JetBrains использует Kotlin во многих своих продуктах, включая флагманскую IntelliJ IDEA.

Kotlin как более лаконичный язык Java

На первый взгляд Kotlin выглядит как более лаконичная и упрощенная версия Java. Рассмотрим снимок экрана выше, где я автоматически преобразовал образец кода Java (слева) в Kotlin. Обратите внимание, что бессмысленное повторение, присущее созданию экземпляров переменных Java, исчезло. Идиома Java

StringBuilder sb = новый StringBuilder ();

Становится в Котлине

val sb = StringBuilder ()

Вы можете видеть, что функции определяются с помощью funключевого слова, и что точки с запятой теперь необязательны, когда присутствуют символы новой строки. valКлючевое слово объявляет свойство только для чтения или локальной переменной. Точно так же varключевое слово объявляет изменяемое свойство или локальную переменную.

Тем не менее Котлин строго типизирован. valИ varключевые слова могут быть использованы только тогда , когда тип может быть выведен. В противном случае вам нужно объявить тип. Вывод типов, кажется, улучшается с каждым выпуском Kotlin.

Взгляните на объявление функции в верхней части обеих панелей. Тип возврата в Java предшествует прототипу, но в Kotlin он следует за прототипом, обозначенным двоеточием, как в Pascal.

Это не совсем очевидно из этого примера, но Kotlin ослабил требование Java, чтобы функции были членами класса. В Kotlin функции могут быть объявлены на верхнем уровне в файле, локально внутри других функций, как функция-член внутри класса или объекта и как функция расширения. Функции расширения предоставляют возможность C # расширять класс с помощью новых функций без необходимости наследовать от класса или использовать какой-либо тип шаблона проектирования, например Decorator.

Для поклонников Groovy Kotlin реализует конструкторы; Фактически, сборщики Kotlin могут быть проверены по типу. Kotlin поддерживает делегированные свойства, которые можно использовать для реализации ленивых свойств, наблюдаемых свойств, свойств, на которые можно накладывать вето, и сопоставленных свойств.

Многие асинхронные механизмы, доступные на других языках, могут быть реализованы в виде библиотек с использованием сопрограмм Kotlin. Это включает async/ awaitиз C # и ECMAScript, каналы и выбор из Go и generators/ yieldиз C # и Python.

Функциональное программирование на Котлине

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

Фильтрация списка в Котлине

val positives = list.filter {x -> x> 0}

Для еще более короткого выражения используйте, itкогда в лямбда-функции есть только один параметр:

val positives = list.filter {it> 0}

Путешествие по карте / списку пар в Котлине

for ((k, v) на карте) {println («$ k -> $ v»)}

kи  v может называться как угодно.

Использование диапазонов в Котлине

for (i in  1..100) {...} // закрытый диапазон: включает 100

for (от  1 до 100) {...} // полуоткрытый диапазон: не включает 100

for (x в  2..10 шаге 2) {...}

for (x in  10 downTo 1) {...}

if (x in  1..10) {...}

В приведенных выше примерах показано  for ключевое слово, а также использование диапазонов.

Несмотря на то, что Kotlin является полноценным языком функционального программирования, он сохраняет большую часть объектно-ориентированной природы Java в качестве альтернативного стиля программирования, что очень удобно при преобразовании существующего кода Java. Котлин имеет классы с конструкторами, вместе с вложенными, внутренними и анонимными внутренними классами, и имеют интерфейсы , как Java 8. Котлин вовсе не имеет newключевое слово. Чтобы создать экземпляр класса, вызовите конструктор как обычную функцию. Мы видели это на скриншоте выше.

Kotlin имеет единственное наследование от именованного суперкласса, и все классы Kotlin имеют суперкласс по умолчанию Any, который не совпадает с базовым классом Java java.lang.Object. Anyсодержит только три предопределенные функции члена: equals(), hashCode()и toString().

Классы Kotlin должны быть помечены openключевым словом, чтобы другие классы могли наследовать от них; Классы Java - это своего рода противоположность, поскольку они наследуются, если не отмечены finalключевым словом. Чтобы переопределить метод суперкласса, необходимо пометить openсам метод и пометить метод подкласса override. Это все часть философии Kotlin, которая заключается в том, чтобы делать вещи явными, а не полагаться на значения по умолчанию. В этом конкретном случае я вижу, где способ Kotlin явной пометки членов базового класса как открытых для наследования и членов производных классов как переопределений позволяет избежать нескольких типов распространенных ошибок Java.

Функции безопасности в Котлине

Говоря об избежании распространенных ошибок, Kotlin был разработан, чтобы устранить опасность ссылок на нулевые указатели и упростить обработку нулевых значений. Он делает это, делая nullнедопустимыми для стандартных типов, добавляя типы, допускающие значение NULL, и реализуя сокращенные обозначения для обработки тестов на значение NULL.

Например, обычная переменная типа  не может содержать  :String null

var a: String = "abc"

a = null // ошибка компиляции

Если вам нужно разрешить нули, например, для хранения результатов SQL-запроса, вы можете объявить тип, допускающий значение NULL, добавив к типу вопросительный знак, например String?.

var  b: String?

b = null  // хорошо

Защита идет немного дальше. Вы можете безнаказанно использовать тип, не допускающий значения NULL, но перед его использованием необходимо протестировать тип, допускающий значение NULL, на наличие значений NULL.

Чтобы избежать многословной грамматики, обычно необходимой для нулевого тестирования, Kotlin вводит безопасный вызов в письменном виде ?.. Например, возвращается, если нет , и в противном случае. Тип этого выражения - .b?.length b.lengthbnullnullInt?

Другими словами, b?.lengthэто ярлык для if (b != null) b.length else null. Этот синтаксис красиво цепляется, устраняя довольно много сложной логики, особенно когда объект был заполнен из серии запросов к базе данных, любой из которых мог дать сбой. Например, bob?.department?.head?.nameвернет имя главы отдела Боба, если Боб, отдел и глава отдела не равны нулю.

Чтобы выполнить определенную операцию только для ненулевых значений, вы можете использовать безопасный оператор вызова ?.вместе с  let:

val listWithNulls: List = listOf ("A", ноль)

for (элемент в listWithNulls) {

      item? .let {println (it)} // печатает A и игнорирует null}

Часто вы хотите вернуть допустимое, но особое значение из выражения, допускающего значение NULL, обычно для того, чтобы сохранить его в типе, не допускающем значения NULL. Для этого написан специальный синтаксис, называемый оператором Элвиса (я не шучу) ?:.

val l = b? .length?: -1

эквивалентно 

val l: Int = if (b! = null) b.length else -1

В том же духе Kotlin опускает проверенные исключения Java, которые являются бросаемыми условиями, которые необходимо перехватить. Например, подпись JDK

Добавляемое добавление (CharSequence csq) выбрасывает  IOException;

требует от вас ловить IOExceptionкаждый раз, когда вы вызываете appendметод:

пытаться {

  log.append (сообщение)

}

catch (IOException e) {

  // Делаем что-нибудь с исключением

}

Разработчики Java думали, что это хорошая идея, и это была чистая победа для игрушечных программ, если программисты реализовали что-то разумное в этом catchпредложении. Слишком часто в больших программах Java, однако, вы видите код , в котором обязательный catchпункт не содержит ничего , кроме комментария: //todo: handle this. Это никому не помогает, а проверенные исключения обернулись чистым убытком для больших программ.

Котлинские сопрограммы

Сопрограммы в Kotlin - это, по сути, легкие потоки. Вы запускаете их с помощью launchпостроителя сопрограмм в контексте некоторых CoroutineScope. Одна из самых полезных областей сопрограммы - runBlocking{}это область действия ее блока кода.

импортировать kotlinx.coroutines. *

fun main () = runBlocking {// this: CoroutineScope

    launch {// запускаем новую сопрограмму в рамках runBlocking

        delay (1000L) // неблокирующая задержка на 1 секунду

        println ("Мир!")

    }

    println ("Привет,")

}

Этот код производит следующий вывод с задержкой в ​​одну секунду между строками:

Здравствуйте,

Мир!

Kotlin для Android

Вплоть до мая 2017 года единственными официально поддерживаемыми языками программирования для Android были Java и C ++. Google объявила об официальной поддержке Kotlin на Android на Google I / O 2017, и начиная с Android Studio 3.0 Kotlin встроен в набор инструментов для разработки Android. Kotlin можно добавить в более ранние версии Android Studio с помощью плагина.

Kotlin компилируется в тот же байтовый код, что и Java, естественным образом взаимодействует с классами Java и делится своими инструментами с Java. Поскольку нет накладных расходов на вызовы между Kotlin и Java, поэтапное добавление Kotlin в приложение Android, которое в настоящее время находится на Java, имеет смысл. Те немногие случаи, когда совместимости между кодом Kotlin и Java не хватает изящества, например, свойства Java только для набора, встречаются редко и легко исправляются.

Pinterest был образцом приложений для Android, написанных на Kotlin еще в ноябре 2016 года, и был заметно упомянут на Google I / O 2017 как часть анонса Kotlin. Кроме того, команда Kotlin любит ссылаться на приложения Evernote, Trello, Square и Coursera для Android.

Котлин против Java

Вопрос о том, следует ли выбрать Kotlin или Java для новой разработки, много раз поднимался в сообществе Android с момента объявления Google I / O, хотя люди уже задавали этот вопрос в феврале 2016 года, когда был выпущен Kotlin 1.0. Короткий ответ заключается в том, что код Kotlin более безопасен и лаконичен, чем код Java, и что файлы Kotlin и Java могут сосуществовать в приложениях Android, так что Kotlin полезен не только для новых приложений, но и для расширения существующих приложений Java.

Единственный убедительный аргумент, который я видел в пользу выбора Java вместо Kotlin, был бы в случае полных новичков в разработке Android. Для них может существовать препятствие, которое необходимо преодолеть, учитывая, что исторически большая часть документации и примеров Android написана на Java. С другой стороны, преобразование Java в Kotlin в Android Studio - это простой вопрос вставки кода Java в файл Kotlin.

Практически для всех, кто занимается разработкой под Android, преимущества Kotlin очевидны. Обычно Java-разработчик изучает Kotlin в несколько часов - небольшая плата за устранение ошибок нулевых ссылок, включение функций расширения, поддержку функционального программирования и добавление сопрограмм. Типичная приблизительная оценка показывает примерно 40-процентное сокращение количества строк кода с Java на Kotlin.