Operatività ripetuta con eccezione generica

3

Sto cercando un modo per ottenere la logica di riprovare un'operazione in un unico metodo mantenendo i tipi di eccezione dell'operazione.

I.e., l'implementazione per riprovare un'operazione potrebbe essere simile a questa:

public void retriedOperation(Operable operable, int maxAttempts) throws Exception {
    for (int attempt = 0; attempt < maxAttempts; attempt++) {
        try {
            operable.doOperation();
            break;
        } catch (Exception e) {
            if (attempt + 1 > maxAttempts) {
                throw e;
            }
        }
    }
}

Questa implementazione è tuttavia in grado solo di generare un Exception non specificato e quindi di perdere molte informazioni.

Sfortunatamente, le eccezioni generiche possono né essere catturate né lanciare non essere catturate in Java, quindi qualcosa di simile

public void <ExceptionType extends Exception> retriedOperation(...) throws ExceptionType { ... }

consentirebbe solo di catturare un'eccezione non specifica, controllare se è del tipo giusto e poi lanciarlo. Ma se è di un altro tipo, non può essere lanciato con questa intestazione del metodo.

Esiste un modo per implementare una funzione di ripetizione generica che conserva eccezioni specifiche?

    
posta mschrimpf 20.05.2014 - 16:12
fonte

2 risposte

5

Unfortunately, generic Exceptions can neither be caught nor thrown in Java, thus something like ... is not possible.

Cambia in:

public void <T extends Exception> retriedOperation(...) throws T { ... }

E dovrebbe funzionare bene. Quando T è un'eccezione controllata, il compilatore si lamenterà in modo appropriato. Per es.

obj.<IOException>retriedOperation(...);

Impone il metodo circostante a gestire IOException o a dichiarare che lo lancia. Tuttavia, fintanto che Operable specifica che genera Exception , il tuo codice non funzionerà, poiché il metodo dovrebbe verificare se l'eccezione rilevata è di un tipo particolare che non conosce ancora. La vera soluzione è cambiare Operable per specificare l'eccezione che lancia:

class Operable<T extends Exception>

E ora puoi riscrivere il tuo metodo come

public <T extends Exception> void retriedOperation(Operable<T> operable, ...) throws T {
    ...
    } catch (Exception e) {
        if (e instanceof RuntimeException) {
            throw (RuntimeException) e;
        } else {
            throw (T) e;
        }
    }
    ...
 }

E tutto funzionerà bene, a condizione che Operable lanci solo un tipo di eccezione controllata. Se devi gestirne più di una, la soluzione diventerà un po 'brutta - dovrai passare un elenco di token di classe come argomento e verificare se l'eccezione rilevata è di un tipo compatibile per ognuno di essi. (In retrospettiva, questo non funzionerebbe come descritto. fai ha bisogno di token di classe, ma avresti bisogno di un sovraccarico del metodo per 2 eccezioni, 3 eccezioni, ecc. per ottenere il throws clause right.)

Infine, mi sembra che retriedOperation debba essere un metodo statico.

    
risposta data 20.05.2014 - 16:31
fonte
-1

Non sono uno sviluppatore Java, ma potrebbe comunque funzionare comunque per te.

Puoi provare a utilizzare l'operatore instanceof .

public void retriedOperation<T>(Operable operable, int maxAttempts) throws Exception {
    for (int attempt = 0; attempt < maxAttempts; attempt++) {
        try {
            operable.doOperation();
            break;
        } catch (Exception e) {
            if (!(e instanceof T) || attempt + 1 > maxAttempts) {
                throw e;
            }
        }
    }
}

Dove T è il tipo di eccezione che desideri consentire.

    
risposta data 20.05.2014 - 16:18
fonte

Leggi altre domande sui tag