718.99K
Категория: ПрограммированиеПрограммирование

Kotlin. Основы

1.

Основы

2.

Переменные и типы данных
Переменная создается с помощью ключевого слова val или var.
Если сразу понятно, что переменная в дальнейшем меняться не будет, то используется val.
Если известно, что переменная в дальнейшем может поменяться, то используется var.
Kotlin - типизированный ЯП, но при первоначальной инициализации переменной тип
может определиться автоматически, в зависимости от того, что было присвоено
переменной.

3.

Nullable types
Переменные в Kotlin (в отличие от Java) по умолчанию не могут хранить в себе null.
По этой причине нельзя создать переменную и ничего туда не положить. Например, в Java
следующая запись была бы верной:
Однако подобная запись в Kotlin:
приведет к ошибке. В таком случае в
переменную нужно что-то положить в соответствии с типом:
,
ну или так:
Но как быть если мы хотим, чтобы переменная могла хранить в себе null? В этом случае
ее тип нужно сделать “нулабельным”. Для этого тип следует указывать со знаком “?”:

4.

Теперь когда в переменной может храниться null, обращаться к ней стало небезопасно!
Например:
Здесь мы пытаемся вывести длину строки name. И если в name действительно что-то
хранится, то мы бы вывели ее длину, но если бы там был null, то приложение аварийно
завершило бы работу (крашнулось). По этой причине IDE на этапе компиляции нам
сообщает, что вызов name.length небезопасный, то есть нужно сначала проверить не
хранится ли там null: если нет, то только в этом случае осуществлять вывод:
Результат
Результат

5.

Но код выше выглядит громоздким, поэтому в Kotlin есть сокращенная версия
подобной проверки. Вместо использования оператора if, можно просто вызвать
“нулабельную” переменную со знаком ?
Представленные варианты выше обезопасят ваш код от краша. И в том, и в другом
случает если в переменной будет храниться null, то вызова не будет, и код сработает
успешно.
Использовать “нулабельные” переменные с безопасным вызовом ? считается
хорошим тоном! Поэтому предпочтение нужно давать второму способу.

6.

Кстати вместо знака ? есть возможность использовать другой знак: !!. Это будет
означать, что в нулабельной переменной точно не хранится null:
И как вы наверно уже догадались, такой код не будет безопасным, так как в случае если
там хранится null, то никакой проверки не будет и код ниже вызовет краш:
Использовать “нулабельные” переменные с НЕбезопасным вызовом !! считается
плохим тоном! Поэтому предпочтение нужно давать безопасному вызову ?. И
стараться писать код без использования !!.

7.

Когда в переменной хранится null, то можно дать значение по умолчанию, для этого есть
спец оператор: ?:
Например:
Здесь если a будет содержать в себе null, то вместо нее будет использован 0.
Заметьте, что код ниже будет некорректным, так как null и 6 сложить нельзя!

8.

Проверь себя :)
постарайся ответить без использования IDE!
Скомпилируется ли этот код?
val intro: String? = "Hello, this is our first lesson"
val withoutSpace = intro.trim()
println(withoutSpace)
Скомпилируется ли этот код?
val firstPart: String? = null
val secondPart: String = "World"
println(firstPart + secondPart)

9.

Проверь себя :)
постарайся ответить без использования IDE!
Что будет выведено на экран ?
val x = null
val y = 56
println(x ?: null + 56)

10.

А теперь можешь проверить в IDE.
Если на что-то ты ответил неправильно, то
будет лучше вернуться назад и почитать еще
раз! Или спросить у Ислома в телеге : )

11.

Условный оператор if … else
Синтаксис условного оператора в Kotlin схож с синтаксисом в Java.
if (логическое выражение) {
} else if (логическое выражение)
{
} else {
}
Однако в отличие от Java, условный оператор в Kotlin является выражением, то есть из него что-то можно вернуть:
val result = if (логическое выражение) {
"Okay"
} else if (логическое выражение) {
"Not okay :("
} else {
"I don't know what to say :("
}

12.

Условный оператор when
В Java у нас был оператор switch … case, его аналог в Kotlin - это оператор when.
var dayOfWeek = 5
when(dayOfWeek) {
1 -> println("Понедельник")
2 -> println("Вторник")
3 -> println("Среда")
4 -> println("Четверг")
5 -> println("Пятница")
6 -> println("Суббота")
7 -> println("Воскресенье")
}

13.

Оператор when в Kotlin также является выражением и оттуда можно что-то вернуть.
var dayOfWeek = 5
val result = when(dayOfWeek) {
1 -> "Понедельник"
2 -> "Вторник"
3 -> "Среда"
4 -> "Четверг"
5 -> "Пятница"
6 -> "Суббота"
7 -> "Воскресенье"
else -> "invalid day of week"
}
println(dayOfWeek)

14.

Циклы while и for
Цикл while в Kotlin не получил особых отличий от циклов while в Java
while(логическое выражение) {
// тело цикла
}
Цикл for в Kotlin значительно отличается от Java
for (i in итерируемый промежуток) {
// тело цикла
}
Здесь итерируемым промежотком может быть массив, список, строка или даже просто промежуток типа 1..100.
Кстати в промежутке 1..100 учитывается правая граница, то есть можно читать так: “От одного до ста
включительно”.
Есть еще и другой вариант: 1 until 100, ключевое слово until означает, означает, что правая граница
затрагиваться не будет, то есть ее можно читать так: “От одного до ста НЕвключительно”.

