java 在异步回调内捕获异常

huangapple go评论61阅读模式
英文:

java Catch exception inside a async callback

问题

以下是翻译好的内容:

我有一个可能抛出自定义异常的回调函数。
我尝试抛出它,但它在外部范围内没有被捕获,编译器也不允许我捕获它,它说:“在相应的 try 块中从未抛出异常”,尽管实际上是抛出了。

这是我的代码:

public void openAsync(MessageAsyncCallback callback) {
    try {
        this.sendChannelOpen(this.getChannel(), getChannelOpenData().getFlags(), new MessageAsyncCallback() {
            @Override
            public void onComplete() throws NanoException {
                // INanoPacket message = transport.getMessageByClassName(AudioServerHandshake.class.getName());
                INanoPacket message = transport.getMessageByClassName(AudioClientHandshake.class.getName());
                Log.info("已收到音频服务器握手,尝试进行客户端握手");
                sendClientHandshakeAsync((AudioServerHandshake) message, callback);
            }
        });
    } catch (NanoException e) {
        System.exit(-2);
    }
}

但它不允许我捕获 NanoException

编辑:
transport.getMessageByClassName 内部,我抛出了一个 NanoException

编辑2:
这是调用异常的方法:

public INanoPacket getMessageByClassName(String destClassName) throws NanoException {
    long startTime = System.currentTimeMillis(); // 获取开始时间
    INanoPacket message = this.getMessageFromTCPQueue();

    while (!(message.getClass().getName().equals(destClassName)) && isRuntimeValid(startTime)) {
        this.insertToTCPQueue(message); // 将消息放回队列
        message = this.getMessageFromTCPQueue();
    }

    if (!(message.getClass().getName().equals(destClassName))) {
        // 超时...
        throw new NanoException("无法找到目标消息:" + destClassName);
    }

    return message;
}

我想处理异常甚至不仅在 openAsync 方法中,还在调用 openAsync 的方法中处理。
为什么呢? 因为我正在处理来自远程设备的消息,这就是为什么它是异步的。我使用了某种超时来等待特定消息,如果消息没有到达,我希望重新启动整个程序。

英文:

I have a callback which may throw a custom exception.
I'm trying to throw it, but it's not being catched on the outer scope, nor the compiler let me catch it, it says: "Exception is never thrown is the corresponding try block", even though it is.

this is my code:

public void openAsync(MessageAsyncCallback callback) {
        try {
            this.sendChannelOpen(this.getChannel(), getChannelOpenData().getFlags(), new MessageAsyncCallback() {
                @Override
                public void onComplete() throws NanoException {
//                INanoPacket message = transport.getMessageByClassName(AudioServerHandshake.class.getName());
                    INanoPacket message = transport.getMessageByClassName(AudioClientHandshake.class.getName());
                    Log.info("Got audio server handshake, trying to client-handshake it");
                    sendClientHandshakeAsync((AudioServerHandshake) message, callback);
                }
            });
        } catch (NanoException e) {
            System.exit(-2);
        }
    }

and it doesn't let me catch NanoException

EDIT:
inside transport.getMessageByClassName I throw a NanoException.

EDIT2:
this is the method who invokes the exception:

public INanoPacket getMessageByClassName(String destClassName) throws NanoException {//} throws NanoException {
        long startTime = System.currentTimeMillis(); // fetch starting time
        INanoPacket message = this.getMessageFromTCPQueue();

        while (!(message.getClass().getName().equals(destClassName)) && isRuntimeValid(startTime)) {
            this.insertToTCPQueue(message); // put message back in queue
            message = this.getMessageFromTCPQueue();
        }

        if (!(message.getClass().getName().equals(destClassName))) {
            // timeout...
            throw new NanoException("Couldn't find destination message: " + destClassName);
        }

        return message;
    }

and I want to handle the exception not even in openAsync but on the method that calls openAsync.
why? because I'm handling messages coming from a remote device, this is why it's async. and I'm using some kind of timeout to wait for a specific message, and if the message isn't coming I want to restart the whole program.

答案1

得分: 1

请注意,在您的代码中,您没有调用onComplete方法,您只是在定义它。

异常将在代码的另一个部分中抛出,可能是单独的Thread(因为它似乎是异步的)。因此,“在相应的try块中永远不会抛出异常”消息是正确的,因为在调用this.sendChannelOpen(...)方法时永远不会抛出异常。

您的try-catch语句需要包装调用onComplete方法的地方。只有通过调用onComplete方法,您才能期望出现NanoException

