Cách bắt nhiều ngoại lệ cùng lúc trong Kotlin


82
try { 

} catch (ex: MyException1, MyException2 ) {
    logger.warn("", ex)
}

hoặc là

try { 

} catch (ex: MyException1 | MyException2 ) {
    logger.warn("", ex)
}

Kết quả là, một lỗi biên dịch: Unresolved reference: MyException2.

Làm cách nào tôi có thể bắt nhiều ngoại lệ cùng lúc trên Kotlin?

Câu trả lời:


95

Cập nhật: Bỏ phiếu cho số báo sau KT-7128 nếu bạn muốn tính năng này xuất hiện ở Kotlin. Cảm ơn @Cristan

Theo chủ đề này, tính năng này không được hỗ trợ tại thời điểm này.

abreslav - Đội JetBrains

Không phải lúc này, nhưng nó đang ở trên bàn

Tuy nhiên, bạn có thể bắt chước multi-catch:

try {
    // do some work
} catch (ex: Exception) {
    when(ex) {
        is IllegalAccessException, is IndexOutOfBoundsException -> {
            // handle those above
        }
        else -> throw ex
    }
}

2
Tôi đang sao chép pdvriezebài trả lời ở đây: This certainly works, but is slightly less efficient as the caught exception is explicit to the jvm (so a non-processed exception will not be caught and rethrown which would be the corollary of your solution)
solidak

1
@IARI elseMệnh đề lặp lại ngoại lệ không mong muốn .
miensol


2
Thậm chí nếu bạn vứt bỏ những lập luận của sang trọng và xấu xa sang một bên, Kotlin (mà tuyên bố là súc tích) thực sự 2x là như tiết như Java trong trường hợp này
Phileo99

2
Đó là bị gắn cờ bởi Detekt bởi vì bạn đang đánh bắt quá chung chung một ngoại lệ ;-)
kenyee

8

Để thêm vào câu trả lời của miensol : mặc dù tính năng đa bắt trong Kotlin chưa được hỗ trợ, nhưng có nhiều lựa chọn thay thế hơn cần được đề cập.

Bên cạnh đó try-catch-when, bạn cũng có thể triển khai một phương pháp để bắt chước nhiều lần bắt. Đây là một tùy chọn:

fun (() -> Unit).catch(vararg exceptions: KClass<out Throwable>, catchBlock: (Throwable) -> Unit) {
    try { 
        this() 
    } catch (e: Throwable) {
        if (e::class in exceptions) catchBlock(e) else throw e
    }
}

Và sử dụng nó sẽ trông giống như:

fun main(args: Array<String>) {
    // ...
    {
        println("Hello") // some code that could throw an exception

    }.catch(IOException::class, IllegalAccessException::class) {
        // Handle the exception
    }
}

Bạn sẽ muốn sử dụng một hàm để tạo lambda thay vì sử dụng lambda thô như được hiển thị ở trên (nếu không, bạn sẽ gặp phải "MANY_LAMBDA_EXPRESSION_ARGUMENTS" và các vấn đề khác khá nhanh). Một cái gì đó giống như fun attempt(block: () -> Unit) = blocksẽ hoạt động.

Tất nhiên, bạn có thể muốn chuỗi các đối tượng thay vì lambdas để soạn logic của bạn một cách thanh lịch hơn hoặc để hoạt động khác với một thử nghiệm cũ đơn giản.

Tôi chỉ khuyên bạn nên sử dụng cách tiếp cận này trên miensol nếu bạn đang thêm một số chuyên môn . Đối với việc sử dụng nhiều bắt đơn giản, một whenbiểu thức là giải pháp đơn giản nhất.


Nếu tôi hiểu nó một cách chính xác, bạn chuyển các lớp trong lệnh bắt của bạn, nhưng param exceptionslấy các đối tượng.
nllsdfx

bạn thật tuyệt vời @aro, cảm ơn bạn đã cung cấp giải pháp thay thế này
mochadwi

Thay thế này là tốt, cảm ơn Aro :) Còn hơn không. Tuy nhiên, tôi hy vọng họ sẽ nhận được tính năng đó mặc dù vấn đề KT-7128 của tôi đã được mở cách đây 5 năm :-)
zdenda.online

-1

Ví dụ từ aro rất tốt nhưng nếu có thừa kế, nó sẽ không hoạt động như trong Java.

Câu trả lời của bạn đã truyền cảm hứng cho tôi để viết một hàm mở rộng cho điều đó. Để cho phép các lớp kế thừa, bạn phải kiểm tra instancethay vì so sánh trực tiếp.

inline fun multiCatch(runThis: () -> Unit, catchBlock: (Throwable) -> Unit, vararg exceptions: KClass<out Throwable>) {
try {
    runThis()
} catch (exception: Exception) {
    val contains = exceptions.find {
        it.isInstance(exception)
    }
    if (contains != null) catchBlock(exception)
    else throw exception
}}

Để xem cách sử dụng, bạn có thể xem thư viện của tôi trên GitHub 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.