15.

Массивы
Для создания массива можно использовать встроенную в Kotlin функцию: arrayOf() и сразу передать туда набор
данных
val array = arrayOf(1,2,3,4,5)
Для обращения к элементу массива используются квадратные скобки:
val array = arrayOf(1,2,3,4,5)
println(array[2]) // напечатается 3
array[2] = 10
println(array[2]) // напечатается 10
Тип массива - Array<>, в треугольные скобки передается тип, который будет храниться в массиве:
val array: Array<Int> = arrayOf(1,2,3,4,5)
val names: Array<String> = arrayOf("Bob", "Terry")
Есть также другой способ создать массив, используя функцию arrayOfNulls(), однако в этом случае в эту
функцию нужно передать длину массива.
val array = arrayOfNulls<Int>(100)

16.

Коллекция list-список
Коллекция list в отличие от массива умеет динамически выделять память для данных. Это означает, что в
процессе использования списка, его длина может меняться (чего нельзя сказать о массивах!)
Код ниже создает список:
val list = ArrayList<String>()
В треугольных скобках передается тип хранимых данных. ArrayList обладает
некоторыми полезными методами, например:
list.add("Ellis")
Метод add() позволяет динамически добавить элемент в список (обратите внимание, что при этом увеличивается
длина списка, в массивах так сделать не получилось бы!)
Обычно список удобнее создавать с помощью встроенных методов: listOf(), mutableListOf().
val list = listOf<String>()
val list = mutableListOf<String>()
Но в чем же отличия между ними ?

17.

Отличие между listOf() и mutableListOf() заключается в том, что первый возвращает неизменяемый список, а
второй возвращает изменяемый список, например:

18.

Лямбда - выражения
Лямбда - выражение по своей сути это такая же функция, но в отличие от нее она не имеет имени. Поэтому
иногда ее еще называют анонимной функцией.
{
// вот так довольно просто выглядит
// лямбда выражение, просто две фигурные скобки :)
// хотя на самом деле - это целая функция!
}
Так же как и в функциях, в лямбду можно передать параметры:
{
x: Int, y: Int ->
// параметры лямбды и тело лямбды
// разделяются знаком '->'
// то есть здесь уже идет тело лямбды, а вот до символа
// '->' были параметры
}
Эти параметры можно спокойно использовать внутри лямбды:

19.

{
x: Int, y: Int ->
println(x)
println(y)
println(x + y)
// и так далее, внутри лямбды может быть
// сколько угодно инструкций
}
Так же как и в функциях, из лямбды можно вернуть значение, для этого самой последней инструкцией в лямбде
должны быть возвращаемые данные без ключевого слова return:
{
}
x: Int, y: Int ->
println(x)
println(y)
println(x + y)
// и так далее, внутри лямбды может быть
// сколько угодно инструкций
// но если мы что - то хотим вернуть, то это должно быть
// последней инструкцией. Например вернем результат сложения
// x и y
x + y

20.

В отличие от функций лямбду можно сохранить в переменной, передать в функцию или даже в другую лямбду. Этот
момент не всегда понятен с первого раза, но разобраться можно :)
val result = {
x: Int, y: Int ->
println(x)
println(y)
println(x + y)
// и так далее, внутри лямбды может быть
// сколько угодно инструкций
// но если мы что - то хотим вернуть, то это должно быть
// последней инструкцией. Например вернем результат сложения
// x и y
x + y
}
Мы знаем, что функцию можно вызвать в любой момент в нашем коде, а как это делается в лямбдами? Очень
просто, нужно просто обратиться к переменной, где вы сохранили лямбду и вызвать ее:
result(5, 10) // сюда вернется 15

21.

А какой тип у лямбды ?
Это зависит от передаваемых параметров и возвращаемого типа.
Например для нашей лямбды ниже
val result = {
x: Int, y: Int ->
println(x)
println(y)
println(x + y)
x + y
}
тип будет следующим: (Int, Int) -> Int
Здесь в скобках - это типы передаваемых параметров, а после знака ‘->’ идет возвращаемый тип.
Смело можем указывать его:
val result: (Int, Int) -> Int = {
println(x)
println(y)
println(x + y)
x + y
}
x: Int, y: Int ->

22.

Можно также сразу указать имена параметров в типе: (x: Int, y: Int) -> Int
val result: (x: Int, y: Int) -> Int = {
println(x)
println(y)
println(x + y)
x + y
}
x: Int, y: Int ->
И тогда в лямбде их типы можно опустить:
val result: (x: Int, y: Int) -> Int = {
println(x)
println(y)
println(x + y)
x + y
}
x, y ->

23.

Если в лямбду передаются параметры, но ничего не возвращается, то в качестве возвращаемого типа можно указать
Unit
val result: (x: Int, y: Int) -> Unit = { x, y ->
println(x)
println(y)
println(x + y)
}
А вот так выглядит лямбда, в которую ничего не передают и ничего не возвращают:
val result: () -> Unit = {
println("нет параметров")
println("и ничего не возвращается")
}
Если в лямбду передается всего один параметр, то достаточно указать только его тип, а его имя
будет автоматически определено как it:
val sayHelloTo: (String) -> Unit = {
println("Hello, $it")
}
English     Русский Правила