[英]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 代码一样?)
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.