Нововведения в Kotlin 1.4.0

Сегодня я решил написать о самых главных нововведениях в Kotlin 1.4.0. Думаю, что начинающим Android разработчикам будет очень интересна данная тема и они смогут применить новые фишки в своих приложениях. Также, я надеюсь, что моя статья будет полезна и для профессиональных разработчиков, которые очень любят и помогают развивать Kotlin.

Основные темы, которые я затрону:

  • Нововведения в синтаксисе

  • Новые инструменты в IDE

  • Новый компилятор

  • Качество и производительность

Ну что ж, предлагаю вам налить себе кофе или чай, запастись сладеньким и можно начинать)

Немного о релизах Kotlin

На момент написания статьи самыми новыми релизами были:

Релиз

Дата и краткое описание

Kotlin 1.4.0

17 августа, 2020, основной пласт нововведений, который мы сегодня рассмотрим. Улучшение производительности, введение новых синтаксических конструкций и добавление новых функций в IDE.

Kotlin 1.4.10

Kotlin 1.4.20

Kotlin 1.4.21

7 сентября, 2020, исправление багов для Kotlin 1.4.0

23 ноября, 2020, несколько улучшений, такие как производительность и поддержка новых функций для JVM.

7 декабря, 2020, исправление ошибок для Kotlin 1.4.20

Нововведения в синтаксисе

SAM - интерфейсы

Одной из самых важных и довольно полезных фишек является добавление нового синтаксиса для SAM интерфейсов (SAM - Single Abstract Method, также интерфейс с одним методом называют функциональным).

Чтобы указать компилятору Kotlin о том, что перед нами SAM интерфейс нужно использовать ключевое слов fun, как ниже в примере:

fun interface ItemSelectListener {
		fun onItemSelect(position: Int): String
}

val items = listOf("Item 1", "Item 2", "Item 3")

val myListener = ItemSelectListener { position ->
		items[position]
}

fun main() {
    print("selected item -> ${myListener.onItemSelect(0)}")
}

Одно из применений: передача обработчиков событий в адаптер RecyclerView для отслеживания нажатия на элемент списка.

Данный подход сокращает количество строк кода и вводит дополнительные удобства.

Явный API режим

Kotlin предлагает новый явный API режим для разработчиков библиотек.

Основные моменты:

  1. Явный API режим помогает делать API библиотек чистым и последовательным

  2. Накладывает различные требования и ограничения на публичные API:

    1. Строгое использование модификаторов доступа

    2. Явное указание типов для свойств и функций, которые являются частью публичного API

  3. Некоторые определения исключены из проверок: свойства data классов, первичные конструкторы и т.д.

Более подробно

Смешанные именованные и позиционные параметры

Довольно легко объяснить на примере. До Kotlin 1.4.0 нельзя было делать так:

fun foo(a: Int, b: String = "", c: Int) {}

fun main() {
		foo(a = 10, "Hello, World", c = 100000)
}

В данном примере мы сначала указываем именованный параметр, а потом позиционный (строка "Hello, World"). В ранних версиях Kotlin нужно было всегда указывать сначала позиционные.

Конечная запятая

Довольное удобно при обмене строк или копировании параметров функций

fun reformat(str: String, 
             wordSeparator: Char = ' ', // конечная запятая
) {
  // TODO
}

Улучшения вызываемых ссылок на функции

Теперь вы можете использовать ссылки на функции, которые имеют default аргументы:

fun foo(a: Int = 0): String = "value -> $a" // параметр 'a' имеет значение по умолчанию 0

fun apply(f: () -> String): String = f()

fun main() {
    println(apply(::foo))
}

Вы можете использовать ссылки на функции, которые возвращают любое тип там, где требуются функции возвращающие Unit.

Например у нас есть функция foo, которая принимает другую функцию, которая ничего не возращает (Unit). Мы можем передать ей любую ссылку на функцию, у которой совпадает количество аргументов, а возвращаемый тип может быть любой:

