Consigli per l'aggiunta di messaggi di eccezione al codice [chiuso]

5

Il "problema" che sto avendo adesso è piuttosto semplice, sto creando un codice con MOLTE convalide, nel caso in cui uno di questi fallisca dovrebbe generare un'eccezione.

Per rendere espliciti i messaggi in favore della descrizione del motivo dell'eccezione, devo scrivere una quantità "considerevole" di testo. Questo non sarebbe un problema se ci fossero solo un paio di eccezioni, ma ora sono in rotta diretta per finire con un file con più testo (per i messaggi di eccezione) rispetto al codice.

Mi piacerebbe avere alcuni suggerimenti / alternative per mettere tutto quel testo fuori dal mio codice (stavo pensando di averlo nelle variabili nella parte superiore del file ma non è molto intelligente "memoriwise-able" parlando).

Esempio

if (operator.isBitwiseOperator()) {
    // >>=, <<=, &=, |=, ^=
    if (!(IntegerStmt.isAnIntegerAsignableClass(fstOpClass)
            && IntegerStmt.isAnIntegerAsignableClass(sndOpClass))) {
        if ((operator.equals(Operator.AND_ASSIGN)
                || operator.equals(Operator.OR_ASSIGN)
                || operator.equals(Operator.XOR_ASSIGN))
                    && !(LogicalInfo.isBoolean(fstOpClass)
                        && LogicalInfo.isBoolean(sndOpClass))) {
                    throw new UnsupportedOperationException(
                            "In order to use a bitwise logical assign "
                                    + "operator (&=, |=, ^=) it is "
                                    + "necessary booth operands to be "
                                    + "either an integer assignable type "
                                    + INTEGER_ASSIGNABLE_VALUES 
                                    + " or a logical boolean value " 
                                    + "(b/Boolean)");
        } else {
            throw new UnsupportedOperationException(
                            "In order to use a bitwise assign operator it is "
                                    + "necessary booth operands to be an "
                                    + "integer assignable type "
                                    + INTEGER_ASSIGNABLE_VALUES);
        }
    }
}

Ora, come quell'esempio che mostra che ho "alcune" eccezioni che considero non terribilmente lunghe, ne ho molte, quindi da una goccia all'altra sto riempiendo il bicchiere: / ...

    
posta Ordiel 04.11.2015 - 17:35
fonte

3 risposte

4

Inizierò con la raccomandazione di leggere "Codice pulito" di Robert Martin . Se seguiamo i suggerimenti di quel libro, potresti:

  • interrompe quell'enorme albero se in parti più piccole di codice
  • inserisce le eccezioni di lancio in metodi privati alla fine dei file

E quella sarebbe la soluzione al tuo problema. In questo modo, il testo non interferirà con la logica.

Qualcosa del genere:

if (operator.isBitwiseOperator()) {
    // >>=, <<=, &=, |=, ^=
    if (!(IntegerStmt.isAnIntegerAsignableClass(fstOpClass)
            && IntegerStmt.isAnIntegerAsignableClass(sndOpClass))) {
        if ((operator.equals(Operator.AND_ASSIGN)
                || operator.equals(Operator.OR_ASSIGN)
                || operator.equals(Operator.XOR_ASSIGN))
                    && !(LogicalInfo.isBoolean(fstOpClass)
                        && LogicalInfo.isBoolean(sndOpClass))) {
            ThrowExceptionForNotIntTypes();

        } else {
            ThrowExceptionForIncopatibleTypes();
        }
    }
}


private void ThrowExceptionForNotIntTypes() {
  throw new UnsupportedOperationException(
                            "In order to use a bitwise logical assign "
                                    + "operator (&=, |=, ^=) it is "
                                    + "necessary booth operands to be "
                                    + "either an integer assignable type "
                                    + INTEGER_ASSIGNABLE_VALUES);
}

private void ThrowExceptionForIncopatibleTypes() {
  throw new UnsupportedOperationException(
                            "In order to use a bitwise assign operator it is "
                                    + "necessary booth operands to be an "
                                    + "integer assignable type "
                                    + INTEGER_ASSIGNABLE_VALUES);
}
    
risposta data 04.11.2015 - 18:29
fonte
3

