ลองกับทรัพยากรใน Kotlin


149

เมื่อฉันพยายามเขียนเทียบเท่า Java tryโค้ด -with-resourcesใน Kotlin มันไม่ได้ผลสำหรับฉัน

ฉันลองรูปแบบต่าง ๆ ต่อไปนี้:

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

แต่ก็ไม่ได้ผล

ไม่มีใครรู้ว่าสิ่งที่ควรใช้แทน? เห็นได้ชัดว่า Kotlin ไวยากรณ์ไม่ได้มีความหมายสำหรับการสร้างดังกล่าว แต่บางทีฉันอาจจะขาดอะไรบางอย่าง มันกำหนดไวยากรณ์สำหรับลองบล็อกดังนี้:

try : "try" block catchBlock* finallyBlock?;

คำตอบ:


220

มีuse-function ใน kotlin stdlib ( src )

วิธีใช้งาน:

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

3
ฉันชอบวิธีการต่อเติมมาก ๆ มีหลายสิ่งที่คุณสามารถทำได้และไม่จำเป็นต้องใช้คุณสมบัติภาษาเพิ่มเติม
คิริลล์ Rakhman

20
เพิ่มไปนี้มีคุณสมบัติส่วนขยายจริง ๆ เพื่อรับOutputStreamWriterเช่นกัน:r.outputStream.writer.use { ... }
Damian Wieczorek

3
เชื่อมโยงไปยังเอกสารอ้างอิงที่แสดงให้เห็นถึงuseส่วนขยาย: kotlinlang.org/docs/reference/ …
Javaru

1
ฉันจะใช้ "การใช้" แบบหลายทางได้อย่างไรในวิธีที่ดีกว่า FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Ponomarenko Oleh

44

TL; DR: ไม่มีไวยากรณ์พิเศษเพียงแค่ฟังก์ชั่น

Kotlin ซึ่งตรงกันข้ามกับ Java ไม่มีไวยากรณ์พิเศษสำหรับสิ่งนี้ ให้ลองใช้ทรัพยากรแทนเป็นฟังก์ชันไลบรารีมาตรฐานuseแทน

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

การuseใช้งาน

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

ฟังก์ชั่นนี้ถูกกำหนดให้เป็นส่วนขยายทั่วไปในทุกCloseable?ประเภท Closeableเป็นอินเทอร์เฟซของ Java ที่อนุญาตให้ลองกับทรัพยากรเป็นของ Java SE7
ฟังก์ชั่นใช้เวลาตัวอักษรฟังก์ชั่นที่ได้รับการดำเนินการในblock tryเช่นเดียวกับกับลองกับทรัพยากรใน Java, Closeableรับปิดfinallyใน

นอกจากนี้ความล้มเหลวที่เกิดขึ้นภายในblockนำไปสู่closeการประหารชีวิตหากมีข้อยกเว้นที่เป็นไปได้คือ "ระงับ" อย่างแท้จริงโดยเพียงเพิกเฉยต่อสิ่งเหล่านั้น สิ่งนี้แตกต่างจากการทดลองใช้กับทรัพยากรเนื่องจากข้อยกเว้นดังกล่าวสามารถร้องขอได้ในโซลูชันของJava

วิธีใช้งาน

useส่วนขยายที่มีอยู่ในใด ๆCloseableชนิดเช่นลำธารผู้อ่านและอื่น ๆ

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

ส่วนในวงเล็บปีกกาคือสิ่งที่จะกลายเป็น blockในuse(แลมบ์ดาถูกส่งผ่านเป็นอาร์กิวเมนต์ที่นี่) หลังจากบล็อกเสร็จสิ้นคุณสามารถมั่นใจFileInputStreamได้ว่าถูกปิด


16

แก้ไข : การตอบสนองต่อไปนี้ยังคงใช้ได้สำหรับ Kotlin 1.0.x สำหรับ Kotlin 1.1 มีการสนับสนุนไลบรารีมาตรฐานที่กำหนดเป้าหมาย Java 8 เพื่อสนับสนุนรูปแบบทรัพยากรที่ปิดได้

สำหรับคลาสอื่นที่ไม่รองรับฟังก์ชั่น "use" ฉันได้ทำการลองทำแบบลองด้วยทรัพยากรต่อไปนี้:

package info.macias.kotlin

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

จากนั้นคุณสามารถใช้วิธีดังต่อไปนี้:

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

1
สิ่งนี้ไม่ได้จัดการอย่างถูกต้องกับข้อยกเว้นที่ถูกส่งออกมาจาก clause สุดท้ายซึ่งเป็นหนึ่งในเหตุผลที่การลองกับรีซอร์สถูกเพิ่มใน Java นี่เป็นเพียงtry/finallyบล็อกง่ายๆ
Nikola Mihajlović

0

เนื่องจากโพสต์ StackOverflow นี้อยู่ใกล้กับด้านบนของผลการค้นหาปัจจุบันสำหรับ "kotlin closeable example" และยังไม่มีคำตอบอื่นใด (หรือเอกสารทางการ) อธิบายอย่างชัดเจนถึงวิธีการขยายCloseable(aka java.io.Closeable) ฉันคิดว่าฉันจะเพิ่มตัวอย่าง Closeableของวิธีการที่จะทำให้ระดับของคุณเองที่ขยาย มันจะเป็นเช่นนี้:

import java.io.Closeable

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

แล้วใช้มัน:

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

ดูตัวอย่างนี้ใน Kotlin สนามเด็กเล่นที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.