Это подборка базового синтаксиса с примерами. В конце каждого раздела вы найдете ссылку на более подробное описание соответствующей темы.
Вы также можете изучить все основы Kotlin в бесплатном курсе Основы Kotlin от JetBrains Academy.
Определение имени пакета и импорт
Имя пакета указывается в начале исходного файла, так же как и в Java.
package my.demo import java.util.* // .
Но в отличие от Java, нет необходимости, чтобы структура пакетов совпадала со структурой папок: исходные файлы могут располагаться в произвольном месте на диске.
Точка входа в программу
В Kotlin точкой входа в программу является функция main .
fun main()
Другая форма main может принимать массив строк String .
fun main(args: Array)
Вывод в стандартный поток
Источник: kotlinlang.ru
Мои любимые примеры функционального программирования в языке Kotlin
Одной из замечательных особенностей Kotlin является то, что он поддерживает функциональное программирование. Давайте посмотрим и обсудим некоторые простые, но выразительные функции, написанные на языке Kotlin.
Kotlin: это что и зачем нужен
Работа с коллекциями
Kotlin поддерживает удобную работу с коллекциями. Есть множество разнообразных функций. Предположим, что мы создаем некоторую систему для университета. Нам нужно найти лучших студентов, которые достойны стипендии. У нас есть следующая модель Student :
class Student( val name: String, val surname: String, val passing: Boolean, val averageGrade: Double )
Теперь мы можем вызвать следующую функцию, чтобы получить список десяти лучших студентов, которые соответствуют всем критериям:
students.filter < it.passing it.averageGrade >4.0 > // 1 .sortedBy < it.averageGrade >// 2 .take(10) // 3 .sortedWith(compareBy(< it.surname >, < it.name >)) // 4
- Оставляем только сдавших экзамен студентов, средний балл которых более 4.0.
- Сортируем их по среднему баллу.
- Оставляем первых десять студентов.
- Сортируем их по алфавиту. Компаратор сначала сравнивает фамилии, и если они равны, то он сравнивает имена.
Что, если вместо порядка по алфавиту нам нужно сохранить изначальный порядок студентов? Мы можем это сделать, используя индексы:
students.filter < it.passing it.averageGrade >4.0 > .withIndex() // 1 .sortedBy < (i, s) ->s.averageGrade > // 2 .take(10) .sortedBy < (i, s) ->i > // 3 .map < (i, s) ->s > // 4
- Привязываем текущий индекс итерации к каждому элементу.
- Сортируем по среднему баллу и оставляем первые десять студентов.
- Снова сортируем, но теперь по индексу.
- Удаляем индексы и оставляем только студентов.
Этот пример наглядно показывает, как проста и интуитивно понятна работа с коллекциями в Kotlin.
Что учить новичку в Android: Java vs Kotlin? Мобильный разработчик [Ru, Android]
Супермножество (булеан)
Если вы изучали алгебру в университете, вы можете вспомнить, что такое супермножество. Для любого множества его супермножеством является множество всех его подмножеств, включая само оригинальное множество и пустое множество. Например, если у нас есть следующий набор:
То его супермножество:
В алгебре такая функция очень полезна. Как нам её реализовать?
Если вы хотите бросить себе вызов, то остановитесь читать прямо сейчас и попытайтесь решить эту проблему самостоятельно.
Давайте начнем наш анализ с простого наблюдения. Если мы возьмем какой-либо элемент множества (например, 1), то в супермножестве будет равное количество множеств с этим элементом (, , , ) и без него (<>, , , ).
Обратите внимание, что второй набор – это супермножество (), а первый – это супермножество () с нашим добавленным элементом (1) к каждому множеству. Таким образом, мы можем вычислить супермножество, взяв первый элемент, вычислив супермножество для всех остальных и вернув сумму результата и результата с добавлением первого элемента к каждому множеству:
fun powerset(set: Set): Set < val first = set.first() val powersetOfRest = powerset(set.drop(1)) return powersetOfRest.map < it + first >+ powersetOfRest >
Но данный метод работать не будет. Проблема заключается в пустом множестве: first вызовет ошибку, когда множество пустое. Здесь на помощь приходит определение супермножества — супермножеством пустого множества является пустое множество: powerset(<>) = >. Вот как выглядит исправленный алгоритм:
fun powerset(set: Set): Set = if (set.isEmpty()) setOf(emptySet()) else < val powersetOfRest = powerset(set.drop(1)) powersetOfRest + powersetOfRest.map < it + set.first() >>
Давайте посмотрим, как это работает. Предположим, нам нужно вычислить powerset(). Алгоритм будет действовать следующим образом:
powerset() = powerset() + powerset().map
powerset() = powerset() + powerset().map
powerset() = powerset(<>) + powerset(<>).map
Но мы можем улучшить нашу функцию ещё больше. Давайте используем функцию let, чтобы сделать обозначения короче и компактнее:
fun powerset(set: Set): Set = if (set.isEmpty()) setOf(emptySet()) else powerset(set.drop(1)) .let
Примеры программ на kotlin
Основные плюсы такого подхода:
- Легко добавить в существующие нативные приложения. Достаточно просто постепенно выделять общий код в отдельную библиотеку.
- Меньший размер приложения. Компиляция кода Kotlin Native добавляет небольшой оверхед, поэтому размер приложения обычно меньше аналогов на Flutter и React Native.
- Большая гибкость. Вы можете использовать любые библиотеки и технологии внутри ваших iOS и Android-приложения, без необходимости написания дополнительного кода.
- Общий код можно использовать не только в мобильных приложениях, но также и в веб-приложениях, и в серверной логике на Kotlin (рис. 2).
Но не стоит забывать и о минусах:
- Высокий порог входа. Необходимы базовые знания разработки под iOS и Android даже для создания простого приложения.
- Небольшое комьюнити. Так как KMM все еще находится в бете, его использует не такое большое число пользователей. Для сравнения: на момент написания статьи вопросов с тегом Flutter в Stackoverflow больше 160 тысяч, а по KMM – чуть больше тысячи.
- Небольшое количество мультиплатформенных библиотек. Несмотря на то что стандартная библиотека языка Kotlin может быть использована в общем коде без ограничений, многие привычные библиотеки языка Kotlin используют платформозависимые вызовы Java-кода и не могут быть использованы напрямую.
- Сложность организации общего кода. KMM не предоставляет никаких готовых решений, как организовать архитектуру приложения, чтобы увеличить процент общего кода и не усложнить процесс разработки.
Команда JetBrains активно работает над развитием комьюнити, а также улучшает плагин для Android Studio, который заметно упрощает создание и поддержку KMM приложения. А последний минус мы рассмотрим подробнее далее и разберем популярный способ организовать код приложения так, чтобы максимально следовать золотому правилу разработки – DRY (don’t repeat yourself).
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека мобильного разработчика»
Архитектура типичного KMM-приложения
Архитектура типичного мультиплатформенного приложения – это монорепозиторий, состоящий из трех модулей: Android-приложение, iOS-приложение и общая библиотека (рис. 3).
Проект с такой структурой можно создать с помощью официального плагина для Android Studio. Шаги по настройке подробно описаны на сайте проекта , поэтому мы не будем углубляться в него подробнее.
Теперь предстоит начать писать общий код. Но как же это сделать? Ведь часто много логики находится непосредственно в UI-компонентах, а что делать с навигацией? Здесь нам на помощь приходит архитектурный паттерн из Flutter, предложенный его создателями компанией Google в 2018.
Этот паттерн называется BLoC (business-logic components) и он предлагает вынести всю бизнес-логику из UI-компонента в специальный компонент – BLoC (рис. 4).
Такие bloc’и тесно связаны с определенным UI-компонентом и его жизненным циклом, они создаются и уничтожаются вместе с ним. Но bloc’и не зависят от его реализации и не содержат никакого UI, а значит, они идеальные кандидаты для помещения в общий код. Библиотеки, позволяющие легко внедрить данный подход, уже созданы и активно поддерживаются комьюнити. Самая популярная из них на GitHub – Decompose , на ней мы и остановимся чуть подробнее.
Давайте разберем пример создания BLoC’а в библиотеке Decompose
В качестве примера рассмотрим простейший счетчик, который умеет показывать текущее значение и который можно увеличивать и уменьшать на единицу.
Опишем бизнес-логику нашего компонента:
- Он хранит состояние – текущее значение счетчика.
- У него есть метод для увеличения значения на один.
- У него есть метод уменьшения значения на один.
Создадим Kotlin-интерфейс с этой логикой в общем модуле:
data class CounterState(val count: Int) interface CounterComponent < val state: Value// (1) fun onIncrease() // (2) fun onDecrease() // (3) >
Это и есть интерфейс нашего bloc’а. Value – это специальный интерфейс, который представляет библиотека Decompose для хранения состояния компонента, который интегрируется со SwiftUI и Jetpack Compose (нативными библиотеками iOS и Android для UI).
Примечание