Tente com recursos no Kotlin

147

Quando tentei escrever o equivalente a um trycódigo Java com recursos no Kotlin, não funcionou para mim.

Tentei diferentes variações do seguinte:

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

Mas nem funciona.

Alguém sabe o que deve ser usado? Aparentemente, a gramática de Kotlin não tem definição para essa construção, mas talvez eu esteja perdendo alguma coisa. Ele define a gramática para o bloco try da seguinte maneira:

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

Respostas:

219

use-função no kotlin stdlib ( src ).

Como usá-lo:

OutputStreamWriter(r.getOutputStream()).use {
    // by `it` value you can get your OutputStreamWriter
    it.write('a')
}
user2235698
fonte
3
Eu amo muito os métodos de extensão. Tantas coisas que você pode fazer e sem necessidade de recursos adicionais de idioma.
Kirill Rakhman
20
Além disso, também há uma propriedade de extensão para obter uma OutputStreamWriter:r.outputStream.writer.use { ... }
Damian Wieczorek
3
Link para o documento de referência que demonstra a useextensão: kotlinlang.org/docs/reference/…
Javaru
1
Como posso usar o "uso múltiplo" de uma maneira melhor? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Ponomarenko Oleh
43

TL; DR: Nenhuma sintaxe especial, apenas uma função

O Kotlin, ao contrário do Java, não possui uma sintaxe especial para isso. Em vez disso, tente com recursos , é oferecido como a função de biblioteca padrão use.

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

As useimplementações

@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 função é definida como uma extensão genérica em todos os Closeable?tipos. Closeableé a interface do Java que permite tentar com recursos a partir do Java SE7 .
A função aceita literalmente uma funçãoblock que é executada em a try. Igual ao try-with-resources em Java, o Closeableé fechado em um finally.

Além disso, falhas ocorridas no interior blocklevam aclose execuções, onde possíveis exceções são literalmente "suprimidas" simplesmente ignorando-as. Isso é diferente da tentativa com recursos , porque essas exceções podem ser solicitadas na solução do Java .

Como usá-lo

A useextensão está disponível em qualquer Closeabletipo, como fluxos, leitores e assim por diante.

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

A parte entre chaves é o que torna-se blockno use(a lambda é passado como um argumento aqui). Após a conclusão do bloqueio, você pode ter certeza de que FileInputStreamfoi fechado.

s1m0nw1
fonte
16

Editar : A resposta a seguir ainda é válida para o Kotlin 1.0.x. Para o Kotlin 1.1, há suporte a uma biblioteca padrão que visa o Java 8 para suportar o padrão de recurso que pode ser fechado.

Para outras classes que não oferecem suporte à função "use", executei o seguinte teste caseiro com recursos:

package info.macias.kotlin

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

Então você pode usá-lo da seguinte maneira:

fun countEvents(sc: EventSearchCriteria?): Long {
    return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
        var rs = it.executeQuery()
        rs.next()
        rs.getLong(1)
    }
}
Mario
fonte
1
Isso não lida corretamente com as exceções lançadas na cláusula finally, que é um dos motivos pelos quais o try-with-resources foi adicionado ao Java. Este é apenas um try/finallybloco simples
Nikola Mihajlović
0

Como esta postagem do StackOverflow está perto do topo dos resultados atuais da pesquisa "exemplo fechado do kotlin", e ainda nenhuma das outras respostas (nem os documentos oficiais) explica claramente como estender Closeable(aka java.io.Closeable), pensei em adicionar um exemplo de como criar sua própria classe que se estende Closeable. É assim:

import java.io.Closeable

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

E então para usá-lo:

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

Veja este exemplo no Kotlin Playground aqui .

Quuxplusone
fonte