如何在没有Java的纯Kotlin中实现接口null vs throw分派
考虑这个例子:如何在没有Java的纯Kotlin中实现接口null vs throw分派,java,kotlin,interface,kotlin-null-safety,Java,Kotlin,Interface,Kotlin Null Safety,考虑这个例子: CommonHandler.java: 具有附加逻辑的公共处理程序。这里非常简单: import kotlin.jvm.functions.Function0; 公共类CommonHandler{ 私有void docooltuffever(){/*做一些很酷的事情*/} 私有void docooltuffiter(){/*做一些很酷的事情*/} public R getResult(函数0提供程序){ R结果; doCoolStuffBefore(); 试一试{ 结果=pro
CommonHandler.java: 具有附加逻辑的公共处理程序。这里非常简单:
import kotlin.jvm.functions.Function0;
公共类CommonHandler{
私有void docooltuffever(){/*做一些很酷的事情*/}
私有void docooltuffiter(){/*做一些很酷的事情*/}
public R getResult(函数0提供程序){
R结果;
doCoolStuffBefore();
试一试{
结果=provider.invoke();
}最后{
doCoolStuffAfter();
}
返回结果;
}
}
NullableHandler.kt: 如果操作引发异常,则返回
null
的处理程序版本。结果的类型为R?
class NullableHandler : CommonHandler() {
override fun <R> getResult(provider: Function0<R>): R? {
return try {
super.getResult(provider)
} catch(ex: Throwable) {
null
}
}
}
Api.kt: 基本上任何我们不拥有的API都不能修改
object Api {
fun find(query: String): Int =
if (query.length > 3) 42
else throw NoSuchElementException("Not found for $query")
fun select(query: String): String =
if (query.count { it == 'x' } > 2) "Selected"
else throw NoSuchElementException("Not found for $query")
}
现在,有了上述所有类,我们可以实现API包装器:
object ApiProxy {
private val throwingHandler = ThrowingHandler()
private val nullableHandler = NullableHandler()
fun find(query: String): Int = throwingHandler.getResult { Api.find(query) }
fun findOrNull(query: String): Int? = nullableHandler.getResult { Api.find(query) }
fun select(query: String): String = throwingHandler.getResult { Api.select(query) }
fun selectOrNull(query: String): String? = nullableHandler.getResult { Api.select(query) }
}
我的问题是,我如何实现类似的层次结构,而不返回Java,这样就有一个带有方法的类/接口,可以返回
R
类型或R?
类型。据我所知,我们不能在Kotlin中使用R显式声明平台类型代码>语法。我认为简单的解决方案是让CommonHandler的getResult返回可为null的结果,然后处理null返回,因为它是一个异常。至少一开始我是这么想的
因此,根据提示,我们将公共处理程序定义为
open class CommonHandler {
private fun doCoolStuffBefore() { /* do some cool stuff */
}
private fun doCoolStuffAfter() { /* do some cool stuff */
}
open fun <R> getResult(provider: Function0<R>): R? {
doCoolStuffBefore()
return try {
provider.invoke()
} finally {
doCoolStuffAfter()
}
}
}
开放类CommonHandler{
私人娱乐doCoolStuffBefore(){/*做一些很酷的事情*/
}
私人娱乐doCoolStuffAfter(){/*做一些很酷的事情*/
}
打开fun getResult(提供程序:函数0):R{
doCoolStuffBefore()
回击{
provider.invoke()
}最后{
doCoolStuffAfter()
}
}
}
NullableHandler不会更改,但会更改ThrowingHandler
class ThrowingHandler : CommonHandler() {
class WrappedException(message: String, cause: Throwable?): Exception(message, cause)
override fun <R> getResult(provider: Function0<R>): R {
return try {
super.getResult(provider) ?: throw AnotherWrappedException("whooops")
} catch(ex: Throwable) {
throw WrappedException("Throwing handler failed with exception: ${ex.javaClass.name}", ex)
}
}
}
class ThrowingHandler:CommonHandler(){
类WrappedException(消息:字符串,原因:可丢弃?):异常(消息,原因)
重写fun getResult(提供程序:函数0):R{
回击{
super.getResult(提供者)?:抛出另一个WrappedException(“Whoops”)
}捕获(例如:可丢弃){
抛出WrappedException(“抛出处理程序失败,异常:${ex.javaClass.name}”,ex)
}
}
}
如果值不为null,则使用elvis运算符返回值;如果值为null,则抛出另一个WrappedException(“Whoops”)
你觉得怎么样?它能为您工作吗?我认为简单的解决方案是让CommonHandler的getResult返回可为null的结果,然后处理null返回,因为它是一个异常。至少一开始我是这么想的 因此,根据提示,我们将公共处理程序定义为
open class CommonHandler {
private fun doCoolStuffBefore() { /* do some cool stuff */
}
private fun doCoolStuffAfter() { /* do some cool stuff */
}
open fun <R> getResult(provider: Function0<R>): R? {
doCoolStuffBefore()
return try {
provider.invoke()
} finally {
doCoolStuffAfter()
}
}
}
开放类CommonHandler{
私人娱乐doCoolStuffBefore(){/*做一些很酷的事情*/
}
私人娱乐doCoolStuffAfter(){/*做一些很酷的事情*/
}
打开fun getResult(提供程序:函数0):R{
doCoolStuffBefore()
回击{
provider.invoke()
}最后{
doCoolStuffAfter()
}
}
}
NullableHandler不会更改,但会更改ThrowingHandler
class ThrowingHandler : CommonHandler() {
class WrappedException(message: String, cause: Throwable?): Exception(message, cause)
override fun <R> getResult(provider: Function0<R>): R {
return try {
super.getResult(provider) ?: throw AnotherWrappedException("whooops")
} catch(ex: Throwable) {
throw WrappedException("Throwing handler failed with exception: ${ex.javaClass.name}", ex)
}
}
}
class ThrowingHandler:CommonHandler(){
类WrappedException(消息:字符串,原因:可丢弃?):异常(消息,原因)
重写fun getResult(提供程序:函数0):R{
回击{
super.getResult(提供者)?:抛出另一个WrappedException(“Whoops”)
}捕获(例如:可丢弃){
抛出WrappedException(“抛出处理程序失败,异常:${ex.javaClass.name}”,ex)
}
}
}
如果值不为null,则使用elvis运算符返回值;如果值为null,则抛出另一个WrappedException(“Whoops”)
你觉得怎么样?它是否适用于您?如果您将返回类型定义为可为null的R:
开放类CommonHandler{
私人娱乐doCoolStuffBefore(){/*做一些很酷的事情*/
}
私人娱乐doCoolStuffAfter(){/*做一些很酷的事情*/
}
打开有趣的getResult(提供程序:()->R):R{
doCoolStuffBefore()
回击{
provider.invoke()
}最后{
doCoolStuffAfter()
}
}
}
然后可以将作用域缩小到子类中不可为null的R
class ThrowingHandler:CommonHandler(){
类WrappedException(消息:字符串,原因:可丢弃?):异常(消息,原因)
覆盖有趣的getResult(提供程序:()->R):R{
回击{
super.getResult(提供者)!!
}捕获(例如:可丢弃){
抛出WrappedException(“抛出处理程序失败,异常:${ex.javaClass.name}”,ex)
}
}
}
您的ThrowableMhandler假设API无法返回null,因此使用
代码>运算符,并让任何KotlinNPE包装在WrappedException中。这实际上比您已经拥有的要好,因为意外异常包含在包装器中,而不是冒泡到代码中其他地方的JavaNPE。如果您需要包装一个应该能够返回null的API,那么我认为您还需要一个NullableThrowingHandler。如果您将返回类型定义为nullable R:
开放类CommonHandler{
私人娱乐doCoolStuffBefore(){/*做一些很酷的事情*/
}
私人娱乐doCoolStuffAfter(){/*做一些很酷的事情*/
}
打开有趣的getResult(提供程序:()->R):R{
doCoolStuffBefore()
回击{
provider.invoke()
}最后{
doCoolStuffAfter()
}
}
}