Thử tài nguyên trong Kotlin


147

Khi tôi cố gắng viết một mã tương đương tryvới mã tài nguyên Java trong Kotlin, nó không hoạt động với tôi.

Tôi đã thử các biến thể khác nhau sau đây:

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

Nhưng không hoạt động.

Có ai biết những gì nên được sử dụng thay thế? Rõ ràng ngữ pháp của Kotlin không có định nghĩa cho cấu trúc như vậy, nhưng có lẽ tôi đang thiếu một cái gì đó. Nó định nghĩa ngữ pháp cho khối thử như sau:

try : "try" block catchBlock* finallyBlock?;

Câu trả lời:


219

usechức năng trong kotlin stdlib ( src ).

Làm thế nào để sử dụng nó:

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

3
Tôi yêu các phương pháp mở rộng rất nhiều. Rất nhiều điều bạn có thể làm và không cần thêm các tính năng ngôn ngữ.
Kirill Rakhman

20
Thêm vào đó, thực sự có một tài sản mở rộng để có được một OutputStreamWriter:r.outputStream.writer.use { ... }
Damian Wieczorek

3
Liên kết đến tài liệu tham khảo thể hiện usephần mở rộng: kotlinlang.org/docs/reference/iêu
Javaru

1
Làm thế nào tôi có thể sử dụng đa "sử dụng" một cách tốt hơn? FileOutputStream(into).use { val mergingStream = BufferedOutputStream(it).use { } }
Ponomarenko Oleh

43

TL; DR: Không có cú pháp đặc biệt, chỉ là một hàm

Kotlin, trái ngược với Java, không có cú pháp đặc biệt nào cho việc này. Thay vào đó, try-with-resource , được cung cấp dưới dạng hàm thư viện chuẩn use.

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

Việc usethực hiện

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

Hàm này được định nghĩa là một phần mở rộng chung trên tất cả các Closeable?loại. Closeablegiao diện của Java cho phép dùng thử với các tài nguyên kể từ Java SE7 .
Hàm lấy một hàm theo nghĩa đen blockđược thực thi trong a try. Giống như với tài nguyên thử với Java, tài khoản Closeableđược đóng trong a finally.

Ngoài ra những thất bại xảy ra bên trong blockdẫn đến các closevụ hành quyết, trong đó các trường hợp ngoại lệ có thể bị "triệt tiêu" theo nghĩa đen chỉ bằng cách bỏ qua chúng. Điều này khác với thử tài nguyên , bởi vì các ngoại lệ như vậy có thể được yêu cầu trong giải pháp của Java .

Làm thế nào để sử dụng nó

Phần usemở rộng có sẵn trên bất kỳ Closeableloại nào , tức là luồng, người đọc, v.v.

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

Phần trong dấu ngoặc móc là những gì trở nên blocktrong use(một lambda được thông qua như là một cuộc tranh cãi ở đây). Sau khi khối được hoàn thành, bạn có thể chắc chắn rằng nó FileInputStreamđã được đóng lại.


16

Chỉnh sửa : Phản hồi sau đây vẫn hợp lệ cho Kotlin 1.0.x. Đối với Kotlin 1.1, có hỗ trợ thư viện chuẩn nhắm mục tiêu Java 8 để hỗ trợ mẫu tài nguyên có thể đóng.

Đối với các lớp khác không hỗ trợ chức năng "sử dụng", tôi đã thực hiện thử tài nguyên tự chế sau đây:

package info.macias.kotlin

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

Sau đó, bạn có thể sử dụng nó theo cách sau:

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

1
Điều này không giải quyết đúng đắn các trường hợp ngoại lệ được đưa ra từ mệnh đề cuối cùng, đây là một trong những lý do thử tài nguyên đã được thêm vào Java. Đây chỉ là một try/finallykhối đơn giản
Nikola Mihajlović

0

Vì bài đăng StackOverflow này ở gần đầu kết quả tìm kiếm hiện tại cho "ví dụ có thể đóng kotlin" và chưa có câu trả lời nào khác (cũng không phải là tài liệu chính thức) giải thích rõ ràng cách mở rộng Closeable(aka java.io.Closeable), tôi nghĩ tôi nên thêm một ví dụ làm thế nào để làm cho lớp học của riêng bạn mà mở rộng Closeable. Nó như thế này:

import java.io.Closeable

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

Và sau đó sử dụng nó:

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

Xem ví dụ này trong Sân chơi Kotlin tại đây .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.