Java 在';中创建可恢复的错误接口是否比处理恢复更有效;捕捉';
注意这个问题以观点为基础,所以我用更实际的方法重新提问 因此,正如标题所说,我不确定是应该尝试实现可恢复的错误类,还是继续尝试在Java 在';中创建可恢复的错误接口是否比处理恢复更有效;捕捉';,java,exception,try-catch,Java,Exception,Try Catch,注意这个问题以观点为基础,所以我用更实际的方法重新提问 因此,正如标题所说,我不确定是应该尝试实现可恢复的错误类,还是继续尝试在catch块中进行恢复 要演示的一些psuedo代码: // more or less what I have now postToServer(data) { try { socket.write(data) } //Interrupted being a custom exception catch(Interrupt
catch
块中进行恢复
要演示的一些psuedo代码:
// more or less what I have now
postToServer(data) {
try {
socket.write(data)
}
//Interrupted being a custom exception
catch(Interrupted ex) {
//happened twice is a common static method on all custom exceptions that returns a boolean indicating if the last thrown error is the same as this one
if(Interrupted.happenedTwice(ex)) throw ex;
else postToServer(data);
}
//another custom exception indicating that the network is unreachable
catch(NetworkDrop ex) {
if(!NetworkDrop.happenedTwice(ex) && !reconnectToServer()) throw ex;
else postToServer(data);
}
}
//What I would like to implement
interface Recoverable {
public void recover(Runnable) throws Exception;
}
class NetworkDrop extends Exception implements Recoverable {
...
public void recover(Runnable resume) {
if(!NetworkDrop.happenedTwice(this) && reconnectToServer()) resume.run();
else throw this;
}
}
class Interrupted extends Exception implements Recoverable {
...
public void recover(Runnable resume) {
if(!Interrupted.happenedTwice(this)) resume.run();
else throw this;
}
}
postToServer(data) throws Exception {
try {
socket.write(data)
}
catch(Recoverable ex) {
ex.recover(() -> postToServer(data));
}
}
作为示例,我希望所有的恢复代码都在异常中(减少重复代码,正如现在所说的,5种不同的方法可以调用recover
,而不是运行相同的恢复代码)。这将允许我捕获可以恢复的异常,但仍然抛出不可恢复的异常,或者在无法恢复时抛出异常
但我认为这有一个问题:
当从恢复中调用的中间Runnable
不返回数据时,如何在预期返回数据的方法中恢复?
假设我正在从服务器读取而不是写入,并获得一个可恢复的异常(如NetworkDrop)并成功恢复。由于执行是通过recover方法上的Runnable恢复的,并且Runnable不返回任何内容,那么调用read的函数如何从Runnable中获取数据呢
那么,这个系统会比多个捕获更有效吗?或者说,仅仅捕获可恢复异常所带来的可读性和简单性是一把双刃剑
如果折衷有利于可恢复类,我将如何解决从恢复的异常中获取返回值的问题?异常意味着在调用堆栈上进行故障通信。抛出异常尤其支持这样一种特性,即在某个嵌套调用失败后,调用方通常不想继续,而是在堆栈的更上层发出失败信号
因此,在接收到异常后,调用方跳过其方法体的其余部分,并向其调用方发出失败信号,这在所有调用堆栈中都会发生,直到您找到具有适当的catch
块的位置
瑕疵
您的Recoverable
异常将破坏该系统。如果我理解正确,恢复是一个双重过程:异常包含如何重新建立连接的代码,可运行由catch块提供,负责修复由于异常而跳过的代码行
但是由于跳过的代码将来自多个嵌套的调用层,我认为您无法可靠地提供有效的恢复代码
当然,如果您准备在每个软件层上用try/catch来包围每一行业务代码,这会变得更容易,但这与异常处理的精神相矛盾
为了确立您的概念,您无论如何都需要确定可能发生可恢复故障的所有位置—您必须抛出可恢复的
异常,通常会包装一些原始异常。这是另一种方法的关键
暗示
我建议使用不同的方法:
在所有抛出可恢复异常的地方,您都知道可以从故障中恢复。因此,我将在那里实现这些知识,而不是让方法失败,而是立即应用恢复策略,这样您就可以成功地返回
如果您担心恢复失败会浪费太多的尝试,请查看“断路器”模式。这听起来过于复杂,通常比try-catch更糟糕。请参考您的示例“我可以使用Runnable调用recover,它将重试上一个操作,这将检查文件访问,创建父目录”,然后我的问题是-如果您认为权限可能错误,或者目录不存在,为什么在尝试访问文件之前不确定它们是否存在?例外情况适用于例外情况。“在访问文件之前不检查文件是否存在”也不例外。@Michael我理解你的意思。这可能是个坏例子,但很容易想到;)我认为这对于嵌入式环境中的线程任务非常有用,因此我将以它为例,例如发送SPI设备数据,设备处于坏状态,因此通过强制设备重新启动来恢复,并在设备重新启动时调用runnable。如果这是个坏主意,回答是这样的,为什么会这样,以便其他人可以引用它,我会接受它。我认为我们需要看到实际的代码,才能做出任何明智的判断。我明白你的意思,我的直觉是,这不是一个好方法,但要准确地解释为什么我需要用一些具体的例子来演示。如果你寻找更好的错误处理方法的想法和灵感,我个人的建议是阅读有关将你的应用程序建模为管道/操作图的框架(参与者模型、反应流)或函数编程。例如,您可以阅读(我认为重试运算符特别接近您的初始问题)。感谢您提供了一篇内容丰富的帖子!这篇文章的信息量和帮助性要比其他人只是询问您为什么要这样做,并说他们不理解,所以不要这样做。我的印象是,异常是当今最不被理解的软件功能。即使是著名的教程通常也只涉及异常的机制,而不是异常的灵魂。因此我试着分享我的理解,希望它能被证明是有用的。非常感谢,好先生。我在这里更真实地问了我的问题:你能检查一下并提供反馈吗?只是为了第二个意见哈哈