Kotlin string and string templates

Содержание:

Свойства

Свойства (properties) — весьма полезный инструмент программирования, и надо сказать, что в Kotlin этот вопрос решен очень интересно:

Это довольно простой пример, но вполне актуальный. Здесь — это вычислимое свойство (предполагается, что у класса, внутри которого находится функция, есть свойство ). Также для свойства можно задать и сеттер через , и устанавливать значение можно будет через присваивание .

С одной стороны, это менее прозрачно, чем использование явных get/set-методов в стиле Java, однако это здорово разгружает код.

Более того, начиная с версии Kotlin 1.1 можно не прописывать тип свойства явно, если он может быть выведен автоматически:

Если нам нужно поменять только видимость или аннотировать или , то это довольно легко сделать с помощью указания области видимости или аннотации перед или :

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

Останавливаемые функции

Приостановка происходит в случае вызова функции, обозначенной специальным модификатором :

Такие функции называются функциями остановки (приостановки), поскольку их вызовы могут приостановить выполнение сопрограммы (библиотека может принять решение продолжать работу без приостановки, если результат вызова уже доступен). Функции остановки могут иметь параметры и возвращать значения точно так же, как и все обычные функции, но они могут быть вызваны только из сопрограмм или других функций остановки. В конечном итоге, при старте сопрограммы она должна содержать как минимум одну функцию остановки, и функция эта обычно анонимная (лямбда-функция остановки). Давайте взглянем, для примера, на упрощённую функцию (из библиотеки ):

Здесь является обычной функцией (не функцией остановки), но параметр имеет функциональный тип с модификатором : . Таким образом, когда мы передаём лямбда-функцию в , она является анонимной функцией остановки, и мы можем вызывать функцию остановки изнутри её:

Продолжая аналогию, может быть функцией остановки (также может вызываться из блока ), которая приостанавливает сопрограмму до тех пор, пока некоторые вычисления не будут выполнены, и затем возвращает их результат:

Больше информации о том, как действительно работают функции в , может быть найдено .

Отметим, что функции приостановки и не могут быть вызваны из обыкновенных функций, подобных :

Заметим, что функции остановки могут быть виртуальными, и при их переопределении модификатор также должен быть указан:

Aннотация @RestrictsSuspension

Расширяющие функции (и анонимные функции) также могут быть маркированы как , подобно и всем остальным (регулярным) функциям. Это позволяет создавать DSL и другие API, которые пользователь может расширять. В некоторых случаях автору библиотеки необходимо запретить пользователю добавлять новые пути приостановки сопрограммы.

Чтобы осуществить это, можно использовать аннотацию . Когда целевой класс или интерфейс аннотируется подобным образом, все расширения приостановки должны делегироваться либо из членов , либо из других его расширений. Поскольку расширения не могут делегировать друг друга до бесконечности (иначе программа никогда не завершится), гарантируется, что все приостановки пройдут посредством вызова члена , так что автор библиотеки может полностью их контролировать.

Это актуально в тех редких случаях, когда каждая приостановка обрабатывается специальным образом в библиотеке. Например, при реализации генераторов через функцию, описанную , мы должны быть уверены, что любой приостанавливаемый вызовов в сопрограмме завершается вызовом либо , либо , а не какой-либо другой функции. Именно по этой причине аннотирована с @RestrictsSuspension:

См. исходники на Github.

Mapped types

Kotlin treats some Java types specially. Such types are not loaded from Java «as is», but are mapped to corresponding Kotlin types.
The mapping only matters at compile time, the runtime representation remains unchanged.
Java’s primitive types are mapped to corresponding Kotlin types (keeping in mind):

Тип Java Тип Kotlin

{:.zebra}

Some non-primitive built-in classes are also mapped:

Тип Java Тип Kotlin

{:.zebra}

Java’s boxed primitive types are mapped to nullable Kotlin types:

Java type Kotlin type

{:.zebra}

Note that a boxed primitive type used as a type parameter is mapped to a platform type:
for example, becomes a in Kotlin.

