Probar con recursos en Kotlin

148

Cuando intenté escribir un equivalente de un trycódigo Java con recursos en Kotlin, no funcionó para mí.

Intenté diferentes variaciones de lo siguiente:

try (writer = OutputStreamWriter(r.getOutputStream())) {
    // ...
}

Pero tampoco funciona.

¿Alguien sabe qué se debe usar en su lugar? Aparentemente, la gramática de Kotlin no tiene definición para tal construcción, pero tal vez me falta algo. Define la gramática para el bloque try de la siguiente manera:

try : "try" block catchBlock* finallyBlock?;
Alex
fuente

Respuestas:

219

Hay una usefunción en kotlin stdlib ( src ).

Cómo usarlo:

OutputStreamWriter(r.getOutputStream()).use {
    // by `it` value you can get your OutputStreamWriter
    it.write('a')
}
usuario2235698
fuente
3
Me encantan los métodos de extensión. Tantas cosas que puede hacer y no necesita funciones de idioma adicionales.
Kirill Rakhman el
20
Además de esto, en realidad hay una propiedad de extensión para obtener OutputStreamWritertambién:r.outputStream.writer.use { ... }
Damian Wieczorek
3
Enlace al documento de referencia que muestra la useextensión: kotlinlang.org/docs/reference/…
Javaru
1
¿Cómo puedo usar multi "use" de una mejor manera? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Ponomarenko Oleh
44

TL; DR: sin sintaxis especial, solo una función

Kotlin, a diferencia de Java, no tiene una sintaxis especial para esto. En cambio, try-with-resources , se ofrece como la función de biblioteca estándar use.

FileInputStream("filename").use { fis -> //or implicit `it`
   //use stream here
} 

Las useimplementaciones

@InlineOnly
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var closed = false
    try {
        return block(this)
    } catch (e: Exception) {
        closed = true
        try {
            this?.close()
        } catch (closeException: Exception) {
        }
        throw e
    } finally {
        if (!closed) {
            this?.close()
        }
    }
}

Esta función se define como una extensión genérica en todos los Closeable?tipos. Closeablees la interfaz de Java que permite probar con recursos a partir de Java SE7 .
La función toma una función literal blockque se ejecuta en a try. Al igual que con probar con recursos en Java, el Closeablese cierra en a finally.

También las fallas que ocurren dentro blockconducen a closeejecuciones, donde las posibles excepciones son literalmente "suprimidas" simplemente ignorándolas. Esto es diferente de probar con recursos , porque tales excepciones se pueden solicitar en la solución de Java .

Cómo usarlo

La useextensión está disponible en cualquier Closeabletipo, es decir, transmisiones, lectores, etc.

FileInputStream("filename").use {
   //use your stream by referring to `it` or explicitly give a name.
} 

La parte entre llaves es lo que se convierte blocken use(aquí se pasa una lambda como argumento). Una vez que el bloqueo está hecho, puede estar seguro de que FileInputStreamse ha cerrado.

s1m0nw1
fuente
16

Editar : la siguiente respuesta sigue siendo válida para Kotlin 1.0.x. Para Kotlin 1.1, existe una biblioteca estándar compatible con Java 8 para admitir un patrón de recursos que se puede cerrar.

Para otras clases que no admiten la función "usar", he realizado los siguientes recursos caseros de prueba con recursos:

package info.macias.kotlin

inline fun <T:AutoCloseable,R> trywr(closeable: T, block: (T) -> R): R {
    try {
        return block(closeable);
    } finally {
        closeable.close()
    }
}

Luego puede usarlo de la siguiente manera:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}
Mario
fuente
1
Esto no trata adecuadamente con las excepciones lanzadas desde la cláusula final, que es una de las razones por las que se agregó try-with-resources a Java. Esto es solo un simple try/finallybloqueo
Nikola Mihajlović
0

Dado que esta publicación de StackOverflow está cerca de la parte superior de los resultados de búsqueda actuales para "ejemplo que se puede cerrar de Kotlin", y sin embargo ninguna de las otras respuestas (ni los documentos oficiales) explican claramente cómo extender Closeable(también conocido java.io.Closeable), pensé que agregaría un ejemplo de cómo hacer tu propia clase que se extienda Closeable. Dice así:

import java.io.Closeable

class MyServer : Closeable {
    override fun close() {
        println("hello world")
    }
}

Y luego para usarlo:

fun main() {
    val s = MyServer()
    s.use {
        println("begin")
    }
    println("end")
}

Vea este ejemplo en el Kotlin Playground aquí .

Quuxplusone
fuente