Сравнение Kotlin и Java при написания backend-приложений
Всем привет, меня зовут Вячеслав Аксёнов. В этой статье я расскажу, как пересел на Kotlin после Java 8/11 и в чём его преимущества.
18К открытий19К показов
Я разработчик больших и маленьких бэкенд систем в крупных компаниях. Приходилось писать как отдельные сервисы, которые общаются с другими бэкенд сервисами разного уровня глубины, так и сервисы, работающие в связке с фронтом. Раньше для написания кода я использовал Java + Spring.
А после поменял проект и столкнулся с Kotlin именно в бэкенде. И хочу поделиться преимуществами Kotlin отличиями Kotlin от Java в абсолютно одинаковых задачах.
Забегая вперёд скажу, что колоссальной разницы, из-за которой нужно срочно переписывать всё на Kotlin, нет. Но есть огромное количество фич, которые делают разработку быстрее, проще и безопаснее. На текущем проекте весь новый функционал мы с командой пишем на Kotlin, параллельно переписывая старые куски Java-кода n-летней давности. На Kotlin эти куски получаются гораздо более читабельными и короткими.
Простота интеграции в уже существующий проект, написанный на Java
Если вы только присматриваетесь к Kotlin для бэкенда, то учитывайте что в окружении, которое запускает ваш проект на Java 8, можно без танцев с бубном запустить скомпилированный проект на Kotlin. Да, на той же jvm, на том же окружении и с минимумом усилий.
Для меня было открытием, что даже в рамках одного приложения могут быть классы на Java и Kotlin. Вся магия происходит на этапе компиляции. В зависимости от настроек, можно указать что собирать первым: Kotlin-классы или Java-классы.
Сейчас доступна компиляция Kotlin-исходников в байткод от Java LTS – 8, 11 и (пока экспериментально) 16.
Инициализация и логика работы с DTO классами
Пример избитый, но максимально наглядный.
И теперь то же самое на Java:
Мне кажется, здесь даже комментарии излишни.
Указатели data class в Kotlin по-умолчанию подразумевают наличие getter, setter (для var полей), equals, hashcode, toString для всех полей. При желании можно переопределить каждый из этих методов по своему, но требуется это крайне редко.
Null safety
В Kotlin требуется явно указывать, может ли тот или иной метод вернуть null или нет. Таким образом можно считать, что все данные уже обернуты в аналог Optional. И NullPointerException будет вами встречаться настолько редко, что вы успеете по нему соскучиться.
Выделение основного конструктора
Суть в чём: есть основной (Primary) конструктор и вспомогательные (Secondary). Вспомогательные обязаны вызывать основной как конструктор родительского класса.
Явное объявление изменяемых и неизменяемых полей
Следующее преимущество: в Kotlin получаются довольно простые и элегантные конструкции. Если требуется, чтобы поле dto можно было менять, то для его объявления используется var. Тогда будет создан метод setter и поле не будет final.
А если нужно сделать поле иммутабельным, для объявления следует использовать val. Смотрится очень красиво и просто. Плюс не нужно следить за вспомогательными методами.
Пример: поля цвета и роста можно изменить после создания, а имя — только при инициализации объекта:
Immutable коллекции по умолчанию.
То, что появилось в Java несколько позже, уже давно было в Kotlin — создание коллекций сразу иммутабельными.
Любые изменения с этими коллекциями будут создавать новую иммутабельную коллекцию после преобразования:
Но изменить какой-то элемент отдельно не получится. Для классических мутабельных коллекций используется явно изменяемые аналоги:
Работа со сложными классами методами примитивов
Преимущество Kotlin, которому не перестаю радоваться — возможность использовать операторы для базовых операций к сложным классам. Если нужно сложить BigDecimal числа — берёшь и пишешь их через плюс. Не нужно явно вызывать метод у первого слагаемого.
То же самое с массивами: хочешь удалить элемент из мутабельного массива – пишешь массив минус этот элемент. И если элемент присутствует, то он удаляется
В Java нужно вызывать специальный метод:
Аналогичные приёмы работают и с более сложными классами, например с коллекциями:
Возможно писать однострочные методы действительно в одну строку
Если метод простой и состоит из одной операции или из цепочки операций, записанных в одну строчку, то не обязательно писать фигурные скобки и return. Прямо пишешь:
Вместо Java варианта:
Контекстные функции.
Интересные движения в сторону функционального программирования в духе выделения контекста: лямбды можно вертеть как хочешь.
Есть функции let, apply, also, with, run. Из-за их обилия вначале возникает вопрос: что подходит для конкретного кейса. Но когда привыкаешь, становится непонятно как раньше жил без них.
Простой пример: взять результат и как-то его обработать:
Либо инициализировать объект и дополнительно проинициализировать его var поля:
Кто-то может сказать, что это сахар сахарный и будет прав. Но по себе скажу: если большое количество шаблонных вещей входит в язык, и о них не нужно постоянно думать — процесс разработки становится проще, количество ошибок — меньше. Но нужно чаще думать про код стайл, потому что без него навертеть можно многое ?
Сейчас я по-прежнему продолжаю писать и видеть код на Java, но в 99% случаев это связано с образовательными программами, в которых принимаю участие: профессия Java разработчика на Hexlet и различные вебинары для онлайн школ и курсов. Так что я постоянно сравниваю два языка и радуюсь, что рабочие проекты пишу на Kotlin.
Советую попробовать каждому — как минимум на pet-проекте чтобы понять подходят вам парадигмы Kotlin или нет.
18К открытий19К показов