Collection types may be read-only or mutable in Kotlin, so Java’s collections are mapped as follows
(all Kotlin types in this table reside in the package ):

Java type Kotlin read-only type Kotlin mutable type Loaded platform type

{:.zebra}

Java’s arrays are mapped as mentioned :

Java type Kotlin type

{:.zebra}

Вложенные классы

Последнее обновление: 15.12.2017

В Kotlin классы могут быть определены в других классах. Такие классы (вложенные классы или nested classes) обычно выполняют какую-то вспомогательную роль, а определение их внутри класса
позволяет разместить их как можно ближе к тому месту, где они непосредственно используются.

Например, в следующем случае определяется вложенный класс:

class Account{
    class Transaction{

    }
}

В данном случае класс Transaction является вложенным, а класс Account — внешним.

По умолчанию вложенные классы имеют модификатор видимости public, то есть они видимы в любой части программы. Но для обращения к вложенному классу надо использовать
имя внешнего класса. Например, создание объекта вложенного класса:

val t = Account.Transaction()

Если необходимо ограничить область применения вложенного класса только внешним классом, то следует определить вложенный класс с модификатором private:

class Account{
    private class Transaction{

    }
}

Внутренние классы

Стоит учитывать, что вложенный класс по умолчанию не имеет доступа к свойствам и функциям внешнего класса. Например, в следующем случае при попытке
обратиться к свойству внешнего класса мы получим ошибку:

class Account{
    private var sum: Int = 3450
    class Transaction{
        fun pay(s: Int){
            sum -= s		// ! Ошибка
        }
    }
}

Чтобы вложенный класс мог иметь доступ к свойствам и функциям внешнего класса, необходимо определить вложенный класс с ключевым словом inner.
Такой класс еще называют внутренним классом (inner class), чтобы отличать от обычных вложенных классов. Например:

fun main(args: Array<String>) {

    Account().Transaction().pay(1200)
}
class Account{

    private var sum: Int = 3450
    fun display(){
        println("sum = $sum")
    }
	
    inner class Transaction{
        fun pay(s: Int){
            sum -= s
            display()
        }
    }
}

Теперь класс Transaction определен с ключевым словом inner, поэтому имеет полный доступ к свойствам и функциям внешнего класса Account. Но теперь если мы хотим использовать объект
подобного вложенного класса, то необходимо создать объект внешнего класса:

Account().Transaction().pay(1200)

Совпадение имен

Но что если свойства и функции внутреннего класса называются также, как и свойства и функции внешнего класса? В этом случае внутренний класс может обратиться к свойствам и функциям внешнего
через конструкцию :

class A{
	private val n: Int = 1
	inner class B{
		private val n: Int = 1
		fun action(){
			println(n)			// n из класса B
			println(this.n)		// n из класса B
			println(this@B.n)	// n из класса B
			println(this@A.n)	// n из класса A
		}
	}
}

Например, перепишем случай выше с классами Account и Transaction следующим образом:

fun main(args: Array<String>) {

    Account().Transaction(1200).pay()
}
class Account{
    private var sum: Int = 3450
    fun display(){
        println("sum = $sum")
    }
    inner class Transaction(s: Int){
        private var sum : Int = 0
        init {
            this.sum = s
        }
        fun pay(){
            this@Account.sum -= this@Transaction.sum
            display()
        }
    }
}

НазадВперед

Kotlin

Kotlin это новейший статически типизированный
язык программирования с открытым
исходным кодом. Он может эффективно
запускаться на виртуальной машине Java
(JVM). Kotlin разработан JetBrains и официально
поддерживается Google.

Недавний
опрос Jexenter поместил Kotlin на шестое
место среди технологических трендов.

В настоящее время Kotlin используется
для создания Android-приложений такими
лидерами бизнеса как Pivotal, Atlassian, Pinterest,
Evernote и Uber.

Последняя статистика App brain показывает,
что в сегменте топовых приложений 2018
года Kotlin
занимает 25,3% рынка. При этом 40,76% новых
инсталляций приложений также приходятся
на приложения, написанные на Kotlin.

