1.42M
Категория: ПрограммированиеПрограммирование

Kotlin. Null-safety

1.

16.Еще Kotlin

2.

Содержание
1
Null-safety
2
Extensions
3
it, this (let. with, apply, ...)
4
Mutable
5
Coroutine

3.

1. Null-safety
Самым распространённым подводным камнем многих языков программирования, в том числе Java, является
попытка произвести доступ к null значению. Это приводит к ошибке. В Java такая ошибка называется
NullPointerException (сокр. "NPE").
Kotlin призван исключить ошибки подобного рода из нашего кода. NPE могу возникать только в случае:
• Явного указания throw NullPointerException()
• Использования оператора !!
• Эту ошибку вызвал внешний Java-код
• Есть какое-то несоответствие при инициализации данных (в конструкторе использована
ссылка this на данные, которые не были ещё проинициализированы)

4.

1. Null-safety
Проверка на null
Первый способ. Вы можете явно проверить b на null значение и обработать два варианта по отдельности:
Компилятор отслеживает информацию о проведённой вами проверке и позволяет
вызывать length внутри блока if. Также поддерживаются более сложные конструкции:

5.

1. Null-safety
Безопасные вызовы
Вторым способом является оператор безопасного вызова- ?.
Такие безопасные вызовы полезны в цепочках. К примеру, если Bob, Employee (работник), может быть
прикреплён (или нет) к отделу Department, и у отдела может быть управляющий, другой Employee. Для того,
чтобы обратиться к имени этого управляющего (если такой есть), напишем:

6.

1. Null-safety
Безопасные приведения типов (ориг.: Safe Casts)
Обычное приведение типа может вызвать ClassCastException в случае, если объект имеет другой тип.
Можно использовать безопасное приведение, которое вернёт null, если попытка не удалась:

7.

1. Null-safety
Оператор !!
Для любителей NPE существует ещё один способ. Мы можем написать b!! и это вернёт
нам либо non-null значение b (в нашем примере вернётся String), либо выкинет NPE:

8.

2. Extensions
Аналогично таким языкам программирования, как C# и Gosu, Kotlin позволяет расширять
класс путём добавления нового функционала. Не наследуясь от такого класса и не
используя паттерн "Декоратор". Это реализовано с помощью специальных выражений,
называемых расширения.
Для того, чтобы объявить функцию-расширение, нам нужно указать в качестве
префикса расширяемый тип, то есть тип, который мы расширяем. Следующий пример
добавляет функцию swap к MutableList<Int>:

9.

3. it, this (let. with, apply, ...)
Функция with позволяет выполнить несколько операций над одним объектом, не повторяя его
имени.
Функция принимает два аргумента - объект и лямбда-выражение. Первый аргумент
преобразуется в получатель лямбда-выражения. К получателю можно обращаться через this.

10.

3. it, this (let. with, apply, ...)
apply
Функция apply работает почти так же, как with, но возвращает объект, переданный в аргументе.
Полезна в тех случаях, когда требуется создание экземпляра, у которого следует
инициализировать некоторые свойства. Часто в этих случаях мы просто повторяем имя
экземпляра.

11.

3. it, this (let. with, apply, ...)
also
Метод для обмена значениями между двумя переменными без участия третьей переменной.

12.

3. it, this (let. with, apply, ...)
let
let полезен при работе с объектами, которые могут принимать значение null. Вместо того,
чтобы создавать длинные цепочки выражений if-else, можно просто скомбинировать
оператор ? («оператор безопасного вызова») с let: в результате мы получим лямбду, у
которой аргумент it является не nullable-версией исходного объекта.

13.

4. Mutable
Все коллекции в Kotlin располагаются в пакете kotlin.collections.
На вершине иерархии находится интерфейс Iterable, который определяет функцию итератор
для перебора коллекции.
Основным интерфейсом, который позволяет работать с коллекциями,
является kotlin.Collection. Данный интерфейс определяет функциональность для перебора
элементов, проверки наличия элементов, чтения данных. Однако он не предоставляет
возможности по добавлению и удалению данных. Его основные компоненты:
• size: возвращает количество элементов в коллекции
• isEmpty(): возвращает true, если коллекция пустая
• contains(element): возвращает true, если коллекция содержит element
• containsAll(collection): возвращает true, если коллекция содержит элементы коллекции
collection

14.

