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ロールバックされる可能性があります。(たとえば、ロールバック/キャッチがあればもっと良いでしょう)12

4

7 に答える 7

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 に答える
2

基本的に、メモリをバージョン管理する必要があります。これは、トランザクション メモリ、オブジェクト グラフのバージョン管理、オブジェクト データベースなど、いくつかの研究で調査されています。

問題は、見た目よりも正しく行うのが難しいことです。対処すべき一般的な重要な問題は次のとおりです。

  • バージョンはどのくらいですか?到達可能なオブジェクトグラフ全体? 関心のあるサブセットですか?
  • バージョン管理されたデータとバージョン管理されていない構造化データの間の相互作用についてはどうですか?
  • スレッドの生成やIOの読み取り/書き込みなど、「回復可能なブロック」内で発生する可能性のある他の操作についてはどうですか。元に戻しますか?あなたはできる?

トランザクショナル メモリは、Clojure などの言語によって、ゆっくりと主流のメカニズムになりつつあります。ただし、上記の問題に対処するには特別な種類の設計が必要です。Clojure は本質的に機能的であり、バージョン管理されたデータが明示的に識別されるため、バランスが取れています。Java のようなオブジェクト指向の命令型言語に同様の機能を追加するのは無料ではありません。


次のリンク/出版物に興味があるかもしれません:

于 2012-11-08T08:50:09.230 に答える
1

そうですね… トランザクションに対応する、データベースの必須機能です。もちろん、これはデフォルトの動作ではなく、トランザクションとしてマークされるべきです。でも:

動作は関数を使用して取得できます...そして、エラーの場合に結果を返さずに、ローカル変数を使用してコードブロックを計算します。関数からグローバル変数を変更するのは貧弱なプログラミングです。保存したい構造は、自分で保存する必要があります

これが実行可能なケースは限られています...ファイルの書き込みを想像してみてください...さらに悪いことに、ネットワーク転送...これらはロールバックできません

さらに、あなたのケースは単純です...しかし、ループ内の画像または大きな配列の画像編集...「念のため」コンパイルにコピーを取得させたいですか?

于 2012-11-08T08:06:54.760 に答える
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 ブロックですべての例外をキャッチするよりも、より具体的な例外をキャッチすることをお勧めします。

あなたの場合、ArithmeticExceptionではなくキャッチする必要がありますException

また、例外がスローされる前に、try ブロックで行われたすべての変更を追跡することは実際的ではありません。固定数の変数がある場合、それは大したことではありません。tryしかし、ブロックが変数を操作する方法がわからない場合を考えてみてください。その場合、簡単にはできず、try ブロックの前の状態にロールバックすることは容易ではありません。

于 2012-11-08T07:55:35.420 に答える
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 に答える
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 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 に答える