Чтобы сравнить Kotlin с Java, нам нужно
понять преимущества и недостатки этого
языка.

Почему Kotlin это ведущий язык
программирования для разработки
Android-приложений?

Улучшенная производительность

Последовательный и интуитивный
синтаксис Kotlin обеспечивает повышение
производительности команд разработчиков.
Для написания и деплоймента программы
требуется меньше времени и меньше строк
кода. В результате вы получаете готовое
приложение быстрее.

100% совместимости с Java

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

Легкость поддержки

Android-разработчикам легко поддерживать
код на Kotlin, поскольку этот язык
поддерживается во многих IDE, включая
Android studio, и в нескольких других SDK. Кроме
того, разработчики могут работать с
любым привычным набором инструментов.

Надежность

Последняя версия Kotlin имеет обратную
совместимость со всеми предыдущими
версиями. Это избавляет Android-разработчиков
от огромной головной боли – работы с
разными версиями.

Легкость изучения

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

Поддержка Android Studio

Android Studio предоставляет расширенную
поддержку Kotlin и инструменты адаптации.
Разработчики могут работать одновременно
на Kotlin и на Java.

Недостатки Kotlin

Скорость компиляции

Разработчики жалуются на колебания
скорости компиляции кода на Kotlin. В
некоторых случаях она происходит очень
быстро, а в других заметно медленнее.

Меньшая поддержка сообщества

У Kotlin маленькое сообщество разработчиков,
в связи с чем количество ресурсов для
изучения этого языка ограничено. Вам
встретится много вопросов без ответов.

Нехватка разработчиков

Очень ограниченное количество людей
занимаются разработкой на Kotlin. Недостаток
талантов в разработке Android-приложений
касается Kotlin в большей степени, чем
Java.

Few String Properties and Functions

Since literals in Kotlin are implemented as instances of class, you can use several methods and properties of this class.

  • property — returns the length of character sequence of an string.
  • function — compares this String (object) with the specified object. Returns 0 if the object is equal to the specfied object.
  • function — returns character at the specified index.
    You can use index access operator instead of function as index access operator internally calls function.
  • function — returns a new string which is obtained by the concatenation of this string and the string passed to this function.
    You can use operator instead of function as operator calls function under the hood.
  • Function — returns a new character sequence starting at the specified start and end index.

Example: String Properties and Function

When you run the program, the output is:

Length of s1 string is 10.
Strings s1 and s2 are equal.
Third character is y.
result = Hey there! How are you?
Substring is "the"

Visit Kotlin String class for more information on extension properties, extension, functions and constructors.

Отличия от Java

Классы данных (Data Classes)

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

И на Kotlin:

Легко создавать копии классов данных при помощи метода :

Функции-расширения

Kotlin позволяет расширять функциональность существующих классов, не прибегая к наследованию. Это делается при помощи функций-расширений. Для объявления такой функции к её имени нужно приписать префикс в виде расширяемого типа. Вот так можно добавить функцию в :

Ключевое слово this внутри функции-расширения относится к объекту-получателю, который передаётся перед точкой. Теперь мы можем применить функцию swap к любому изменяемому списку:

Умные приведения типов

Компилятор Kotlin очень умён, когда речь заходит о приведениях типов. В большинстве случаев не требуется явно указывать операторы приведения, поскольку в языке есть оператор , который делает за вас всю работу:

Функциональное программирование

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

Вот пример работы с коллекциями:

Функции высшего порядка — это функции, которые принимают другие функции в качестве аргументов и возвращают функции. Рассмотрим следующий пример:

В нём — это имя аргумента, а — это тип функции. Мы говорим, что будет функцией, не принимающей аргументов и ничего не возвращающей.

Лямбда-выражения, или анонимные функции — это функции, которые не объявляются, а передаются в виде выражений. Вот пример:

Мы объявляем переменную , которая берёт два числа, складывает их и принимает значение суммы, приведённое к целому. Для вызова достаточно простого .

