Автор оригинала: Jussi Hallila.
Знакомство с Котлином Что такое Котлин? Что это дает, чего еще нет в JVM? Синтаксис Котлина
Знакомство с Котлином
Котлин – это новое детище любви в мире разработчиков JVM.
Google продвигал Kotlin как первоклассный язык на своей платформе Android на базе Java еще в мае . С тех пор весь мир разработчиков задается вопросом: что это за язык? Котлин существует уже несколько лет и работает в производственных системах после выпуска languages 1.0 в феврале 2016 года в течение года или около того. Язык получил много похвал и слов любви от сообщества разработчиков. Это глоток свежего воздуха, хорошее обновление до систем, работающих под управлением более старых версий Java, и все еще каким-то образом старая собака на знакомом игровом поле.
В следующих трех уроках мы познакомим вас с языком Котлин, начиная с основ и проходя через более сложные его аспекты. В этом посте мы рассмотрим синтаксис и другие основные строительные блоки языка. В Введение в Kotlin Часть 2 мы коснемся переменных, функций, классов, интерфейсов и объектов . Наконец, в Части 3 мы рассмотрим несколько примеров потока управления в Котлине.
Что такое Котлин? Что это дает, чего еще нет в JVM?
Котлин против Ява
Есть несколько подходов, которые мы можем использовать при внедрении Kotlin. Мы можем обсудить это через Java, язык, на котором должен основываться Kotlin, из-за его среды выполнения JVM, или мы можем сделать это через Scala, язык, на который сильно влияет Kotlin. Нет никаких сомнений в том, что Котлин лучше, чем Java. Это гораздо безопаснее и лаконичнее. Он предоставляет вам множество дополнений к вашему стандартному языку Java и улучшает некоторые элементы, которые не нравятся разработчикам Java. Дополнения включают такие вещи, как нулевая безопасность, функции расширения, классы данных, объекты, функции первого класса, а также обширные и выразительные лямбды. Kotlin также улучшает вывод типов и систему типов Java и делает огромные скачки вперед с коллекциями.
Котлин против Скала
Возможно, лучше сравнить Котлин со Скалой. Это сравнение может немного напугать некоторых из вас, потому что Scala имеет репутацию одновременно интригующей и пугающей. Он в значительной степени знакомит вас с парадигмой функционального программирования, все еще смешивая ее со знакомой объектной ориентацией (следовательно, в очень многих случаях создает мешанину передовых методов из обеих парадигм), привносит некоторые новые инструменты сборки и время от времени дает вашему внутреннему потоку неприятный перерыв из-за длительного времени компиляции.
Я пришел с хорошими и плохими новостями. Давайте начнем с плохих новостей: Плохая новость заключается в том, что Котлин похож на Scala, он следует по тому же пути, что и Scala делает
Хорошая новость: к счастью, он лишь немного похож на Scala во всех аспектах.
Котлин и Парадигма Функционального Программирования
Парадигма функционального программирования также является важной частью Kotlin. К счастью, это не относится к типам высшего рода, монадическим продолжениям или концепциям теории продвинутых типов, которые заставляют вас искать Бартош Милевский и его блестящая книга по теории категорий . Kotlin представляет для вас простые в использовании функции управления коллекциями и функциональные конвейеры. Вы получите свои карты, фильтры и сгибы, которых в большинстве случаев достаточно, чтобы перейти на путь функционального программирования.
Разработчики Java, которым посчастливилось перейти на Java 8 (обнимаю и целую вас, разработчики Android и/или предприятия), будут знакомы с этими основами и будут чувствовать себя как дома, когда они перейдут в Kotlin. Они также найдут лаконичность и безопасность лучшей системы типов, которая вызовет их первое увлечение языком. Это просто так красиво и легко соединить эти функции вместе и построить чистый трубопровод. И когда вы вернетесь к нему через несколько недель, вы все равно почувствуете, что в какой-то степени можете его понять. Все вокруг улыбаются.
Процессы построения
При разработке в Kotlin ваши процессы сборки будут более или менее такими же, как в вашем старом приложении Java. Поскольку вы уже знакомы с ними, нет необходимости изучать что-то новое. Процесс сборки и инструменты сборки, представленные Kotlin, можно описать двумя словами: Плагин Gradle/Maven. Вы можете ввести язык в свою кодовую базу, добавив плагин Kotlin в сценарий сборки Gradle/Maven и убедившись, что он указывает на правильную папку, которая определяет ваши файлы Kotlin.Добавление Kotlin в вашу кодовую базу —это всего лишь быстрое нажатие Ctrl-C + Ctrl-V. Более подробную информацию о том, как это сделать, можно найти в официальной документации Kotlin: Мавен / Грейдл . Это буквально так, это просто чудесным образом сработает , как устройства Apple [1] .
О, и Котлин также легко устанавливается на место поверх вашего инструмента. Котлин создан JetBrains, теми же людьми, которые создали IntelliJ, лучшая ИДЕЯ, которую когда-либо видел мир , поэтому инструменты лучше использовать на месте. И, о боже, так оно и есть. В настоящее время IntelliJ поставляется в комплекте с плагином Kotlin, который дает вам все хорошее, что вы ожидаете увидеть, выплевывая Java-код. Вы получите блестящий intellisense, встроенную интеграцию для построения процессов и умные предложения о том, как сделать ваш код лучше — все это упаковано в красивый и функциональный пакет.
Естественно, у вас также будут плагины для вашей любимой IDE, если IntelliJ не ваша чашка чая. Эти инструменты делают Kotlin легким для разработки. Это и системы безопасности, умело встроенные в язык, гарантируют, что вероятность покраснеть из-за плохого качества кода меньше, когда вы показываете свою кодовую базу 4-летней давности своему коллеге/начальнику/сообществу ОС/супругу.
Как язык, Kotlin очень близок к Java. Это дает пользователям несколько приятных маленьких преимуществ. Например, совместимость между Java и Kotlin великолепна —вы можете переходить от одного файла к другому и менять язык с нулевыми барьерами. Введение Kotlin в вашу кодовую базу может выполняться постепенно, потому что ваш старый код Java может жить бок о бок с вашим новым кодом Kotlin. Еще одно преимущество, которое мы получаем, не отклоняясь слишком далеко от Java, – это весь процесс компиляции. Компиляция кода Kotlin в байт-код JVM не занимает так много времени. Ребята из Keepsafe провели небольшой приятный тест , чтобы сравнить свою кодовую базу Kotlin с Java. Их результаты показывают, что время компиляции Kotlin на самом деле быстрее при инкрементных сборках, чем время компиляции Java. Невероятно быстро! [2] Совсем не грустно.
Синтаксис Котлина
Один великий человек однажды сказал разговоры дешевы, покажи мне код . Так что давайте немного окунемся в Котлин.
Чтобы сделать всех богов блога счастливыми, мы начнем с простого приветственного мира. В Котлине это выглядит примерно так:
print("Hello World")
Теперь, когда мы с этим разобрались, мы можем провести некоторый псевдо – анализ. Синтаксис кажется знакомым, поэтому давайте предположим, что скобки означают вызов функции. В конце строки нет точки с запятой, что является аккуратным. О, эта печатная
штука должна что – то печатать. Это почти все, что мы можем извлечь из этой единственной строки.
Хорошо, теперь, когда боги блога счастливы, мы можем двигаться вперед.
Переменные Котлина
Объявление переменной в Kotlin может происходить несколькими различными способами. У нас есть ключевые слова вэл
и различные
. Эти два вида похожи, но имеют одно существенное отличие:
Значения , объявленные с помощью val
, являются неизменяемыми (ну, только для чтения), и вы можете присвоить им значение только один раз. Это время наступает, когда вы объявляете и создаете значение или когда вы присваиваете значение уже объявленному, но не созданному. Переменные с var
изменяемы и могут быть переназначены. Предпочтительный способ – использовать val
s везде, где это возможно. Таким образом, с кодовой базой будет легче работать и рассуждать.
val hello: String = "hello" val world: String world = "world" var helloWorld: String = "Hello" helloWorld = "Hello World"
Обратите внимание, как тип переменной определяется после переменной, разделенной двоеточием. За этим стоит веская причина. Теперь компилятор может решить, следует ли выводить тип, что означает, что у Kotlin более мощный вывод типов, чем у Java. На самом деле вы можете полностью исключить объявление типа, и компилятор поймет, что вы имеете в виду.
val hell0 = "hi" val w0rld = "earth"
Это работает только тогда, когда известно значение и, следовательно, тип значения.
Забавы, Забавы, Забавы
Как насчет функций? Всегда интересно писать функции в Котлине. Поскольку мы используем ключевое слово fun
для их объявления, это обязательно будет весело! (ха-ха. )
// No return type. (can also be --> fun sayIt (a: String): Unit) fun sayIt (a: String) { println(a) } // With return type fun returnIt (returnable: String): String { return returnable } // As a `single-expression function with inferred return type and automatic return fun returnIt2 (turntable: String) = turntable
Объявление типа здесь следует тому же шаблону —оно идет последним. В нашей первой, побочной функции мы ничего не возвращаем, поэтому мы можем опустить тип, который в данном случае был бы Unit
. Во второй функции мы определили, что мы должны возвращать Строка
и мы сделали это, используя надежный возврат
ключевое слово. Последнее немного более загадочно. Здесь нет фигурных скобок, только знак равенства. Это означает, что наше веселье
является выражением и он вернется автоматически.
Когда вы только начинаете создавать функциональные конвейеры, большинство людей склоняются к этим выражениям. Это способ заставить ваши функции выполнять одну вещь, и делать это хорошо . Как вы можете видеть, возвращаемый тип в выражениях является необязательным и может быть опущен или оставлен на месте, что бы вас ни радовало (эмпирическое правило: в длинных выражениях введите его, в более коротких его можно опустить).
Котлин также вводит понятие необязательных и именованных параметров функций. Это особенно полезно, если ваши функции вырастают в монстра из множества одинаковых типов и множества разных параметров.
fun optFun(isItFun: Boolean = true, whyIsItFun: String = "Because") = if (isItFun) whyIsItFun else "It's not fun" println(optFun()) // Because println(optFun(false)) // It's not fun println(optFun(whyIsItFun = "It's Summer!")) // It's Summer!
В этом фрагменте мы определили параметры нашей функции со значениями по умолчанию. Когда это будет сделано, мы можем просто вызвать функцию с нулем, одним или обоими ее аргументами. Если аргументы опущены, то вступают в силу значения по умолчанию. Как вы можете видеть, мы также можем вызывать функцию, называя аргументы. Это дает нам больше понимания того, что мы называем, с каким значением и возможностью ориентироваться на отдельный необязательный аргумент. Обратите внимание, что необязательные аргументы работают как для конструкторов классов, так и для функций.
Есть также аккуратные мелочи, такие как функции расширения и функции инфикса, а также перегрузка операторов в языке. Это интересные аспекты Kotlin, которые делают написание языка более приятным. Эти функции дают нам, помешанным на контроле, больше возможностей для написания красивого кода и естественно читаемые структуры . Это другая тема для другой статьи, хотя .
Классы, интерфейсы и объекты
Как и Java, в Kotlin есть классы и интерфейсы. В отличие от Java, экземпляры Kotlin могут находиться в одном файле и не нуждаются в своих собственных. Это решение, принятое командой Kotlin, сделало организацию кода более приятной, а язык-более лаконичным. Давайте сначала займемся занятиями.
Занятия
class SimpleClass // Also --> class constructor SimpleClassWithConstructor(val chop: String) class SimpleClassWithConstructor(val chop: String)
В Котлине существует несколько способов создания классов. Первый пример во фрагменте показывает нам несколько вещей: Соглашение об именовании начинается с заглавной буквы Здесь нет фигурных скобок В этом примере модификатор видимости отсутствует Мы по-прежнему используем ключевое слово class
.
В Kotlin мы создаем экземпляры этих классов почти так же, как и в Java, за исключением того, что мы опускаем new
ключевое слово. Подобный этому:
val simpleClass = SimpleClass()
Теперь мы создали экземпляр класса, с которым ничего не можем поделать. Хорошая работа!
Второй пример похож, но в нем есть конструктор. Обратите внимание, как конструктор помещен в ту же строку, что и класс (вы можете оставить конструктор
ключевое слово в большинстве случаев его нужно добавлять только в том случае, если в классе есть аннотации или модификаторы видимости), еще один способ сделать код Kotlin более лаконичным. Когда мы создаем экземпляр этого класса, нам нужно передать значение для chop
.
val lamb = SimpleClassWithConstructor("Hello")
Свойства в Котлине по умолчанию являются общедоступными, поэтому есть простой способ получить доступ к этому свойству:
println(lamb.chop)
Этот класс не обладает никакой функциональностью; это просто сосуд для наших данных. Мы можем добавить туда некоторую функциональность, определив fun
s внутри класса. В этом случае нам нужно вставить эти красивые фигурные скобки в нашу декларацию.
class SimpleClassWithConstructor(val chop: String) { fun sayItMate(): String = chop + ", mate" }
Вы можете более или менее сбросить те же вещи, что и в Java, в класс здесь. Мы можем добавить свойства , другие классы , дополнительные конструкторы или блоки инициализации в и мы можем назначить модификаторы видимости для всех из них по отдельности.
Блоки Init
в Kotlin можно использовать для выполнения действий, которые вы обычно выполняете с помощью своего конструктора Java. Если вы хотите создать класс внутри класса, вы можете пометить его ключевым словом inner
, чтобы иметь доступ к членам окружающего класса.
class Kenny(val celly: String) { lateinit var wheel: CanadianPerson val friend: String init { friend = "buddy" } fun initializeWheel (wheeler: String) { wheel = CanadianPerson(wheeler) } inner class CanadianPerson(val snipe: String) // The dollar sign makes use of string interpolation and replaces the $-prefixed property name with toString implementation defined in that property. fun sayItCanadianWay(): String = "${wheel.snipe} $celly, $friend" } val d = Kenny("friend") d.initializeWheel("I'm not") print(d.sayItCanadianWay()) // I'm not your friend, buddy
Здесь у нас есть несколько движущихся частей. Используя ключевое слово lateinit
, мы можем сообщить компилятору, что это свойство не равно нулю, даже если мы не инициализируем его сразу. Это полезно в тех случаях, когда мы не инициализируем наши свойства в конструкторе, а используем, например, платформу внедрения зависимостей для присвоения им значений. Обратите внимание, что наше свойство lateinit
изменяемо — это обязательно.
в нем
эквивалентен блоку конструктора в классах Java. Там мы можем выполнять необходимые действия при создании экземпляра класса. В этом случае мы присваиваем строку нашему свойству, что также может быть сделано в качестве объединенного назначения.
Далее у нас есть функция, которая, наконец, присваивает значение нашему свойству lateinit
, создавая экземпляр внутреннего класса Канадский человек
. Этот внутренний класс снова является просто сосудом для наших данных.
Наконец, у нас будет функция, которую мы вызовем: эта функция вернет строку, которую она проанализировала вместе с помощью интерполяции строк . Символ знака доллара может использоваться в строках для замены имени свойства с префиксом $на его реализацию toString, определенную в этом свойстве.
При добавлении дополнительных конструкторов в класс нам нужно заставить их вызывать исходный конструктор.
class DoubleTrouble(val str: String){ constructor(lamb: SimpleClassWithConstructor): this(lamb.chop) }
Классы данных
Теперь, когда мы рассмотрели классы с некоторой функциональностью в них, мы можем взглянуть на некоторые более простые классы, которые не делают ничего, кроме хранения наших данных.
Для такого рода объектов передачи данных Котлин ввел ключевое слово для их определения: класс данных
. Он отличается от стандартных классов несколькими способами. класс данных
автоматически генерирует равен
, хэш-код
, toString
и копировать
функции. Первые три из них знакомы разработчикам Java, четвертый-приятное дополнение, которое помогает нам создавать аналогичные объекты из нашего класса данных только для чтения. Для этого можно использовать функцию копировать
.
data class DataClass(val str: String, val num: Int) val daata = DataClass("Hello", 3) val peeta = daata.copy(str = "Goodbye")
В этом случае наш объект пита содержит число
3 и str
“До свидания”. Ловко!
Мы также бесплатно получаем компонент
функции в класс данных. Эти функции компонентов являются способом доступа к данным в нашем классе данных посредством деструктуризации. Это помогает извлекать отдельные свойства из наших классов данных с помощью краткого вызова в одну строку.
val (str, num) = peeta
С помощью этого трюка у нас есть переменные ул
и номер
и их значения – “До свидания” и 3 соответственно. Обратите внимание, что порядок деструктурирования переменных зависит от порядка свойств в нашем классе данных; имена на самом деле не имеют никакого значения.
Двумя другими структурами верхнего уровня являются интерфейсы
и объекты
.
Интерфейсы
Интерфейсы в Kotlin не сильно отличаются от мира Java. Одна приятная вещь заключается в том, что вы также можете иметь абстрактные свойства в своих интерфейсах. Эти свойства должны быть инициализированы в классе реализации, чтобы выполнить контракт интерфейса.
interface Sayer { val value: String fun sayIt(): String } class SayerClass: Sayer{ override val value: String = "Hello" override fun sayIt(): String = "$value, world" } println(SayerClass().sayIt()) // Hello, world
Как вы можете видеть, это очень похоже на Java. Как и Java 8, Kotlin также может иметь реализации по умолчанию в интерфейсах. Мы можем добиться того же, что показано выше, с помощью этого интерфейса.
interface Sayer { val value: String fun sayIt(): String { return "$value, world" } }
Используя это, нам не нужно переопределять функцию в нашем классе реализации. Обратите внимание, что переопределяет
ключевое слово является обязательным в Kotlin. Это помогает нам, пользователям чужого кода, оценить тот факт, что контракт функции/свойства исходит откуда – то извне нашей реализации. Хороший способ уклониться от ответственности XD
Объекты
object SingletonClass{ fun sayIt(): String = "Hello world" } class CompaniedClass(val str: String){ companion object Printer{ fun sayIt(): String = "Hello world" } }
Что же это тогда такое? В Kotlin вы можете создавать синглеты с ключевым словом object
. Это хороший шаблон для хранения, например, более широкого контекста вашего приложения в одном месте. Вы могли бы создать экземпляр группы сложных классов и хранить эти объекты в месте, где к ним можно легко получить доступ. Вы можете получить доступ к функциям в объектах, напрямую вызывая их имена.
SingletonClass.sayIt() // Hello world
Объект-компаньон-это немного другой зверь. Он определен в классе, который по-прежнему является одноэлементным, и к нему можно получить доступ, используя имя класса-оболочки .
CompaniedClass.sayIt() // Hello world
Это краткое введение в занятия в Котлине. Есть еще кое-что, что мы можем обсудить на занятиях, но чтобы этот пост был коротким, мы отложим модификаторы видимости
, запечатанные классы
, дженерики
и другие для будущей должности.
Поток управления (если, когда и для)
Теперь, когда у нас есть переменные, функции и классы, прибитые украшенным пушистым молотком, мы можем кратко взглянуть на некоторые структуры управления в Котлине.
Если
Операторы If в Kotlin работают более или менее так же, как и в Java. Есть одно большое и важное отличие, на которое стоит обратить внимание:
val three = 4 if (three != 3) { println("Liar!") } else{ println("Good job") }
Это выглядит точно так же, как и в Java. Сюрприз! Так и есть! Следующий немного более загадочный.
val three = 4 val goodOrNot = if(three != 3) { "Liar!" } else{ "Good job" } println(goodOrNot) // Liar!
Если операторы в Котлине на самом деле являются выражениями. Они возвращают последнее значение в своем блоке, поэтому в данном случае в нем записано строковое значение. Это влечет за собой несколько предостережений. Потому что вы можете использовать эти if
s так же, как троичные (доверенные val > 4 ? " Что?": "Новей!?"
) операторы, ребята из Котлина, на самом деле полностью опустили троичный. Поэтому, если вы пытаетесь найти этот вопросительный знак на клавиатуре, не делайте этого. В Котлине этот символ имеет совершенно другое значение. Мы коснемся вопросительных знаков в следующем посте.
Когда
Если лучший друг предложений случай переключения
имеет ту же судьбу, что и тернарный оператор. Он был заменен на когда
заявление в Котлине.
when (three) { 3 -> print("three is three") 2 -> print("three is two?!?") else -> print("I don't know what's going on anymore") }
Как вы можете видеть, предложение else
заменило регистр по умолчанию
, а стрелка заменила символ :
. Ключевое слово break
больше не нужно, так как когда
выражение остановится, когда оно попадет в первый истинный случай. Мы также можем заключить каждый из этих случаев в волнистые скобки — в этих случаях, как и в выражении if
, будет возвращен последний оператор блока. Есть несколько интересных аспектов этих когда
выражений. Они могут быть оценены с использованием любых выражений, многие случаи могут быть объединены вместе, а для числовых значений вы можете использовать диапазоны для определения предложения.
when (three) { 3 -> print("three is three") 1,2 -> print("three is two or one?!?") in 4..10 -> print("What? Three can't be between 4 and 10!") else -> print("I don't know what's going on anymore") }
Мы также можем полностью опустить скобки и переданное значение из нашего когда
и очень сильно прищуриться. Если мы посмотрим под правильным углом, мы сможем сделать наши выражения “когда” похожими если
s и впоследствии полностью заменить их.
val three = 4 val goodOrNot = when { three != 3 -> "Liar!" else -> "Good job" } println(goodOrNot) // Liar!
Для
Подожди! Вы, должно быть, думаете. “Что это за двойная точка там, которую мы полностью пропустили?”. Это выражение диапазона в Kotlin, это один из строительных блоков для для
операторов в языке. Теперь, через некоторое время (не цикл [хе-хе]), циклы for не будут играть большой роли в языке, поскольку функции расширения коллекции во многих случаях делают простые циклы бесполезными. Давайте все равно пробежимся по ним, чтобы завершить эту статью.
for (i in 1..10) { print(i) } // 12345678910 for (i in 1..10 step 2) { print(i) } // 13579 val lst = listOf(1,2,3) for (i in lst){ print(i) } // 123
Это выглядит достаточно прямолинейно. В первом мы использовали магическое ключевое слово in
, чтобы взять значение из диапазона
, которое мы определили с помощью двойной точки, и присвоили его i
. Следующий цикл добавляет ключевое слово step
, которое указывает, что мы хотим взять все остальные значения из диапазона. Третий цикл примера берет значения из списка (который мы создали с помощью вызова функции список
) и выводит их на печать. Это более или менее для циклов в Котлине.
Это основные строительные блоки для языка Котлин. С их помощью вы можете начать писать и играть с языком. Мы упустили некоторые важные вещи, такие как лямбды, нулевая безопасность и типы. Мы также еще не касались коллекций, так как им нужна своя глава, и лучше затронуть ее после того, как мы рассмотрим лямбды. Надеюсь, к концу этого поста у вас теперь будет представление о Kotlin и его базовом синтаксисе. В следующей статье мы расширим магию и раскроем больше аспектов, которые делают Kotlin таким любимым языком среди разработчиков, нацеленных на JVM.
Не забудьте ознакомиться с другими постами из этой серии. Во введении к части 2 Kotlin я познакомлю вас с безопасностью null , лямбдами, коллекциями и типами, а также с несколькими удобными служебными функциями на языке Kotlin.
В части 3 мы завершим введение функциями расширения, функциями более высокого порядка и функциональным стилем, и, наконец, познакомим вас с обобщениями и делегатами.
Только в унисон с другими устройствами Apple (кроме последнего поколения, которое иногда работает ). На самом деле, давайте скажем, что он работает лучше, чем устройства Apple, потому что это ближе к истине. И Котлин тоже симпатичный, как устройства Apple, да. Предположим, что Kotlin очень похож на устройства Apple и просто работает как все, что сделал Лайнус. Это гораздо лучшая аналогия. с тех пор, как︎
Да, со звездочкой, естественно. И да, да, люди, это не самый быстрый во Вселенной, просто помните, что мы все еще работаем на JVM. Будем надеяться, что ваши URL-адреса зависимостей останутся в Сети. с тех пор, как︎
Оригинал: “https://www.codementor.io/@jussihallila/introduction-to-kotlin-part-1-9mt0ony0g”