根据评论进行编辑:
如果您需要处理在getMessageByClassName中抛出的异常,您可以在onComplete方法中处理它,而不是重新抛出它。如果您想在其他地方处理它,您需要提供我们sendChannelOpen方法的代码或回调被调用的地方。

根据问题的编辑进行第二次编辑:
请查看下面的代码,这是一个示例,演示了如何在线程之间进行通信。我使用了Latch,但是在java.util.concurrent中还有其他您可能会发现有用的类。
顺便说一句,我不会讨论为什么您希望在出现NanoException时重新启动整个应用程序,尽管可能有其他值得考虑的从该异常中恢复的选项。

import java.util.concurrent.CountDownLatch;

class NanoException extends Exception {}

interface MessageAsyncCallback {
    void onComplete() throws NanoException;
}

public class AsyncApp {
    private static final CountDownLatch errorLatch = new CountDownLatch(1);
    public static void main(String[] args) {
        new AsyncApp().run();
    }

    void run() {
        sendChannelOpen("something", new MessageAsyncCallback() {
            @Override
            public void onComplete() throws NanoException {
                // the whole try-catch-sleep is not really needed, just to wait a bit before exception is thrown
                try {
                    // not needed, just to wait a bit before exception is thrown
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    throw new NanoException();
                }
                throw new NanoException();
            }
        });

        try {
            System.out.println("This is a main thread and we wait here, while the other thread executes...");
            errorLatch.await();
            System.out.println("Latch has reached 0, will now exit.");
            System.exit(-2);
        } catch (InterruptedException e) {
            System.out.println("Error in main thread.");
            System.exit(-1);
        }
    }

    void sendChannelOpen(String notImportant, MessageAsyncCallback troublesomeCallback) {
        runSomethingInSeparateThread(troublesomeCallback);
    }

    void runSomethingInSeparateThread(MessageAsyncCallback troublesomeCallback) {
        new Thread(() -> {
            try {
                troublesomeCallback.onComplete();
            } catch (NanoException e) {
                System.out.println("You can catch it here, and do system exit here or synchronize with main Thread as below");
                errorLatch.countDown();
            }
        }).start();
    }
}
英文:

Please notice that in your code you are not invoking onComplete method, you are defining it.

The exception would be thrown in a separate part of the code, possibly separate Thread (as it seems to be async). Therefore the "Exception is never thrown is the corresponding try block" message is right, as the exception will never be thrown when invoking this.sendChannelOpen(...) method.

Your try-catch statement needs to wrap the place where you invoke the onComplete method. As only by invoking onComplete method can you expect NanoException.

EDIT based on comments:
If you need to handle the exception throw in getMessageByClassName you can do it in onComplete method and not rethrow it. If you want to handle it somewhere else, you'd need to provide us the code of sendChannelOpen method or a place where the callback is invoked.

EDIT2 (based on question edits):
Please see the code below, as an example of how you can communicate between threads. I've used Latch, but there are other classes in java.util.concurrent that you may find useful.
BTW, I'm not going into the discussion why you want to restart the whole app on your NanoException, although there might be other options worth considering for recovering from that Exception.

import java.util.concurrent.CountDownLatch;
class NanoException extends Exception {}
interface MessageAsyncCallback {
void onComplete() throws NanoException;
}
public class AsyncApp {
private static final CountDownLatch errorLatch = new CountDownLatch(1);
public static void main(String[] args) {
new AsyncApp().run();
}
void run() {
sendChannelOpen("something", new MessageAsyncCallback() {
@Override
public void onComplete() throws NanoException {
// the whole try-catch-sleep is not really needed, just to wait a bit before exception is thrown
try {
// not needed, just to wait a bit before exception is thrown
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new NanoException();
}
throw new NanoException();
}
});
try {
System.out.println("This is a main thread and we wait here, while the other thread executes...");
errorLatch.await();
System.out.println("Latch has reached 0, will now exit.");
System.exit(-2);
} catch (InterruptedException e) {
System.out.println("Error in main thread.");
System.exit(-1);
}
}
void sendChannelOpen(String notImportant, MessageAsyncCallback troublesomeCallback) {
runSomethingInSeparateThread(troublesomeCallback);
}
void runSomethingInSeparateThread(MessageAsyncCallback troublesomeCallback) {
new Thread(() -> {
try {
troublesomeCallback.onComplete();
} catch (NanoException e) {
System.out.println("You can catch it here, and do system exit here or synchronize with main Thread as below");
errorLatch.countDown();
}
}).start();
}
}

huangapple
  • 本文由 发表于 2020年9月4日 22:06:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63742737.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定