fun foo(f: () -> Unit) { }
fun returnValue(): Int = 42

fun main() {
    foo { returnValue() } // Так было до Kotlin 1.4.0
    foo(::returnValue) // начиная с Kotlin 1.4.0 можно передать сюда функцию, 
  									  // которая возвращает любой тип
}

Вы можете адаптировать ссылки на функции, когда передается переменное количество аргументов:

fun foo(a: Int, vararg words: String) {}

fun useCase0(f: (Int) -> Unit) {}
fun useCase1(f: (Int, String) -> Unit) {}
fun useCase2(f: (Int, String, String) -> Unit) {}

fun test() {
    useCase0(::foo) 
    useCase1(::foo) 
    useCase2(::foo) 
}

В дополнение появилась поддержка передачи ссылки на функцию там, где используется ключевое слово suspend

fun lockUI() {}
fun takeSuspend(f: suspend () -> Unit) {}

fun test() {
    takeSuspend { lockUI() } // до Kotlin 1.4.0
    takeSuspend(::lockUI) // В Kotlin 1.4.0 можно сделать так
}

Использование break and continue внутри when выражений, включенных в цикл for

В Kotlin 1.4.0 вы можете использовать ключевые слова break и continue в операторе when, когда он вложен в циклfor (до этого нужно было создавать метки, более подробно)

fun foo(numbers: List<Int>) {
    for (num in numbers) {
        when {
            num % 2 == 0 -> continue
            num == 10 -> break
            else -> println(x)
        }
    }
}

Новые инструменты в IDE

Новое гибкое окно создания проекта

Теперь вы можете создавать и конфигурировать различные типы проектов Kotlin более гибко и специфично:

Новое окно создания проекта позволяет:

  1. Выбрать шаблон проекта (в будущем будет добавлено больше шаблонов)

  2. Выбрать систему сборки (Gradle, Maven)

  3. Посмотреть структуру проекта до его создания

  4. Добавить/удалить модули, поддерживаемые данным шаблоном проекта

  5. Настроить JVM версию, framework для тестирования и другие вещи.

Отладчик Корутин

Очень много разработчиков на Kotlin используют всеми известные корутины (а как же без них).

До Kotlin 1.4.0 приходилось полагаться на ведение логов и умственные усилия разработчика, чтобы отлаживать программы с наличием корутин.

Теперь появился новый инструмент, который находится в Debug Tool Window в Intellij IDEA, который позволяет:

  1. Легко проверить состояние каждой корутины

  2. Посмотреть значения локальных и захваченных переменных для корутин

  3. Посмотреть полный стек создания корутины, а также стек внутри корутины (все фрэймы с локальными переменными)

  4. Также можно получить полный отчет, воспользовавшись функцией Get Coroutines Dump

Новый компилятор

Главной целью создания нового компилятора было соответствие характеристикам:

  1. Скорость

  2. Создание общего интерфейса для разных платформ, которые поддерживает Kotlin

  3. Обеспечение API для расширения компилятора

Основные улучшения по сравнению с предыдущим компилятором:

  1. Новый более мощный алгоритм для автоматического вывода типов с поддержкой более сложных сценариев вывода типов и с улучшенниями для делегированных свойств. (данный алгоритм уже был доступен в версии Kotlin 1.3 при указании дополнительных опций, в новой версии он будет использоваться по умолчанию). Вы можете найти более десятка исправленных багов и ошибок в новом алгоритме на YouTrack

  2. Унифицированный backend компилятора (в Kotlin есть несколько backend, таких как: Kotlin/JVM, Kotlin/JS и Kotlin/Native. Последний был основан на промежуточном представлении (IR) для Kotlin кода)

Сейчас компания JetBrains работает над более производительной frontend реализацией.

Frontend - это часть компилятора, которая разбирает код, разрешает имена, выполняет проверки типов и многое другое.

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

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

