5

有没有可以回滚Java代码的解决方法?

例如,我希望打印出下面的代码i = 1但不是2:(发生异常时)

int i = 1;
try {
    i = 2;
    int j = 10/0;
} catch (Exception ex) {}
System.out.print("i = " + i);

我不认为这种逻辑对程序员来说实际上是无用的。而且我认为这对于编译器来说并不难处理。

例如,它可以临时保存i = 1在内存中,并在发生异常后,将其值回滚到1而不是2. (例如,如果我们有回滚/捕获会更好)

4

7 回答 7

2

本质上,您需要对内存进行版本控制。这已经在一些研究中进行了探索,例如事务内存、对象图版本控制、对象数据库。

问题是正确地做比看起来更难。需要处理的典型问题有:

  • 你版本多少?整个可达对象图?感兴趣的子集?
  • 版本化和非版本化数据结构化之间的交互如何?
  • 那么在“可恢复块”中可能发生的其他操作呢?比如生成线程和读/写 IO。您要撤消该操作吗?你能?

事务性内存正慢慢成为一种主流机制,像 Clojure 这样的语言。然而,它需要一种特殊的设计来处理上述问题。Clojure 实现了很好的平衡,因为它本质上是功能性的,并且版本化的数据是明确标识的。向像 Java 这样的面向对象的命令式语言添加类似的特性并不是免费的。


您可能对以下链接/出版物感兴趣:

于 2012-11-08T08:50:09.230 回答
2

这个怎么样?

    int i = 1;
    int oldValue = 0;
    try {
        oldValue = i;
        i = 2;
        int j = 10 / 0;
    } catch (Exception ex) {
        i = oldValue;
    }
    System.out.print("i = " + i);
于 2012-11-08T08:08:11.163 回答
1

当然,你可以在你的catch街区里做到这一点。你试过吗?另外,永远不要让你的 catch 块为空。它从来都不是一个好主意。这样,您甚至都不知道是否发生了异常。

catch将您的块更改为:-

int i = 1;
int old = 0;
try {
    old = i;
    i = 2;
    int j = 10/0;
} 
catch (Exception ex) {
    i = old;
    e.printStackTrace();
}
System.out.print("i = " + i);

此外,捕获更具体的异常是一个好主意,而不是使用单个 catch 块来捕获所有异常。

在您的情况下,您应该 catchArithmeticException而不是Exception.

此外,在抛出异常之前跟踪 try 块中的所有更改是不切实际的。如果您有一些固定数量的变量,那么这没什么大不了的。但是考虑一下你不知道你的try块将如何操纵你的变量的情况。在这种情况下,您不能简单地,并且将状态回滚到您的 try 块之前的状态并不容易。

于 2012-11-08T07:55:35.420 回答
1

我同意...它是数据库的基本功能,对应于事务。当然这不应该是默认行为,而是标记为事务。然而:

该行为可以使用函数获得......并且让您的代码块使用局部变量进行计算,在发生错误时不返回结果。从函数修改全局变量是糟糕的编程。你想保存的结构,你应该自己保存它们

只有少数情况下这是可行的……想象一下文件写入……或者更糟糕的是,网络传输……这些不可能回滚

更重要的是,您的情况很简单...但是在循环中编辑图像或大型数组的图像...您真的希望编译器“以防万一”复制它吗?

于 2012-11-08T08:06:54.760 回答
0

我不知道为什么没有人建议它。如果你想回滚,那么只需使用一个函数

public int performOperation(int i) throws CustomException {
    try {
        i = 2;
        int j = 10 / 0;
    } catch (Exception ex) {
        // Handle exception here.
        throw new CustomException();
    }
    return i;
}

public void calculate() {
    int i = 1;
    try {
        i = performOperation(i);//I will not be assigned if exception occurs
    } catch (CustomException e) {
        // Handle exception here.
    }
    System.out.println(i);//i will be always 1 here
}

因为 java 是按值传递的,所以i内部调用方法永远不会改变。不需要回滚。

于 2012-11-08T09:30:21.910 回答
0

回滚的替代方法是在可能引发异常的代码之后才“提交”状态更改:

int i = 1;
try {
    // initialize temporary state with current state
    int newState = i;

    // have actual operation using the temporary state
    newState = 2;
    int j = 10 / 0;

    // commit temporary state with code which can not throw exceptions
    i = newState;

} catch (ArithmeticException ex) { // catch only the expected exception!
    /* Add possible error reporting or whatever needs to be done */
}

System.out.print("i = " + i);
于 2012-11-08T08:20:34.407 回答
0

不,这是不可能的。如果你有一个用例,你当然可以编写一个自定义类。这是一个简单的例子(不处理许多边缘情况)。

public class MemoryInt {
    private int current;
    private int last;

    public MemoryInt(int value) {
        this.current = value;
        this.last = null;
    }

    public int get() {
        return current;
    }

    public int set(int value) {
        this.last = current;
        this.current = value;
    }

    public void rollback() {
        this.current = last;
        this.last = null;
    }
}
于 2012-11-08T08:07:04.793 回答