Попробуй с ресурсами в Котлине

Попробуй с ресурсами в Котлине

1. Вступление

Управляемые языки, например ориентированные на JVM, автоматически обрабатывают наиболее распространенный ресурс: память.

Однако нам нужно иметь дело со всеми видами ресурсов, а не только с памятью: файлы, сетевые подключения, потоки, окна и т. Д. И,just like memory, those need to be released when no longer needed.

В этой статье мы рассмотрим, как можно автоматически управлять ресурсами в Kotlin и чем это отличается отJava’s try-with-resources construct.

Если вы хотите пропустить теорию,jump straight to the example.

2. Автоматическое управление ресурсами

Мы можем выделить три разных этапа при работе с ресурсами в Java (псевдокод):

resource = acquireResource()
try {
    useResource(resource)
} finally {
    releaseResource(resource)
}

Если язык или библиотека отвечает за освобождение ресурса (частьfinally), то мы называем этоAutomatic Resource Management. Такая функцияrelieves us from having to remember to free a resource.

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

В Java объекты, которые содержат ресурс и имеют право на автоматическое управление ресурсами, реализуют определенный интерфейс:Closeable для ресурсов, связанных с вводом-выводом, иAutoCloseable.

Кроме того, Java 7 модернизировала ранее существовавший интерфейсCloseable, чтобы расширитьAutoCloseable.

Следовательно, Kotlin использует ту же концепцию держателей ресурсов: то есть объекты, реализующие либоCloseable, либоAutoCloseable.

3. Функцияuse в Котлине

Для автоматического управления ресурсами в некоторых языках есть специальная конструкция: например, в Java 7 введенtry-with-resources, а в C # -the using keyword.

Иногда они предлагают нам паттерн, напримерRAII in C++. В некоторых других случаях они дают нам библиотечный метод.

Котлин попадает в последнюю категорию.

По конструкции этоdoesn’t have a language construct akin to try-with-resources in Java.

Вместо этого мы можем найти метод расширения под названиемuse в его стандартной библиотеке.

Позже мы рассмотрим это подробнее. На данный момент нам просто нужно знать, что каждый объект-держатель ресурса имеет методuse, который мы можем вызвать.

3.1. Как это использовать

Простой пример:

val writer = FileWriter("test.txt")
writer.use {
    writer.write("something")
}

Мы можем вызвать функциюuse для любого объекта, который реализуетAutoCloseable илиCloseable, точно так же, как с try-with-resources в Java.

Метод принимает лямбда-выражение, выполняет его и удаляет ресурс (путем вызоваclose() на нем) всякий раз, когда выполнение покидает блок, как обычно, так и с исключением.

Итак, в этом случае, послеuse,writer больше не может использоваться, потому что Kotlin автоматически закрыл его.

3.2. Более короткая форма

В приведенном выше примере для ясности мы использовали переменную с именемwriter, создав таким образом замыкание.

Однакоuse принимает лямбда-выражение с единственным параметром - объектом, содержащим ресурс:

FileWriter("test.txt")
  .use { w -> w.write("something") }

Внутри блока мы также можем использовать неявную переменнуюit:

FileWriter("test.txt")
  .use { it.write("something") }

Итак, как мы видим, нам не нужно давать объекту явное имя. Однако, как правило, хорошей идеей является ясность, а не написание слишком лаконичного кода.

3.3. Определениеuse()

Давайте посмотрим на определение функцииuse в Kotlin, которое можно найти в его стандартной библиотеке:

public inline fun  T.use(block: (T) -> R): R

Мы видим в части<T : Closeable?, R>, чтоuse is defined as an extension function on Java’s Closeable interface.

Подробнее о методах расширения можно найти вour introductory article.

Конечно,the use function is documented как часть стандартной библиотеки Kotlin.

3.4. Closeable противAutoCloseable

Если мы более внимательно рассмотрим пример из предыдущего раздела, то увидим, что сигнатура функцииuse определена только в интерфейсеCloseable. This is because Kotlin’s standard library targets Java 6.

В версиях Java до 7AutoCloseable не существовало и, конечно же,Closeable не расширял его.

На практике классы, реализующиеAutoCloseable, но неCloseable, встречаются редко. Тем не менее, мы можем столкнуться с одним из них.

В этом случае нам нужно только добавить зависимость от расширений Kotlin для Java 7, 8 или любой другой версии, на которую мы ориентируемся:


    org.jetbrains.kotlin
    kotlin-stdlib-jdk8

Последнюю версию зависимости можно найти наMaven Central.

Это дает нам еще одну функцию расширенияuse, определенную в интерфейсеAutoCloseable:

public inline fun  T.use(block: (T) -> R): R

4. Заключение

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

Реализация всех этих примеров и фрагментов кода можно найти вthe GitHub project - это проект Maven, поэтому его должно быть легко импортировать и запускать как есть.