10
votes

Détecter une exception dans Autoclosable Fermer ()

Je veux construire une classe CUSTOCLOSIBLE Autoclosable , afin que je puisse transformer ceci: xxx

dans la facilité xxx

transaction serait le autoclogeable ici et dans close () Il engagerait ou retourne la transaction comme approprié. < P> Mais pour faire ce travail, je devrais détecter dans transaction.close () si une exception s'est produite à l'intérieur du bloc d'essai ou complétée normalement. Est-ce possible du tout?

Si cela nécessite d'analyser la trace de la pile à partir d'une nouvelle exception, c'est bon. La programmation plus facile aurait la peine de toucher la petite performance qui apporte.


3 commentaires

Je pense que l'essai avec les ressources est spécifiquement destiné à gérer le cas où la configuration et le nettoyage d'une ressource se lancent eux-mêmes des exceptions, conduisant au redouté enfin {essayer {if (ressource! = Null) {ressource.frose () ... bloc. Ce n'est pas censé être les gestionnaires de contexte de Python.


@Inderdial peut-être, mais s'il est possible (que cette question montrait, espérons-le), je ne suis pas contre les abuser d'un tel but.


Par "précisément", je voulais dire que j'ai écrémé la spécification et aussi loin que possible, tout ce qui se passe est que le bytecode correspondant aux blocs de configuration / nettoyage est généré, avec les points uniquement points sur lesquels vous pouvez accrocher En étant l'initialiseur et la mise en œuvre de autoclotionable.Close , qui ne accepte aucun paramètre d'exception.


3 Réponses :


6
votes

Le plus proche que je puisse arriver, il est toujours nécessaire de marquer le succès de la transaction manuellement comme la dernière instruction du bloc:

class Transaction implements AutoCloseable {
    private boolean rollback = true;

    public void success() {
        rollback = false;
    }

    public void close() {
        if (rollback) doRollback();
        else doCommit();
        // …
    }
}

class Main {
    public static void main(String[] args) {
        try (Transaction t = new Transaction()) {
            doThings();
            t.success();
        }
    }
}


0 commentaires

1
votes

Bien que mon code soit différent de la vôtre, j'ai eu un besoin similaire pour commettre automatiquement les transactions (la plupart) transactions et la restauration sur les erreurs.

La plupart du temps mon code est saupoudré de simples requêtes qui se font rouler automatiquement, comme ça : P>

try(Transaction t : database.beginReadOnlyTransaction()) {
  return t.selectUnique(Employee.class, "id=?", 200);
}  // implicit commit here


0 commentaires

0
votes

Le plus proche que j'ai pu obtenir est d'appeler explicitement commettre () et de supposer que n'importe quel code qui quitte le bloc de transaction sans le faire devrait être renvoyé. Ceci est cohérent avec les transactions dans d'autres langues. Pendant que vous pouvez oublier d'appeler commettre () (comme je le fais souvent), au moins cette partie du code est très probablement testée. Et, il est impossible d'oublier de retourner à l'exception, ce qui est moins susceptible d'avoir une couverture de test.

Ceci est similaire à l'idée de Millimoose de définir un drapeau: p> xxx pré>

sauf que vous utilisez simplement l'état actif comme drapeau. Même quantité de code, aucun nouvel indicateur nécessaire. Cela suppose que toute transaction pour laquelle commit () n'a pas été explicitement appelée doit être renvoyée, ce qui a entraîné un code comme celui-ci: P>

try (Transaction t = new Transaction()) {
    doThings();
    t.commit(); // marks the transaction as successful...
}

class Transaction implements AutoCloseable {
    public void close() {
        if (isActive())
            doRollback();
    }

    ...
}


0 commentaires