Предисловие

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

Вызов Java-кода в Котлине

Одна из замечательных особенностей Kotlin заключается в том, что вы можете использовать любой код, написанный и скомпилированный на Java, внутри Kotlin почти так же, как на Java. Kotlin был разработан с учетом совместимости с Java, чтобы облегчить разработчикам экспериментирование с Kotlin и интеграцию его в свои текущие программы на Java, и, честно говоря, JetBrains проделала фантастическую работу для достижения этой цели. Это также одна из функций, которые резко повысили популярность Kotlin, и один из его основных аргументов в пользу продажи, а также в центре внимания этой статьи. Итак, давайте начнем здесь!

Вот пример простого (и небезопасного!!) представления Customer в Java:

Вот как вы можете получить к нему доступ в Котлине

Как вы видите, Kotlin уже мало чем отличается от Java! Прежде чем мы продолжим, нам нужно выяснить, как получить доступ к Kotlin из Java. Иначе какой смысл смешивать языки? Как нам вернуть customer из Kotlin обратно в Java? Ну, вокруг customer нет класса, поэтому вы просто относитесь к нему так, как будто он уже находится в том же пространстве имен? Не совсем! Одна важная вещь в доступе к Kotlin из Java заключается в том, что, хотя вы не видите никакого класса-оболочки в этом файле Kotlin, как в каждом java-файле, он все еще существует по причинам совместимости с Java. Чтобы получить к нему доступ, вы должны перейти к нему, сделать первую букву заглавной и поставить после нее Kt.

В качестве послесловия вы МОЖЕТЕ обернуть класс вокруг customer, и вы сможете использовать это имя класса вместо FileKt, но это не обязательно. Организовать материал в Kotlin немного проще и с меньшими отступами благодаря возможности писать большую часть материала на верхнем уровне файла!

Привет мир

Хорошо, теперь мы знаем основы доступа к Java из Kotlin и наоборот. Теперь, чтобы НА САМОМ ДЕЛЕ начать наше путешествие в чужое царство Котлина, мы должны выполнить древний ритуал, передаваемый веками, я имею в виду десятилетиями от программиста к программисту. Первый привет, мир!

Вот и все! Вот краткое объяснение того, что здесь происходит.

fun — это ключевое слово Kotlin для определения функции. В Java такого эквивалента нет, так как вы определяете функцию по типу возвращаемого значения и его модификаторам.

main — это имя функции для точки входа в программу Kotlin, точно так же, как public static void main в Java.

args: Array<String> этот Kotlin эквивалентен String[] в Java, но тип находится в странном месте. Большинство современных языков выбрали постфиксный тип для удобочитаемости, и к этому может потребоваться некоторое время, чтобы привыкнуть, но будьте спокойны, зная, что вам не нужно явно вводить все!

: Unit это следует тому же соглашению, что и переменные, аргументы и тому подобное. Эта часть анатомии функции — просто тип возвращаемого значения для функции, а Unit — это версия Kotlin для void из Java.

println("Hello world!") это должно быть понятно, но на всякий случай: println в Kotlin эквивалентно System.out.println в Java. Он короче и работает так же.

Церемония сокращения

Что такое церемония? Что ж, есть некоторые вещи, которые вы считаете само собой разумеющимися, без которых вы, возможно, не можете жить. Как аргумент args в типах public static void main,return и фигурных скобках вокруг функций. Вы правильно прочитали, эти вещи НЕ являются обязательными в Котлине!

Нам действительно нужно args? Я пишу программу, которая не использует args, так что… давайте просто забросим ее.

Что-то здесь не так… Ну, по крайней мере, для меня. Еще одна приятная особенность Kotlin заключается в том, что вам не нужно указывать Unit в качестве типа возвращаемого значения, если вы не планируете ничего возвращать! Избавимся и от этого.

Теперь чисто! Но... могло быть и почище. Мы используем только одно выражение внутри этой функции. Было бы здорово, если бы мы могли сделать его однострочным, но без фигурных скобок? да. Да, это было бы. К счастью, у кого-то (или у кого-то из команды) в JetBrains тоже была такая мысль!

Теперь это Hello World, если я когда-либо видел его. Но откуда он знает, что main должно вернуть Unit? Одна из замечательных особенностей постфиксных типов заключается в том, что они значительно упрощают как человеку (когда он привыкнет к постфиксным типам), так и компилятору вывод типа без подгонки. Компилятор Kotlin сделает вывод, что тип возвращаемого значения функции — это тип выражения, а тип println — это Unit, так что это соответствует разъему USB 2 в порту USB после того, как вы перевернули его пару раз!