I messaggi di eccezione buona sono importanti. Tuttavia, i messaggi di eccezione generati da una parte di codice potrebbero non essere sempre adatti per un utente finale. È quindi possibile rinviare la costruzione di un messaggio di errore a un livello esterno. Le tue eccezioni dovrebbero invece contenere tutti i dati necessari per costruire un messaggio. Ciò implica che crei classi di eccezioni specifiche per le applicazioni sufficienti.

Se si sta creando una libreria invece di un'applicazione, le gerarchie di eccezioni a grana fine sono più utili della possibilità di aggiungere un livello di localizzazione dei messaggi di errore, ma un po 'di astrazione sarà comunque molto utile. In particolare, il codice comune dovrebbe essere scomposto. Nel tuo caso, entrambi i messaggi hanno una struttura sintattica molto simile. È quindi possibile creare un modello di messaggio e semplicemente compilare gli spazi vuoti quando si genera un'eccezione. O potresti creare una funzione di supporto che crea un'eccezione.

Vorrei riscrivere il tuo codice come

// making the exception format public makes testing easier
public static final String BITWISE_ASSIGN_ERROR_MESSAGE_FORMAT = "In order to use %1s it is necessary that both operators be %2s"

...

// >>=, <<=, &=, |=, ^=
if (operator.isBitwiseOperator()) {
    checkBitwiseOperator(...);
}

...

private void checkBitwiseOperator(...) {
    bool operandsAreIntegerAssignable =
         IntegerStmt.isAnIntegerAsignableClass(fstOpClass)
      && IntegerStmt.isAnIntegerAsignableClass(sndOpClass);  
    bool operandsAreBoolean =
         LogicalInfo.isBoolean(fstOpClass)
      && LogicalInfo.isBoolean(sndOpClass)
    bool operatorIsLogicalAssign =
         operator.equals(Operator.AND_ASSIGN)
      || operator.equals(Operator.OR_ASSIGN)
      || operator.equals(Operator.XOR_ASSIGN);

    // special-case &=, |=, ^= – they can be integer or boolean
    if (operatorIsLogicalAssign && !operandsAreBoolean) {
        if (operandsAreInteger || operandsAreBoolean)
            return;

        throw new UnsupportedOperationException(
            String.format(BITWISE_ASSIGN_ERROR_MESSAGE_FORMAT, 
                "a bitwise logical assignment operator (&=, |=, ^=)", 
                "either integer assignable " + INTEGER_ASSIGNABLE_VALUES + " or a boolean value"));
    }

    // the shift-assignment operators can only work on integers
    if (operandsAreIntegerAssignable)
      return;

    throw new UnsupportedOperationException(
        String.format(BITWISE_ASSIGN_ERROR_MESSAGE_FORMAT,
            "bitwise assignment operator",
            "integer assignable " + INTEGER_ASSIGNABLE_VALUES));
}

Il prossimo passo sarebbe quello di estrarre la costruzione del messaggio. Nota che il tuo codice esegue essenzialmente il controllo dei tipi, quindi potremmo creare una classe di eccezioni speciale per questo. Potrebbe mostrare il codice circostante, stampare il numero della linea e spiegare i tipi. Questo diventa più potente quando si dispone di un modello esplicito sufficiente delle operazioni disponibili. Questo potrebbe ad es. ti consente di creare un'eccezione come

throw new TypeError(expectedType, actualType, expression.sourceInfo());

e ottieni un messaggio di errore creato da quel tipo di eccezione come

inputFile:32:6: TypeError
expected operator |= (Int left, Int right)
      or operator |= (Bool left, Bool right)
but found "x" of type String
      and "y + 2" of type Int
here:
foo(x |= y + 2)
    ~~^~~~~~~~

Questo è estremamente facile da usare, ma difficile da ottenere (per i principianti, è necessario un modello effettivo del sistema di tipi nel codice e un meccanismo per connettere i tipi con frammenti di codice sorgente).

    
risposta data 04.11.2015 - 19:12
fonte
2

Lancia un codice di errore, quindi usalo per cercare il testo lungo. Quel testo potrebbe anche essere inserito in un file di risorse specifiche della locale.

Detto questo, avrei lanciato anche un breve messaggio di errore leggibile dall'uomo, in modo tale che un registro di lettura dell'amministratore sarebbe in grado di capire quale errore fosse senza doverlo cercare.

    
risposta data 04.11.2015 - 18:43
fonte

Leggi altre domande sui tag