Сравнение скорости Java и Kotlin

Первая сборка Kotlin-кода занимает примерно на 15–20% больше времени, чем аналогичный процесс на Java. Однако инкрементная сборка Kotlin даже немного быстрее, чем у Java. Таким образом, языки примерно равны по скорости компиляции.

«Kotlin не лучше Java в целом, но лучше в мире Android»

Ильназ Гильязов

Сооснователь AIMS, автор программы курса «Разработчик на Kotlin» в Нетологии

Какие языки знает. Изначально я учил несколько языков по мере необходимости: Ассемблер, C/C++, потом уже Java, JS, PHP, Python. Поскольку работал и работаю в сфере ИБ, не могу останавливаться только на одном языке

Какие использует. Сейчас выбираю инструменты в зависимости от задач и предпочтений заказчика. Для бэкенда — Java/Kotlin, для легковесных вещей без множества интеграций — Go/NodeJS, для фронтенда — JS/TypeScript + фреймворки, для системных вещей — C++/Go. То есть учитываю не личные предпочтения, а исхожу из задачи и возможностей языка и его экосистемы.

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

В Android выбор Kotlin вместо Java очевиден. В мире backend позиции Kotlin гораздо слабее, хотя и там он себе пробивает дорогу. В Spring Framework (который для многих — стандарт в backend) включают фишки для Kotlin, недоступные для Java. Это уже говорит о многом. В большом и сложном backend мы пока по-прежнему работаем на Java, хотя и используем в некоторых местах Kotlin. В случае микросервисной архитектуры, где для конкретного микросервиса не требуется большого количества интеграций, Kotlin чувствуют себя прекрасно.

Kotlin не лучше Java в целом, но лучше в мире Android. Хотя с этим тоже можно поспорить — все зависит от параметров, по которым мы оцениваем.

О противостоянии и будущем языков. Противостояние между разработчиками на Kotlin и Java иногда наблюдаю в проектах, где нет общей договоренности и используют оба языка. А еще есть фанатики, которые верят в единственно правильный язык. В остальном все более-менее гладко, хотя в вопросах интеграции остаются шероховатости. Если вы хотите стать профи в Android, придется знать оба языка. Да и вообще, стоит привыкнуть к тому, что придется постоянно осваивать новые языки, библиотеки, фреймворки, идеи и подходы.

Сейчас будущее Java в Android непонятно. Когда мы перевели все свои Android-проекты на Kotlin, Java в Android застряла на уровне седьмой версии с некоторыми фишками из восьмой. И до сих пор неясно, собирается ли Google решать свои споры с Oracle и вводить поддержку новых версий, либо остановится на текущих позициях. Поэтому инвестиции в изучение, использование и поддержку Java на Android выглядят, как минимум, рискованными в среднесрочной перспективе.

Kotlin же развивается более-менее предсказуемо и предоставляет обертки, которые позволяют использовать все современные возможности языка, добавляет ряд удобств и возможностей именно для разработки под Android. Это немаловажный фактор, который влияет на удовлетворенность разработчиков.

В ближайшем будущем я не думаю, что Kotlin заменит Java. Скорее, он сможет сосуществовать с Java, так как изначально на это и ориентировался. Надеяться на то, что большую часть существующих популярных Java-библиотек перепишут на Kotlin не стоит. Но вы можете писать на Kotlin (разобравшись в нюансах интеграции Kotlin <-> Java, например, рефлексии и всех подводных камнях) и использовать библиотеки, написанные на Java.

?: – оператор «элвис»

Оператор, обозначаемый вопросительным знаком с двоеточием, подобен проверке на null в варианте if-else. Он возвращает значение слева от себя, если оно не null. И возвращает значение справа от себя, если то, что слева, – null.

Оператор используется для замены null, каким-либо значением, принадлежащим обычно зауженному типу. В результате выражение с «элвисом» позволяет не увеличивать в программе количество nullable-переменных.

fun main() {
    val b String? = readLine()
    val c String = b ?: "" 
 
    println(c.length)
}