4. Mutable
Изменяемые коллекции
Все изменяемые коллекции реализуют интерфейс MutableIterable. Он представляет функцию
итератора для перебора коллекции.
Для изменения данных в Kotlin также определен интерфейс kotlin.MutableCollection, который
расширяет интерфейс kotlin.Collection и предоставляет методы для удаления и добавления
элементов. В частности:
• add(element): добавляет элемент
• remove(element): удаляет элемент
• addAll(elements): добавляет набор элементов
• removeAll(elements): удаляет набор элементов
• clear(): удаляет все элементы из коллекции

15.

4. Mutable
Все коллекции в Kotlin располагаются в пакете kotlin.collections.

16.

4.1 Интервалы
Интервалы оформлены с помощью функций rangeTo и имеют оператор в виде .., который
дополняется in и !in. Они применимы ко всем сравниваемым (comparable) типам. Вот несколько
примеров применения интервалов.

17.

4.1 Интервалы
А что, если вы хотите произвести итерацию в обратном порядке? Это просто. Можете
использовать функцию downTo(), определённую в стандартной библиотеке:
А есть ли возможность производить итерацию с шагом, отличным от единицы?
Разумеется. В этом вам поможет функция step():
Для создания интервала, который не включает последний элемент перебора,
используйте until:

18.

4.1 Интервалы
Ключевое слово when призвано заменить оператор switch, присутствующий в C-подобных
языках. В простейшем виде его использование выглядит так:
Если для нескольких значений выполняется одно и то же действие, то условия можно
перечислять в одной ветке через запятую:

19.

4.1 Интервалы
Также можно проверять вхождение аргумента в интервал in или !in или его наличие в
коллекции:
when удобно использовать вместо цепочки условий вида if-else if. При отстутствии аргумента,
условия работают как простые логические выражения, а тело ветки выполняется при его
истинности:

20.

5. Coroutines
Обычно экземпляры классов, которые реализуют интерфейс Runnable, используются для создания
потоков в Kotlin. Поскольку интерфейс Runnable имеет только один метод, метод run(), вы можете
использовать функцию преобразования для создания новых потоков с минимальным
стандартным кодом. Вот как вы можете использовать функцию thread(), которая является частью
стандартной библиотеки Kotlin, для быстрого создания и запуска нового потока:
Вышеуказанный подход подходит только тогда, когда вам нужно порождать поток или два. Если
параллелизм является важной частью бизнес-логики вашего приложения и вам нужно большое
количество потоков, лучше использовать пулы потоков со службой исполнителя.

21.

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

22.

5. Coroutines
Фоновые задачи, созданные с использованием интерфейса Runnable, не могут возвращать
результаты напрямую. Если вы хотите получать результаты от своих потоков, вы должны
использовать вместо этого интерфейс Callable
Когда вы передаете объект Callable методу submit() службы executor, вы получаете объект Future.
Объект Future будет содержать результат Callable в какой-то момент в будущем, когда служба
исполнителя закончит его запуск. Чтобы получить реальный результат от объекта Future, нужно
вызвать его метод get(), но будьте осторожны, ваш поток заблокируется, если вы вызовете его
преждевременно.

23.

5. Coroutines
В следующем примере кода показано, как создать объект Callable, который возвращает Future
типа String, запустить его и распечатать его результат:

24.

5. Coroutines
В отличие от Java, Kotlin не имеет ключевого слова synchronized. Следовательно, для
синхронизации нескольких фоновых операций вы должны использовать
аннотацию @Synchronized или встроенную функцию стандартной библиотеки synchronized().
Аннотация может синхронизировать весь метод, и функция работает с блоком операторов.

25.

5. Coroutines

26.

5. Coroutines
Корутины — это облегчённые потоки. Облегчённый поток означает, что он не привязан к
нативному потоку, поэтому он не требует переключения контекста на процессор, поэтому он
быстрее.
Корутины — это новый способ написания асинхронного, неблокирующего кода.
Корутины можно представить в виде облегчённого потока. Подобно потокам, корутины
могут работать параллельно, ждать друг друга и общаться. Самое большое различие
заключается в том, что корутины очень дешевые, почти бесплатные: мы можем
создавать их тысячами и платить очень мало с точки зрения производительности.
Потоки же обходятся дорого. Тысяча потоков может стать серьезной проблемой даже
для современной машины.
https://www.youtube.com/watch?v=jYuK1qzFrJg (на английском)
English     Русский Правила