Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

为 java 添加 EventChannel.exceptionHandler( <Java 友好型空返回 lambda> ) #1953

Closed
JiHongYuan opened this issue Mar 29, 2022 · 2 comments
Labels
M 优先级: 主要 s:core 子系统: mirai-core t:problem 类型: 不容易归类为特性或 bug 的综合问题
Milestone

Comments

@JiHongYuan
Copy link

问题描述

Java exceptionHandler方法遇到的编译问题

复现

语言

JAVA11

问题描述

在使用exceptionHandler方法时:

 Listener<Event> eventListener = GlobalEventChannel.INSTANCE
                    .exceptionHandler(e -> e.printStackTrace())
                    .subscribeAlways(handler.getHandlerEvent(), handler::onEvent);

出现了一些错误,如下述:

Bad return type in lambda expression: void cannot be converted to Unit java.lang.Throwable

文档实现

// https://github.com/mamoe/mirai/blob/dev/docs/Events.md#%E6%B7%BB%E5%8A%A0-coroutinecontext
channel.exceptionHandler(exception ->
    logger.error(exception);
);

我做了

一、尝试使用idea推荐方法

public void start() {
    for (EventHandler<Event> handler : handlers) {
        Listener<Event> eventListener = GlobalEventChannel.INSTANCE
                // 这里
                .exceptionHandler((coroutineContext, throwable) -> {
                    throwable.printStackTrace();
                })
                .subscribeAlways(handler.getHandlerEvent(), handler::onEvent);
        listeners.add(eventListener);
    }
}

但是编译期间报了奇怪的错误:

java: 对于exceptionHandler((coroutine[...](); }), 找不到合适的方法
    方法 net.mamoe.mirai.event.EventChannel.exceptionHandler(kotlinx.coroutines.CoroutineExceptionHandler)不适用
      (参数不匹配; kotlinx.coroutines.CoroutineExceptionHandler 不是函数接口
          在 接口 kotlinx.coroutines.CoroutineExceptionHandler 中找到多个非覆盖抽象方法)
    方法 net.mamoe.mirai.event.EventChannel.exceptionHandler(kotlin.jvm.functions.Function1<? super java.lang.Throwable,kotlin.Unit>)不适用
      (参数不匹配; lambda 表达式中的参数类型不兼容)

二、以匿名内部类的方式

Listener<Event> eventListener = GlobalEventChannel.INSTANCE
  .exceptionHandler(new CoroutineExceptionHandler() {
      @Override
      public void handleException(@NotNull CoroutineContext coroutineContext, @NotNull Throwable throwable) {
  
      }
  })
.subscribeAlways(handler.getHandlerEvent(), handler::onEvent);

同样编译期间报了奇怪的错误:

java: <匿名org.github.palace.bot.core.EventDispatcher$1>不是抽象的, 并且未覆盖kotlin.coroutines.CoroutineContext.Element中的抽象方法minusKey(kotlin.coroutines.CoroutineContext.Key<?>)

三、偶然间

在翻遍各路搜索引擎之后,偶然间在stackoverflow中找到了这个解决方案:

.exceptionHandler(e -> {
    LOGGER.error(e.getMessage());
    return Unit.INSTANCE;
})

我不确定,这对我后续的异常处理有影响吗

mirai-core 版本

2.9.1

bot-protocol

ANDROID_PHONE

其他组件版本

No response

系统日志

No response

网络日志

No response

补充信息

No response

@Karlatemp Karlatemp added s:core 子系统: mirai-core t:problem 类型: 不容易归类为特性或 bug 的综合问题 labels Mar 29, 2022
@Karlatemp Karlatemp changed the title Java exceptionHandler方法遇到的编译问题 为 java 添加 EventChannel.exceptionHandler( <Java 友好型空返回 lambda> ) Mar 29, 2022
@Karlatemp
Copy link
Member

Karlatemp commented Mar 29, 2022

关于此问题, 由于项目是使用 kotlin 编写的, 所以关于这种 lambda 我们并没有过多考虑

EventChannel 的 exceptionHandler 有以下目前两个定义

public fun exceptionHandler(coroutineExceptionHandler: CoroutineExceptionHandler)

public fun exceptionHandler(coroutineExceptionHandler: (exception: Throwable) -> Unit)

其中 CoroutineExceptionHandler 为底层 Kotlin 携程库中的错误异常处理器原型定义
(exception: Throwable) -> Unit 是我们为了代码简洁添加的 lambda 参数

CoroutineExceptionHandler

由于 CoroutineExceptionHandler 的抽象方法不止一个所以您使用 (coroutineContext, throwable) -> 时会遇到编译问题.

如果您希望使用 CoroutineExceptionHandler 您可以使用以下的代码

class CusEH extends AbstractCoroutineContextElement implements CoroutineExceptionHandler {
    CusEH() { super(CoroutineExceptionHandler.Key); }
    public void handleException(@NotNull CoroutineContext coroutineContext, @NotNull Throwable throwable) {}
}

(exception: Throwable) -> Unit

(exception: Throwable) -> Unit 在 jvm 中的定义原型为

package kotlin.jvm.function;
public interface Function1<E, R> {
   R invoke(E);
}

kotlin.Unit 在 kotlin 中的意义为 Void, 即 空. 所以 .exceptionHandler(e -> Unit.INSTANCE ) 的写法是正确的. 并且不建议直接返回 null, 因为 kotlin 有空检查

@JiHongYuan
Copy link
Author

非常感谢回复!

按照您方法已经解决了这个问题。

@Him188 Him188 added the M 优先级: 主要 label Apr 2, 2022
@Him188 Him188 added this to the 2.12 milestone Apr 2, 2022
@Him188 Him188 modified the milestones: 2.12, 2.12.0-RC May 8, 2022
@Him188 Him188 closed this as completed in 1a2241b Jun 8, 2022
cssxsh pushed a commit to SkyNet1748/mirai that referenced this issue Jul 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
M 优先级: 主要 s:core 子系统: mirai-core t:problem 类型: 不容易归类为特性或 bug 的综合问题
Projects
None yet
Development

No branches or pull requests

3 participants