简体   繁体   English

从 Kotlin 调用用 Java 编写的方法时如何实现空安全,该方法引发异常?

[英]How can I achieve Null-safety when calling a method written in Java from Kotlin, which throws an exception?

I am trying to rewrite a class with Kotlin in a Java product.我正在尝试在 Java 产品中使用 Kotlin 重写一个类。 Our Java product has custom exceptions written like this:我们的 Java 产品具有如下编写的自定义异常:

public class AppError {
    public static void exit(int res_code) {
        throw new AppException(res_code);
    }
    ...
}

public class AppException extends RuntimeException {
    private int res_code = CommonResCode.ERROR;

    public AppException() { super(); }

    public AppException(int res_code) {
        super();
        this.res_code = res_code;
    }
}

So in the existing code, there are codes like:所以在现有的代码中,有如下代码:

int point = null;
point = someMap.get("foo")
if (point == null) {
    AppError.exit(THE_GIVEN_PARAMETER_IS_INVALID_CODE)
}

I want to rewrite this code with something like the Kotlin's我想用 Kotlin 之类的东西重写这段代码

val point: Int = someMap.getOrElse("foo", { AppError.exit(...) })
// or
val point: Int = someMap["foo"] ?: AppError.exit(...)

But since the exit method is seen as returning Unit , Kotlin says that point is both Int and Unit and suggests me to define point as Any .但是由于exit方法被视为返回Unit ,Kotlin 说该 point 既是Int又是Unit并建议我将point定义为Any What can I do to avoid this?我该怎么做才能避免这种情况? (other than doing the same as the Java code?) (除了和 Java 代码一样?)

Edit编辑

Since the code logically always throws an exception, I thought casting may be the simple way:由于代码逻辑上总是抛出异常,我认为强制转换可能是一种简单的方法:

val point: Int = someMap.getOrElse("foo", { AppError.exit(...) }) as Int

Is this correct?这样对吗? Or should I avoid doing this?或者我应该避免这样做?

Well, the method is returning void (the Unit in Kotlin).好吧,该方法返回void (Kotlin 中的Unit )。 Or rather, the method is never returning "normally" at all.或者更确切地说,该方法根本不会“正常”返回。 It never finishes, because it always throws an exception.它永远不会结束,因为它总是抛出异常。

AFAIK, there's nothing built-in which allows the use of custom exceptions. AFAIK,没有任何内置允许使用自定义异常。 You could however create a new helper method similar to Java's Objects.requireNonNull or Kotlin's !!但是,您可以创建一个类似于 Java 的Objects.requireNonNull或 Kotlin 的新辅助方法!! ( sure operator ): 确定运营商):

static <T> T requireOrThrow(final T value, final Supplier<Throwable> exceptionSupplier) {
    // be aware of boxing of primitive types
    if (value == null) throw exceptionSupplier.get();
    return value;
}

This can then be used from your Java …然后可以从您的 Java 中使用它……

int point = requireOrThrow(someMap.get("foo"), () -> new AppException(THE_GIVEN_PARAMETER_IS_INVALID_CODE));

… and Kotlin code, which should simplify both ... 和 Kotlin 代码,这应该简化两者

val point: Int = requireOrThrow(someMap["foo"], { AppException(THE_GIVEN_PARAMETER_IS_INVALID_CODE) });

In Kotlin you can write val point: Int = someMap["foo"] ?: error(ERROR_MESSAGE) because error function returns Nothing .在 Kotlin 中,您可以编写val point: Int = someMap["foo"] ?: error(ERROR_MESSAGE)因为error函数返回Nothing

So to make val point: Int = someMap["foo"] ?: AppError.exit(...) compile, you should make AppError.exit(...) return Nothing .因此,要使val point: Int = someMap["foo"] ?: AppError.exit(...)编译,您应该使AppError.exit(...)返回Nothing