Переменная будет содержать либо строку, которую вернула функция readLine(), либо пустую строку, если readLine() вернет null. Избавимся от переменной :

fun main() {
    val b String = readLine() ?: ""
 
    println(b.length)
}

Оператор нередко используют вместе с оператором . Если надо вызвать ненуллабл-метод на nullable-переменную, требуется оператор безопасного вызова. Поскольку в случае null метод вызываться не будет, а null надо заменить, требуется оператор «элвис».

fun main() {
    val b String? = readLine()
 
    val c Int = b?.length ?: -1
 
    println(c)
}

Последовательность действий в выражении идет слева направо. Сначала выполняется подвыражение с оператором . Потом его результат подставляется как левый операнд оператора . Так если длина строки была удачно измерена, то она и запишется в переменную . Если же оператор безопасного вызова вернул null, то в переменную запишется -1.

«Kotlin-разработчики могут использовать Java-фреймворки и библиотеки и писать более понятный и простой код»

Семен Пилунц

Android-разработчик, эксперт курса Нетологии

Какие языки знает. Знакомство с программированием случилось у меня в институте, начал с Pascal, также изучали Basic, QBasic. Уже в конце учебных лет начал изучать C. На этом я не остановился и начал изучать другие языки — Javascript, VB 6.0, MS SQL, Java. Вскоре осознал, что ближе всех мне Java, поэтому решил сфокусироваться на нем.

Спустя пару лет по воле случая начал использовать Java для создания мобильных приложений под Андроид. Иногда приходилось в самом Андроиде использовать Javascript, HTML, SQL. Знание других языков всегда помогает.

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

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

Почему предпочитает Kotlin. Использовать Kotlin проще и удобнее, чем Джаву. В нем программный код получается в среднем на 40% короче. А еще он позволяет не допускать некоторых ошибок, которые могут возникнуть в ходе выполнения программы. Когда код более простой и понятный, ошибки сложнее сделать и легче обнаружить, поэтому их число стремительно снижается. Вы тратите меньше времени на разработку и тестирование.

О будущем языков. Думаю, в ближайшем будущем Котлин сможет практически полностью заменить Джаву. Уже сейчас он охватывает рынок Android на 50%, и это всего за 3 года после появления. Но все же Джаву надо знать, без нее будет трудно переносить код на Котлин. Здесь отмечу, что Котлин полностью совместим с Java, то есть вовсе не обязательно сразу полностью переписывать приложение. Часто удобнее делать это постепенно.

А еще разработка Android-приложений — не единственное направление Kotlin. Он поддерживает JavaScript, программисты могут перенести на него фронтенд, Kotlin отлично подходит для разработки серверных приложений, позволяя писать короткий и выразительный код, сохраняя полную совместимость с существующими стеками технологий на основе Java. Также создатели добавили поддержку Gradle, чтобы разработчики могли писать на нем Gradle-файлы. Активно идет развитие Kotlin Native, с помощью которого можно создавать iOS-приложения.

Внутреннее функционирование сопрограмм

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

Сопрограммы полностью реализованы с помощью технологии компиляции (поддержка от языковой виртуальной машины, среды исполнения, или операционной системы не требуется), а приостановка работает через преобразование кода. В принципе, каждая функция приостановки (оптимизации могут применяться, но мы не будем вдаваться в эти подробности здесь) преобразуется в конечный автомат, где состояния соответствуют приостановленным вызовам. Прямо перед приостановкой следующее состояние загружается в поле сгенерированного компилятором класса вместе с сопутствующими локальным переменными и т. д. При возобновлении сопрограммы локальные переменные и состояние восстанавливаются, и конечный автомат продолжает свою работу.

Приостановленную сопрограмму можно сохранять и передавать как объект, который хранит её приостановленное состояние и локальные переменные. Типом таких объектов является Continuation, а преобразование кода, описанное здесь, соответствует классическому Continuation-passing style. Следовательно, приостановливаемые функции принимают дополнительный параметр типа (сохранённое состояние) под капотом.