Функция, позволяющая явно не указывать тип, называется «Вывод типа». Здесь тип выводится как результирующий тип выражения, присваиваемого члену. Очень лаконичное название! Вывод типа - это то, что позволило val customer = JCustomer("Bob", "Bobson", 3) быть правильно введенным как JCustomer и проверено путем явного ввода его как такового в Java и без проблем с его запуском.

Одна вещь, которую вы, возможно, заметили ранее, и которую вы, вероятно, не пропустите, это отсутствие ключевого слова new. Я знаю, что нет. При создании экземпляра класса вам просто не нужно ключевое слово new. Вот и все. Имейте в виду, что вам НЕОБХОДИМО использовать ключевое слово new при создании экземпляра класса Kotlin из Java.

Еще одна замечательная часть унаследованных практик, которые теперь отброшены в Kotlin: обязательный конструктор ВНУТРИ класса. Теперь вы можете просто иметь конструктор сразу после имени класса Kotlin. Давайте переведем JCustomer на Котлин как KCustomer.

Вау, это НАМНОГО короче (на 20 строк короче, если игнорировать пробелы), но работает точно так же, за исключением типа KCustomer, а не JCustomer. МОЖНО БЫТЬ КОРОЧЕ!

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

Но что с var и val? Это очень просто! Меньше церемоний! В Kotlin var — это то же самое, что и обычная переменная. Его можно изменить. val — это то же самое, что и переменная final в Java, ее ссылка неизменяема.

Заметьте, я не говорил, что само значение не является неизменным, только ссылка! val всегда будет указывать на один и тот же объект, но НЕ гарантирует неизменность самого объекта. Нет больше final (но да, больше final, больше информации в следующей статье)

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

Больше никаких звонков customer.setName("John"); ! Здесь важно отметить, что компилятор Kotlin ДЕЙСТВИТЕЛЬНО генерирует геттеры и сеттеры для своих свойств для использования Java, и он не нарушает никаких правил конфиденциальности, напрямую обращаясь к полям private. Он по-прежнему вызывает функцию получения/установки! Если компилятор может видеть только геттер, вы не можете использовать этот синтаксис доступа к свойству, чтобы установить новое значение для функции. Так что даже не пытайтесь! Вы получите сообщение об ошибке, похожее на это: customer.customerId = 12345 // val cannot be reassigned

Итак, как вы должны писать собственные геттеры и сеттеры? Как вы должны убедиться, что только ОДИН клиент всегда имеет имя «Боб»? Не волнуйтесь, у Kotlin есть синтаксис для этого!

Особое правило пользовательского геттера Kotlin заключается в том, что ему не нужен указанный тип. Он (конечно) выводит возвращаемый тип из предполагаемого типа свойства. На первый взгляд кажется, что это на самом деле не имеет никаких преимуществ перед геттерами и сеттерами в стиле Java! Это замена шаблона на шаблон! Преимущество на самом деле ЕСТЬ, но оно скрыто за другой особенностью, о которой будет написано в следующей статье.

Говоря о шаблоне… Давайте проигнорируем последнее KCustomer как угасающее воспоминание о примере и двинемся дальше!

Рефакторинг вашего шаблона Java!

Подождите, что такое шаблон? Это код, который вы пишете снова и снова, и который делает одно и то же каждый раз, когда вы его пишете. Нет необходимости писать одно и то же снова и снова, и снова, и снова, и снова, и… подождите, я делаю это прямо сейчас! Первый пример KCustomer был хорошим примером сокращения шаблонов! Но могло быть лучше и практичнее. Что, если бы нам захотелось немного более функционального JCustomer, которое дало бы нам собственное строковое представление с использованием toString, пользовательской функции hashCode и пользовательской функции equals? Ну, это много работы, чтобы сделать вручную! Но IDE может сделать это за вас 😎

Мы превратили нечто и без того огромное во что-то еще более огромное и еще более сложное в обслуживании! Всегда есть библиотека lombok, чтобы помочь с этим.

Но мы здесь не для того, чтобы говорить о ломбоке, не так ли? Вот как это будет выглядеть в Котлине

Все, что вам нужно сделать, это префикс class с data, а компилятор позаботится обо всем остальном! Он автоматически генерирует для вас hashCode, toString и equals. Какое замечательное ключевое слово.

Вот и все для первой части Hopping Islands от Котлина до Явы! Я надеюсь, что вы узнали кое-что о Kotlin и задержитесь, чтобы увидеть следующие статьи.