Unfortunately, only Kotlin functions can return Nothing , but there are still a few solutions to your problem:不幸的是,只有 Kotlin 函数可以返回Nothing ,但仍有一些解决您的问题的方法:

1 . 1 . Make AppError.exit(...) return JNothing :使AppError.exit(...)返回JNothing

public class AppError {
    public static JNothing exit(int res_code) {
        throw new AppException(res_code);
    }
}

Where JNothing is: JNothing在哪里:

public final class JNothing {
    private JNothing() {}
}

JNothing to Nothing converter: JNothing to Nothing转换器:

operator fun JNothing.invoke(): Nothing {
    error("Illegal JNothing instance was created [$this]")
}

Use case:用例:

val point: Int = someMap["foo"] ?: AppError.exit(code)()

2 . 2 . Create KAppError.exit() wrapper of AppError.exit() which returns Nothing :创建KAppError.exit()的包装AppError.exit()返回Nothing

object KAppError {
    fun exit(res_code: Int): Nothing = mustThrow {
        AppError.exit(res_code)
    }
}

Where mustThrow is: mustThrow在哪里:

@PublishedApi
internal const val EXCEPTION_HAS_NOT_BEEN_THROWN = "Exception was expected, but it hasn't been thrown!"

inline fun mustThrow(block: () -> Unit): Nothing {
    block()
    error(EXCEPTION_HAS_NOT_BEEN_THROWN)
}

Use cases:用例:

val point: Int = someMap["foo"] ?: KAppError.exit(code)
val point1: Int = someMap["foo"] ?: mustThrow { AppError.exit(code) }

3 . 3 . Make AppError.exit() return whatever is required:使AppError.exit()返回所需的任何内容:

public class AppError {
    public static <Nothing> Nothing exit(int res_code) {
        throw new AppException(res_code);
    }
}

Use case:用例:

val point: Int = someMap["foo"] ?: AppError.exit(code)

4 . 4 . Make AppError.exit() return exception instead of throwing it:使AppError.exit()返回异常而不是抛出它:

public class AppError {
    public static AppException exit(int res_code) {
        return new AppException(res_code);
    }
}

Use case:用例:

val point: Int = someMap["foo"] ?: throw AppError.exit(code)

You can write a helper method in Kotlin which returns Nothing to indicate it never returns:您可以在 Kotlin 中编写一个辅助方法,它返回Nothing以表示它永远不会返回:

object AppErrorK {
    fun exit(res_code: Int): Nothing {
        AppError.exit(res_code)
        // will never actually be reached, but makes Kotlin accept the correct return type
        throw Exception()
    }
}

Then things like然后事情像

someMap["foo"] ?: AppErrorK.exit(...)

will work.将工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我如何知道从 Kotlin 调用 java 方法时是否应在调用站点检查可为空的参数? - How can i know when calling a java method from Kotlin if a nullable argument should be checked at call site? 通过JNI调用时Java抛出Null异常,但从Java程序调用时可以工作 - Java throws Null exception when calling via JNI but works when calling from Java program 我如何从这个位置实现最终目标? 代码抛出异常 - How can I achieve the end-goal from this position? Code throws out of bounds exception 当我使用引发时,调用方法不要求处理异常 - Calling method is not asking for to handle exception when i use throws 使用 Kotlin 在方法中抛出异常 - throws Exception in a method with Kotlin Kotlin 中方法的返回类型应该是什么,它的值可以为 null 并且将从 Java 调用? - What should be the returning type of a method in Kotlin which value can be null and will be called from Java? 如何使用Java Reflection调用抛出异常的方法? - How to invoke a method which throws an Exception using Java Reflection? Java 并发——使用哪种技术来实现安全? - Java concurrency - use which technique to achieve safety? 哈夫曼算法,构建代码树 dart 空安全 java 参考 - Huffman algorithm, building code tree dart null-safety java reference 执行.class文件的方法时,如何断言安全性? - How can I assert safety when executing a method of a .class file?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM