Prova con risorse in Kotlin


148

Quando ho provato a scrivere un equivalente di un codice Java trycon risorse in Kotlin, non ha funzionato per me.

Ho provato diverse varianti di quanto segue:

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

Ma nessuno dei due funziona.

Qualcuno sa cosa dovrebbe essere usato invece? Apparentemente la grammatica di Kotlin non ha una definizione per un tale costrutto, ma forse mi manca qualcosa. Definisce la grammatica per il blocco try come segue:

try : "try" block catchBlock* finallyBlock?;

Risposte:


219

C'è use-funzione in kotlin stdlib ( src ).

Come usarlo:

OutputStreamWriter(r.getOutputStream()).use {
    // by `it` value you can get your OutputStreamWriter
    it.write('a')
}

3
Adoro i metodi di estensione così tanto. Tante cose che puoi fare e nessuna necessità di funzionalità linguistiche aggiuntive.
Kirill Rakhman,

20
In aggiunta a questo, c'è in realtà una proprietà di estensione per ottenere anche un OutputStreamWriter:r.outputStream.writer.use { ... }
Damian Wieczorek,

3
Link al documento di riferimento che dimostra l' useestensione: kotlinlang.org/docs/reference/…
Javaru

1
Come posso usare il multi "uso" in un modo migliore? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Ponomarenko Oleh,

44

TL; DR: nessuna sintassi speciale, solo una funzione

Kotlin, al contrario di Java, non ha una sintassi speciale per questo. Invece, prova con le risorse , è offerto come funzione di libreria standard use.

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

Le useimplementazioni

@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()
        }
    }
}

Questa funzione è definita come un'estensione generica su tutti i Closeable?tipi. Closeableè l' interfaccia di Java che consente di provare con risorse a partire da Java SE7 .
La funzione assume una funzione letterale blockche viene eseguita in a try. Come con try-with-resources in Java, Closeableviene chiuso in a finally.

Anche i fallimenti che si verificano all'interno blockportano a closeesecuzioni, dove eventuali eccezioni vengono letteralmente "soppresse" semplicemente ignorandole. Ciò è diverso dal tentativo con risorse , poiché tali eccezioni possono essere richieste nella soluzione Java .

Come usarlo

L' useestensione è disponibile su qualsiasi Closeabletipo, ad esempio stream, lettori e così via.

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

La parte tra parentesi graffe è ciò che diventa blockin use(un lambda è passato come argomento qui). Al termine del blocco, puoi essere sicuro che FileInputStreamè stato chiuso.


16

Modifica : la seguente risposta è ancora valida per Kotlin 1.0.x. Per Kotlin 1.1, esiste una libreria standard che supporta Java 8 per supportare il modello di risorse chiudibile.

Per altre classi che non supportano la funzione "usa", ho fatto le seguenti risorse di prova fatte in casa:

package info.macias.kotlin

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

Quindi puoi usarlo nel modo seguente:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}

1
Questo non tratta correttamente le eccezioni generate dalla clausola finally, che è uno dei motivi per cui è stato aggiunto a Java un tentativo con risorse. Questo è solo un semplice try/finallyblocco
Nikola Mihajlović,

0

Poiché questo post StackOverflow è vicino all'inizio dei risultati di ricerca attuali per "esempio chiudibile di kotlin", eppure nessuna delle altre risposte (né i documenti ufficiali) spiega chiaramente come estendere Closeable(aka java.io.Closeable), ho pensato di aggiungere un esempio di come creare la tua classe che si estende Closeable. Va così:

import java.io.Closeable

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

E poi per usarlo:

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

Vedi questo esempio nel Kotlin Playground qui .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.