Написать пост

Переход с Java на Kotlin при создании мобильного приложения

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

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

Зачем нужен переход на Kotlin

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

Kotlin сильно уменьшает количество кода, например, простой Java-объект (Plain Old Java Object), хранящий пять полей, займет примерно 96 строк кода. В то время как на Kotlin аналогичный Data-класс займёт всего одну строку, поскольку компилятор переопределит все нужные методы.

Кроме того, существует несколько серьёзных проблем, которые до сих пор есть в Java, но — внимание — уже решены в Kotlin! Вот некоторые из них:

  • Nullability — в Java мы не знаем, возможен ли null в значении данного объекта (и нельзя запретить ему принимать null), из-за чего может случиться всем известная ошибка NullPointerException, поскольку имело место обращение к «нулевому» объекту.
  • Raw types — это generic-типы в Java без указания типа-параметра, использование которых может привести к heap
    pollution — ситуации, когда переменная параметризованного типа хранит в себе объект, параметризованный другим типом. В результате может возникнуть ClassCastException в процессе исполнения программы — в Kotlin такие типы исключены.
  • Полноценные функциональные типы отсутствуют в Java в отличие от Kotlin.

Преимущества и дополнительные возможности Kotlin

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

Огромное преимущество Kotlin – наличие Coroutines, которые легко позволяют управлять потоками при асинхронном программировании. В Java аналогичный код получается более сложным, плохо читаемым и громоздким.

У Kotlin есть множество возможностей, самые примечательные из которых:

  • Extension-функции или функции-расширения класса — делают код «чище», а в сочетании с автодополнением в IDE ускоряют разработку;
  • Data-классы хранят данные в лаконичном виде;
  • Лямбда-выражения и inline-функции — нужны для использования функций высшего порядка без потери производительности;
  • Object-классы позволяют с лёгкостью реализовать полезный паттерн проектирования Singleton;
  • Inline-функции с параметрами reified типа  позволяют во многих случаях избавиться от рефлексии, которая может влиять на производительность (на старых версиях компиляторов).

Особенности миграции

Есть некоторые особенности, которые стоит учитывать при переходе.

Во-первых, в Kotlin нет привычных методов с ключевым словом static, для этого используется «companion object» в теле класса либо package level-функции. Аннотация @JvmStatic необходима тогда, когда мы хотим вызвать «companion object» — методы из Java таким же образом, каким бы вызывали любой другой static-метод в Java.

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

В-третьих, в Kotlin существуют неизменяемые immutable-коллекции, которые более безопасно использовать при многопоточности, поэтому вы, вероятно, захотите переписать часть кода на них, а лучше вообще на Coroutines. При этом работать с коллекциями удобно в функциональном стиле.

Специальной подготовки непосредственно данных в БД не требуется. Если вы заменяете обычные Java-объекты на Data-классы, то необходимо проверить, что логика переопределенных вами ранее методов toString(), equlas() и hashCode() соответствует той, что по умолчанию будет сгенерирована в этих методах в Kotlin.

Необходимые шаги по переходу

  • Выделите основные участки кода, которые в первую очередь необходимо мигрировать. Выберите места, где максимально сократится код или значительно повысится читаемость и безопасность. Лучше начинать не с core-модулей, а с верхних слоев приложения: из-за того что Kotlin проектировался с учетом необходимости взаимодействия с языком Java, а не наоборот, лучше наследоваться от Java-классов, чем в Java наследоваться от Kotlin-классов.
  • Для упрощения перехода используйте встроенные средства конвертации Java-кода в Kotlin-код в IDE
    Intellij Idea или Android Studio, но не забывайте проверять полученный код.
  • Начинайте писать всю новую функциональность только на Kotlin и по возможности дорабатывайте старый код тоже на нём.
  • Постепенно углубляйте миграцию — переписывайте внутренние, абстрактные слои до тех пор, пока Java-кода не останется в проекте.

Возможные проблемы и уязвимости при переходе на Kotlin

Kotlin создавался как стопроцентно совместимый с Java — это значит, что проблемы при переходе будут минимальными.

Самая распространённая проблема связана с nullability, ведь когда мы вызываем Java-код из Kotlin-кода, то используем платформенные типы, которые не дают никакой информации о допустимости null-значений, а компилятор в свою очередь не делает дополнительной проверки на null. Так мы можем вызвать какой-нибудь метод на возвращённом нам объекте и получить на этапе исполнения кода описанную ранее NullPointerException.

Если в исходном проекте вы использовали популярный плагин Lombok для автоматической генерации методов (getters, setters и так далее), то вам придётся полностью от него отказаться, ведь Kotlin и так выполняет большинство функций Lombok, и вместе работать они не смогут. Полная замена Lombok может привести к масштабным изменениям в коде.

Если вы мигрируете проект, реализованный на Spring Boot, необходимо учитывать, что классы в Kotlin по умолчанию «закрыты» для наследования. Если не «открыть» классы с аннотациями типа @Configuration и @Service, это приведёт к ошибкам при запуске.

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

Пример реального кейса

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

Система сейчас успешно работает в продуктиве — за всё время развития и поддержки доля ошибок, связанных с Kotlin или взаимодействием Java и Kotlin, ничтожно мала. По состоянию на 2020 год все ключевые модули были переписаны, что составляло 60–70% от общего кода. Стоит также отметить, что переход на Kotlin происходил в начале развития этого языка программирования, задолго до пика популярности, что не помешало нам успешно использовать его в продуктиве.

Следите за новыми постами
Следите за новыми постами по любимым темам
15К открытий15К показов