Основные улучшения:

  1. Было исправлено более 60 ошибок производительности, включая большое количество случаев зависания IDE и утечек памяти

  2. Прирост в скорости IDE, который можно увидеть, пройдя по ссылке (здесь время подсвечивания синтаксиса Kotlin при открытии большого проекта). Также на рисунке ниже показано время срабатывания автодополнения (которое уменьшилось по сравнению с предыдущими релизами)

  3. И многие другие, которые напрямую связаны с созданием нового компилятора.

Немного полезных ссылок

  1. Информация о релизе Kotlin 1.4.0 на блоге JetBrains

  2. Нововведения на официальном сайте Kotlin

  3. Kotlin 1.4.0 Online Event (на английском)

  4. Статистика от StackOverflow Survey 2020

  5. Cтатистика от JetBrains

Комментарии 33

    –13
    У меня никто из знакомых Андройд-разработчиков не переходил на Kotlin — все на Java, так зачем переходить на Kotlin если есть Java??
      +10

      Он стильный, модный, молодёжный. Меньше кода, больше null-safety
      Я бы спросил иначе: зачем использовать на андроиде Джаву, если есть Котлин


      Если у вас уже есть огромный проект на Джаве, то его переводить на Котлин может и не обязательно. Но новые проекты, по-моему, явно стоит начинать писать на Котлине

        0
        Я бы спросил иначе: зачем использовать на андроиде Джаву, если есть Котлин

        Например, Джаву знаешь, а Котлин нет, а у нового проекта жёсткий дедлайн. Рискнёте писать новый проект на незнакомом языке?

          +2

          Конечно нет. Разумные действия должны быть в приоритете.
          Есть ещё куча других причин использовать джаву вместо котлина.


          Однако, на мой вкус, на андроиде котлин стоит использовать в бóльшем количестве случаев. Если это не вызывает критических проблем (совместимость, дедлайны, требования, кровь из глаз)


          И котлин уже довольно давно на рынке. Потратить немного времени на изучение его основ, мне кажется, это лучше чем задавать вопросы в стиле "все на Java, так зачем переходить на Kotlin если есть Java??"
          В конце конков каждый выбирает сам. Но выбор из-за незнания вряд ли является правильным.

            +1

            Обычно ровно наоборот: ратуют за переход на котлин не аргументируя особо зачем изучать, кроме спортивного интереса вдруг понравится. Метрик никаких нет, только куски кода на 5 строк в лучшем случае. Вот у вас есть что-то вроде: переписали проект на 100к loc — стало 50к, памяти стал меньше жрать, задачи которые раньше занимали неделю разработки только, сейчас через три дня в проде. Архитектуру и публичный АПИ пакетов при этом не меняли, просто переписали всё внутри их


            Ну и для некоторых вопрос стоит не перейти с джава на котлин, а перейти с Х на джава или на котлин. А выглядит со стороны это как: джава — легаси, но переход возможен только на джава+котлин — своя экосистема у котлина гораздо менее развита.

              +3
              Вот у вас есть что-то вроде: переписали проект на 100к loc — стало 50к,

              К сожалению нет. Мы сейчас только потихоньку добавляем котлин в проект (по гитхабу, 7% репозитория). Новые тесты и простые утилиты на нем. Следующий шаг — новые продакшн модули делать на котлине.
              Т.е. о трансформации имеющегося кода речи не идёт.


              И объективных метрик у нас нет. У меня есть только субъективная: получение большего удовольствия от разработки.


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


              1. .stream.collect(Collectors.toList())
              2. (почти все) опшионалы
              3. перегрузка методов
              4. ломбок аннотации
              5. Nullable/NotNull аннотации. И проверки на null
              6. Объявления типов переменных (Map<String, List<MyCoolWrapper<Entity>>>)
              7. Objects.equals, object1.compareTo(object2) > 0
              8. final модификатор

              У каждого свой подход к разработке, и какие-то пункты могут отсутствовать. Но в любом случае это всё визуальный мусор, который не влияет на функциональность (разве что в случае стримов) и ухудшает читаемость.


              Но есть и куча подводных камней, типа совместимости с другими библиотеками (например ломбок вместе с котлин классами плохо работают), или медленная компиляция/автокомплит.


              но переход возможен только на джава+котлин — своя экосистема у котлина гораздо менее развита.

              У меня бывший коллега в новой компании перевёл весь джава проект на чистый котлин (без джава кода, но в библиотеками), насколько я знаю. О каких-то критических проблемах он так и не сознался.


              Кстати, на всякий случай уточню, я разделяю 3 "технологии" в данном случае:


              1. Андроид джава
              2. Бэкенд джава
              3. Котлин

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

                +5
                У меня «есть такое». Пишу бэкенд и Android-приложения, сейчас активно мигрирую на котлин (кстати, о плюсах — мигрировать на Котлин можно хоть по одному классу за раз, он абсолютно бесшовно совместим с Java-кодом в обе стороны включая различные библиотеки, работающие с reflection). По числу строк кода — в среднем на 50% меньше. Помимо в принципе менее «многословного» синтаксиса, при повседневном использовании, одна из самых удобных вещей — это очень обширная и продуманная стандартная библиотека с активным применением extension functions. Apache Commons и прочие Гуавы становятся практически не нужны.

                Вот простенький примерчик. templates — это List объектов, которые надо отсортировать сперва по дате lastSubmit по убыванию, потом по label по возрастанию без учёта регистра. Теперь представьте, сколько всяких анонимных компараторов для этого надо нагородить в Java.
                templates.sortedWith(
                         compareByDescending<FormBase> { it.lastSubmit }
                        .thenBy(String.CASE_INSENSITIVE_ORDER) { it.label }
                )
                


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

                «переход возможен только на джава+котлин — своя экосистема у котлина гораздо менее развита» — вот это непонятно абсолютно. Котлин работает на JVM и отдельная «экосистема» ему не требуется. И это плюс, а не минус — всё накопленное за годы развития JVM доступно без какой либо потребности в адаптации или портировании. Какие-то более удобные синтаксические штуки для крупных библиотек типа Spring уже написаны, но можно спокойно жить без них.
                  0
                  Есть довольно много case study по разным направлениям разработки: бэкенд, mobile multiplatform. Про андроид от гугла, там как раз есть про LOC:
                  The biggest improvement they saw was that writing in Kotlin reduced their converted lines of code by 20%

                  Впрочем согласен, что вместо этого в статьях чаще пишут про дата классы, в ответ на что довольно справедливо сказать «у нас есть lombok». Ну щто поделать (:
            +7
            Оставляя в покое холиварные аргументы, хотя бы из-за этого developer.android.com/kotlin
            Write better Android apps faster with Kotlin. Kotlin is a modern statically typed programming language used by over 60% of professional Android developers that helps boost productivity, developer satisfaction, and code safety.

            p.s.: Лично мы в свое время свалили с java именно потому, что достали переусложненные конструкции, котлин лаконичнее и проще.
              +5
              Зачем переходить на новые процы если есть пентиум 4?
              Консервативные у вас друзья, придет время когда будут брать только на мобильное котлин/свифт/флаттер, а они все на java)
                +4
                Kotlin имеет очень много преимуществ по сравнению с Java:

                1. Лаконичный и простой синтаксис
                2. Null безопасность — одна из самых главных фишек Kotlin
                3. Высокая поддержка и хорошо развитая экосистема
                4. Kotlin позволяет увеличить скорость разработки в несколько раз, что имеет огромный вес
                5. Более низкий порог входа, что позволяет быстрее начать на нем кодить
                • НЛО прилетело и опубликовало эту надпись здесь
                    +2
                    Пожалуй, нет языка программирования с экосистемой более развитой, чем у джавы.
                    Котлин 100% совместим с явой, вплоть до того, что можно ява-классы написанные на яве вставлять в проект… и к этому еще плюс его собственная экосистема.
                      +1
                      совместимость на словах только. Если про бэк говорить, что кучу раз сталкивался с тем, что не все инструменты работают нормально с котлином. Да, иногда это можно обойти костылями, но зачем?

                      Что же касается скорости разработки — я никакой разницы не заметил, кроме возможности костыли по-быстрому сделать, котлин в этом плане действительно удобней джавы. Только если вы нормально код пишите с использованием паттернов, весь этот синтаксический сахар не сильно помогать будет.

                      возможно действительно для мобильных приложений он будет лучше джавы, но на бэке — спасибо, не надо. Я писал на нем, когда он еще в бета версии был. Недавно снова пришлось вернуться и больше желания использовать его у меня нет. Бесполезная игрушка для тех, кому надоело на джаве код писать и хочется поиграться с чем-нибудь новым.
                        +2
                        Если про бэк говорить, что кучу раз сталкивался с тем, что не все инструменты работают нормально с котлином.
                        Например? Мы больше по мобильной разработке, поэтому правда интересно. Пока ни разу не сталкивались с тем, что бы подключение ява либы приводило бы к проблемам.
                        При этом много либ используется чисто котлиновских, т.к. на яве пришлось бы велосипедить, по сути котлиновские либы под андроид это целый набор фреймворков.

                        Что же касается скорости разработки — я никакой разницы не заметил,
                        По скорости тоже разницы не заметили, но код читается намного проще, когда там меньше синтаксического мусора, пусть даже его количество убрано при помощи синтаксического сахара:)
                          +1
                          на бэке инфраструктура огромная на джаве, поэтому обычно используют просто котлин без каких-либо котлиновских либ + фреймворки с либами на джаве. Первое, что в голову приходит — что кодогенерация не работает, если поддержки котлина нет (а ее нет обычно). Т.е. annotation processing сразу отваливается.
                          в идее, как ни странно, поддержка котлина заметно хуже чем у джавы. Лично у меня индексация котлиновского кода на больших файлах просто падала.
                          Плюс расширенные возможности языка провоцируют разработчиков писать костыли и велосипеды, а не использовать готовые инструменты и конфигурировать нормально тот же спринг. На джаве то же можно костыли городить, но там это немного сложнее будет.

                          Ну и про синтаксический сахар, который чтение упрощает: на мой взгляд упрощает чтение в первую очередь хорошая организация кода и использование паттернов. Если код написан хорошо — он будет читаемым и на котлине, и на джаве и на других языках. Если код лапша из костылей, то и сахар ему не поможет. Я видел и хорошие и плохие проекты на джаве и котлине. И лично я не вижу смысла ради практически такой же читаемости кода использовать котлин вместо джавы. Если бы еще котлиновские фичи использовались, корутины например, то был бы смысл, а так точно нет.

                          Есть, конечно, вариант использовать чисто котлиновские фреймворки для бэка, но они не особо популярны по моим наблюдениям. А непопулярные инструменты использовать на проекте, который потом неизвестно сколько поддерживать — такое себе решение. Если увольняться не собираетесь или совесть есть, то лучше что-то надежное использовать.

                          Хотя если мне очень сильно понадобится котлин использовать, то я и инструменты использовать буду, которые под него заточены. А если какой-нибудь спринг используешь, то проще и лучше джаву выбрать. Тем более при правильном использовании инструментов можно действительно скорость написания кода в разы улучшить
                          +1
                          не все инструменты работают нормально с котлином

                          Подтверждаю


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

                          Не могу подтвердить. Я из тех "кому надоело джаву писать, вместо того чтобы фичи делать". Ну, всмысле, количество кода в джаве в разы больше. Взять те же .streams(), дата классы, перегрузку методов ради дефолтных параметров и т.п.
                          И самое полезное это null-safety, как по мне.


                          Но на вкус и цвет все фломастеры разные. Красные вкуснее

                            0
                            null-safety и элвис оператор действительно хороши, но ради них тянуть новый язык точно смысла нет
                        • НЛО прилетело и опубликовало эту надпись здесь
                          0
                          Я поспешил с некоторыми выводами. И поэтому приношу изменения за допущенные ошибки.

                          Kotlin, по моему мнению, эффективен для мобильной разработки.

                          В каждой области должно быть свое наилучшее решение, потому что невозможно создать один инструмент, который будет использоваться для разработки любых программ (Web, Desktop, мобильные приложения и т.д.).
                        –1
                        У меня никто из знакомых Андройд-разработчиков не переходил на Kotlin

                        [sarcasm]Я подозреваю, на Kotlin перешли только Андроид-разработчики[/sarcasm]
                          0
                          Ничего личного, но Вы похожи на моего отца с его убеждениями, что новая жигули 2106 ничем не хуже тойоты.
                          Не знаю как сейчас с java-bean'ами, но одни только data классы, функции со значениями по умолчанию и интерполяция строк в Kotlin способны придать мотивации для использования его в новом проекте.
                            0

                            Мотивации кому? Программисты, допустим, хотят. А CTO, ПМы и прочие скорее бизнес-люди, чем технари, опасаются сорвать сроки, обрушить, аптаймы, конверсии и прочие метрики. Да и скорость разработки явно просядет пока не будут изучены и освоены соотвествующие практики. Как их мотивировать начать эксперимент хотя бы, выделить время и деньги на обучение команды с риском что они будут выкинуты на строчки в резюме программистов, а до продакшена не дойдут?

                          –3
                          Новые компилятор
                            –1
                            Ну вот, указал на ошибку, ее исправили, а тебе минусы. Помогай так людям.
                              +2

                              Это в личку обычно пишется. Или хотя бы с пояснением, что это вы про ошибку.

                            0
                            Смешанные именованные и позиционные параметры

                            На мой взгляд, вредная фича, хорошо бы пример, в котором код при ее использовании станет лучше.
                              +3
                              Удивляют закостенелые взгляды на Kotlin, только Java, только бойлерплейт! Переход удобный, язык приятный, получаю такое же удовольствие как и на C#, в некоторых местах ещё приятнее. С нуля писал мобильное приложение на Kotlin без какого-либо знания Java/Kotlin, т.к. .Net разработчик.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                +1

                                Мне нравится котлин, но я всегда не понимал одного — зачем было убирать тернарный оператор? Ратуря за краткость и лаконичность заменять минималистичную и общепринятую конструкцию на монстра if (...) else… где логика?

                                  0
                                  Архитектор языка когда-то рассказывал, что они зажали его для какого-то будущего альтернативного использования.
                                  +1

                                  Я полностью с вами согласен.


                                  Вот немного холивара с создателями языка: https://discuss.kotlinlang.org/t/ternary-operator/2116/44


                                  Если кратко: котлин поддерживает if else в качестве expression (т.е. возвращает результат), поэтому его можно использовать для того же, для чего и тернарный оператор. И ради нескольких символов экономии, нет смысла вводить ещё одну конструкцию в язык


                                  Но как по мне, if smth.isValid() abc() else def() очень сильно сливается, и для моих глаз такая конструкция гораздо более читаемая: smth.isValid() ? abc() : def(), т.к. операторы визуально разделяют блоки
                                  А ещё, насколько я помню, перенос строк в идее для этих двух операторов работает по-разному, и отступы в if/else блоках не совпадают


                                  (это ответ APXEOLOG)

                                    +1
                                    Ну может создатели языка просто не хотели смешивать использование? как safe-оператора в связи со своим подходом к null-safety и условного присваивания. Если поменять концепцию и отказаться от if как выражения, возвращающего результат, то что тогда делать с when, как выражения, возражающего результат и также уместного при присваивании?

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                  Самое читаемое