Более детально о том, как работают сопрограммы, можно узнать в этом проектном документе. Похожие описания в других языках (таких как C# или ECMAScript 2016) актуальны и здесь, хотя особенности их языковых реализаций могут существенно отличаться от сопрограмм Kotlin.

Классы и объекты

Последнее обновление: 10.12.2017

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

Представлением объекта является класс. Класс фактически представляет определение объекта. А объект является конкретным воплощением класса.
Например, у всех есть некоторое представление о машине, например, кузов, четыре колеса, руль и т.д. — некоторый общий набор харакстеристик, присущих каждой машине.
Это представление фактически и является классом. При этом есть разные машины, у которых отличается форма кузова, какие-то другие
детали, то есть есть конкретные воплощения этого класса, конкретные объекты или экземпляры класса.

Для определения класса применяется ключевое слово class, после которого идет имя класса. А после имени класса в фигурных скобках определяется
тело класса. Если класс не имеет тела, то фигурные скобки можно опустить. Например, определим класс, который представляет человека:

class Person

// либо можно так
class Person { }

Класс фактически представляет новый тип данных, поэтому мы можем определять переменные этого типа:

fun main(args: Array<String>) {

    val tom: Person
    val bob: Person
    val alice: Person
}

class Person

В функции main определены три переменных типа Person. Стоит также отметить, что в отличие от других объектно-ориентированных языков (как C# или Java), функция main
в Kotlin не помещается в отдельных класс, а всегда определяется вне какого-либо класса.

Для создания объекта класса необходимо вызвать конструктор данного класса. Конструктор фактически представляет функцию, которая называется по имени класса и которая
выполняет инициализацию объекта. По умолчанию для класса компилятор генерирует пустой конструктор, который мы можем использовать:

val tom: Person = Person()

Часть кода после знака равно как раз и представляет вызов конструктора, который создает объект класса Person. До вызова конструктора
переменная класса не указывает ни на какой объект.

Например, создадим три объекта класса Person:

fun main(args: Array<String>) {

    val tom: Person = Person()
    val bob: Person = Person()
    val alice: Person = Person()
}

class Person

В Kotlin классы могут содержать ряд компонентов:

  • конструкторы и инициализаторы

  • функции

  • свойства

  • вложенные классы

  • объявления объектов

Далее мы рассмотрим определение и использование этих компонентов.

НазадВперед

Data-классы

Последнее обновление: 17.12.2017

Иногда классы бывают необходимы только для хранения некоторых данных. В Kotlin такие классы называются data-классы. Они определяются с модификатором
data:

data class Person(val name: String, val age: Int)

При компиляции такого класса компилятор автоматически добавляет в класс функции:

  • equals(): сравнивает два объекта на равенство

  • hashCode(): возвращает хеш-код объекта

  • toString(): возвращает строковое представление объекта

  • copy(): копирует данные объекта в другой объект

Причем при выполнении действий эти функции учитывают все свойства, которые определены в первичном конструкторе. Например, возьмем функцию ,
которая возвращает строковое представление объекта:

fun main(args: Array<String>) {

    val alice: Person = Person("Alice", 24)
    println(alice.toString())
}

class Person(val name: String, val age: Int)

Результатом программы будет следующий вывод:

Person@2a18f23c

По умолчанию строковое представление объекта нам практически ни о чем не говорит. Как правило, данная функция предназначена для вывода состояния объекта,
но для этого ее надо переопределять. Однако теперь добавим модификатор data к определению класса:

data class Person(val name: String, val age: Int)

И результат будет отличаться:

Person(name=Alice, age=24)

То есть мы можем увидить, какие данные хранятся в объекте, какие они имеют значения. То же самое касается всех остальных функций. То есть в случае
с data-классами мы имеем готовую реализацию для этих функций. Их не надо вручную переопределять. Но вполне взможно нас может не устраивать эта реализация, тогда мы можем определить свою:

data class Person(val name: String, val age: Int){
    override fun toString(): String {
        return "Name: $name  Age: $age"
    }
}

В этом случае для функции toString компилятор не будет определять реализацию.

Другим показательным примером является копирование данных:

fun main(args: Array<String>) {

    val alice: Person = Person("Alice", 24)
    val kate = alice.copy(name = "Kate")
    println(alice.toString())   // Person(name=Alice, age=24)
    println(kate.toString())    // Person(name=Kate, age=24)
}

data class Person(var name: String, var age: Int)

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

При этом чтобы класс определить как data-класс, он должен соответствовать ряду условий:

  • Первичный конструктор должен иметь как минимум один параметр

  • Все параметры первичного конструктора должны предваряться ключевыми словами val или var,
    то есть определять свойства

    Свойства, которые определяются вне первичного конструктора, не используются в функциях equals и hashCode

  • Класс не должен определяться с модификаторами data, abstract, sealed или
    inner.

Также стоит отметить, что несмотря на то, что мы можем определять свойства в первичном конструкторе и через val, и через var, например:

data class Person(var name: String, var age: Int)

Но вообще в ряде ситуаций рекомендуется определять свойства через val, то есть делать их неизменяемыми, поскольку на их основании вычисляет хеш-код, который используется в качестве ключа объекта в
такой коллекции как HashMap.

НазадВперед

Блокирование против приостановки

Главным отличительным признаком сопрограмм является то, что они являются вычислениями, которые могут быть приостановлены без блокирования потока (вытеснения средствами операционной системы)

Блокирование потоков часто является весьма дорогостоящим, особенно при интенсивных нагрузках: только относительно небольшое число потоков из общего числа является активно выполняющимися, поэтому блокировка одного из них ведет к затягиванию какой-нибудь важной части итоговой работы

С другой стороны, приостановка сопрограммы обходится практически бесплатно. Не требуется переключения контекста (потоков) или иного вовлечения механизмов операционной системы. И сверх этого, приостановка может гибко контролироваться пользовательской библиотекой во многих аспектах: в качестве авторов библиотеки мы можем решать, что происходит при приостановке, и оптимизировать, журналировать или перехватывать в соответствии со своими потребностями.

Еще одно отличие заключается в том, что сопрограммы не могут быть приостановлены на произвольной инструкции, а только в так называемых точках остановки (приостановки), которые вызываются в специально маркируемых функциях.

Java Arrays

Arrays in Kotlin are invariant, unlike Java. This means that Kotlin does not let us assign an to an ,
which prevents a possible runtime failure. Passing an array of a subclass as an array of superclass to a Kotlin method is also prohibited,
but for Java methods this is allowed (through of the form ).

Arrays are used with primitive datatypes on the Java platform to avoid the cost of boxing/unboxing operations.
As Kotlin hides those implementation details, a workaround is required to interface with Java code.
There are specialized classes for every type of primitive array (, , , and so on) to handle this case.
They are not related to the class and are compiled down to Java’s primitive arrays for maximum performance.

Suppose there is a Java method that accepts an int array of indices:

To pass an array of primitive values you can do the following in Kotlin:

При компиляции в байт-код JVM, компилятор оптимизирует доступ к массивам, таким образом, что отсутствуют
какие-либо накладные расходы:

Even when we navigate with an index, it does not introduce any overhead:

Finally, in{: .keyword }-checks have no overhead either:

Anonymous Inner Class

Anonymous inner class is a pretty good concept that makes the life of a programmer very easy. Whenever we are implementing an interface, the concept of anonymous inner block comes into picture. The concept of creating an object of interface using runtime object reference is known as anonymous class. In the following example, we will create an interface and we will create an object of that interface using Anonymous Inner class mechanism.

fun main(args: Array<String>) {
   var programmer :Human = object:Human // creating an instance of the interface {
      override fun think() { // overriding the think method
         print("I am an example of Anonymous Inner Class ")
      }
   }
   programmer.think()
}
interface Human {
   fun think()
}

The above piece of code will yield the following output in the browser.

I am an example of Anonymous Inner Class 
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector