Care este modalitatea corectă de a gestiona o excepție NumberFormatException atunci când este așteptată? (Programare, Java, Excepție, Încercați Să Prindeți, Numberformatexception)

Erick Robertson a intrebat.
a intrebat.

Mă confrunt cu situația în care trebuie să analizez un fișier String într-un int și nu știu ce să fac cu NumberFormatException. Compilatorul nu se plânge atunci când nu-l prind, dar vreau doar să mă asigur că mă ocup de această situație în mod corespunzător.

private int getCurrentPieceAsInt() {
    int i = 0;
    try {
        i = Integer.parseInt(this.getCurrentPiece());
    } catch (NumberFormatException e) {
        i = 0;
    }
    return i;
}

Vreau doar să simplific codul meu astfel. Compilatorul nu are nicio problemă cu asta, dar firul moare la momentul NumberFormatException.

private int getCurrentPieceAsInt() {
    int i = 0;
    i = Integer.parseInt(this.getCurrentPiece());
    return i;
}

Google CodePro vrea ca eu să înregistrez excepția într-un fel sau altul, și sunt de acord că aceasta este cea mai bună practică.

private int getCurrentPieceAsInt() {
    int i = 0;
    try {
        i = Integer.parseInt(this.getCurrentPiece());
    } catch (NumberFormatException e) {
        i = 0;
        e.printStackTrace();
    }
    return i;
}

Vreau ca această metodă să returneze 0 atunci când piesa curentă nu este un număr sau nu poate fi analizată. Atunci când nu prind excepția NumberFormatException în mod explicit, nu se atribuie variabila i? Sau există o valoare implicită pe care Integer.parseInt() se returnează?

Stilul general spune că, dacă prind o excepție, ar trebui să o înregistrez undeva. Eu nu vreau să o înregistrez. Este o operațiune normală ca această excepție să fie aruncată uneori, ceea ce, de asemenea, nu-mi convine. Nu găsesc însă o funcție care să îmi spună dacă Integer.parseInt() va arunca o excepție. Așa că singura mea cale de acțiune pare a fi să o sun și să prind excepția.

javadoc pentru parseInt nu mă ajută prea mult.

Iată întrebările specifice pe care aș dori să le știu:

  • Există o metodă pe care o pot apela și care îmi va spune dacă Integer.parseInt() va arunca un NumberFormatException înainte de a o apela? Atunci nu aș avea nicio problemă să înregistrez acest lucru, deoarece nu ar trebui să se întâmple niciodată.
  • Dacă pur și simplu nu prind excepția, valabilitatea nu va fi atribuită? Atunci îl voi inițializa pur și simplu la valoarea pe care o doresc atunci când nu este un număr și nu voi prinde excepția.
  • Există o modalitate de a marca cumva excepția în mod explicit că nu-mi pasă de ea? Mă gândesc că acest lucru ar fi ceva similar cu AWTEvent.consume(). Dacă da, atunci voi face acest lucru, astfel încât Google CodePro să nu vadă acest lucru ca fiind „unlogged”.

Comentarii

  • „Dacă pur și simplu nu prind excepția, valabilitatea nu va fi atribuită? Atunci pur și simplu nu voi prinde excepția.” – dacă nu sunteți sigur că aceasta este o opțiune viabilă, vă sugerez să o încercați (și să o parcurgeți cu un debugger) pentru a fi 100% sigur că înțelegeți ce se întâmplă în acest caz. Nu vreau să sune ca și cum aș vorbi de sus, dar consider că este important să aveți o înțelegere solidă a excepțiilor. –  > Por Bert F.
  • Nu sunt programator Java, dar în C#, Integer are o metodă TryParse() care încearcă să analizeze int-ul și returnează un bool pentru a ști dacă a reușit sau nu. Cu siguranță că este mai bine decât să aștepți o excepție. –  > Por Ash Burlaczenko.
  • Mi-ar plăcea dacă ar exista o metodă tryParse() metodă. Cred că înțeleg de ce nu există una, deoarece practic înseamnă să faci munca de două ori. De asemenea, atunci când o încerc, se produce uncaught NumberFormatException ucide firul pe loc. Am actualizat întrebarea pentru a reflecta acest lucru. –  > Por Erick Robertson.
8 răspunsuri
Cameron Skinner
  • Există o metodă pe care o pot apela care îmi va spune dacă Integer.parseInt() va arunca o excepție NumberFormatException înainte de a o apela? Atunci nu aș avea nicio problemă să înregistrez acest lucru, deoarece nu ar trebui să se întâmple niciodată.

Din păcate, nu. Cel puțin nu în API Java de bază. Totuși, este ușor să scrieți una – trebuie doar să modificați codul de mai jos.

  • Dacă pur și simplu nu prind excepția, nu va fi atribuită valoarea? Atunci îl voi inițializa pur și simplu la valoarea pe care o doresc atunci când nu este un număr și nu voi prinde excepția.

Dacă nu prindeți excepția, atunci stiva se va derula până când va ajunge la un bloc de captură care o va gestiona, sau se va derula complet și va opri firul. Variabila nu va fi, de fapt, atribuită, dar acest lucru nu este exact ceea ce doriți.

  • Există o modalitate de a marca cumva excepția în mod explicit că nu-mi pasă de ea? Mă gândesc că acest lucru ar fi ceva similar cu AWTEvent.consume(). Dacă da, atunci voi face acest lucru, astfel încât Google CodePro să nu vadă acest lucru ca fiind „unlogged”.

S-ar putea să existe o modalitate de a spune CodePro să ignore acest avertisment special. Cu siguranță, cu instrumente precum FindBugs și Checkstyle puteți dezactiva avertismentele în anumite locații. (EDIT: @Andy a indicat cum se poate face acest lucru).

Bănuiesc că ceea ce doriți este ceva de genul pachetului Commons lang menționat de @daveb. Este destul de ușor de scris o astfel de funcție:

int parseWithDefault(String s, int def) {
    try {
        return Integer.parseInt(s);
    }
    catch (NumberFormatException e) {
        // It's OK to ignore "e" here because returning a default value is the documented behaviour on invalid input.
        return def;
    }
}

Comentarii

  • CodePro este incorect în a cere logare pentru fiecare captură. În acest caz, este perfect în regulă să mănânci excepția, deoarece acesta este comportamentul dorit și documentat al metodei. –  > Por Steve Kuo.
daveb

Nu există NumberUtils.toInt(String, int) în comenzi lang care va face exact ceea ce doriți.

NumberUtils.toInt("123", 42) ==> 123
NumberUtils.toInt("abc", 42) ==> 42

Comentarii

  • Nu pot face acest lucru într-un fel fără a importa Apache Commons? –  > Por Erick Robertson.
  • Da, dar multe proiecte folosesc commons lang și nu au nevoie să își creeze propriul implant. –  > Por daveb.
  • Până acum am evitat să fac oricare dintre ele. –  > Por Erick Robertson.
  • NumberUtils doar îl prinde acolo. Nu ocolește prinderea. 🙂 –  > Por Joseph Lust.
Andy Thomas
* Is there a way to mark the exception somehow explicitly that I don't care about it? I'm thinking this would be something similar to AWTEvent.consume(). If so, then I will do this so that Google CodePro doesn't see this as "unlogged".

Da, puteți dezactiva local o regulă de audit CodePro pentru o linie de cod:

http://code.google.com/javadevtools/codepro/doc/features/audit/locally_disabling_audit_rules.html

Acestea fiind spuse, nu este neapărat necesar să includeți jurnalizarea de diagnosticare în fiecare bloc de captare a excepțiilor. Uneori, cea mai bună acțiune este să urmați un curs implicit. Alteori, este să interacționați cu utilizatorul. Depinde.

Bert F

Creați-vă propria metodă de comoditate pentru utilizare acum și în viitor:

public static int parseInt(final /*@Nullable*/ String s, final int valueIfInvalid) {
    try {
        if (s == null) {
            return valueIfInvalid;
        } else {
            return Integer.parseInt(s);
        }
    } catch (final NumberFormatException ex) {
        return valueIfInvalid;
    }
}

Există o metodă pe care să o pot apela și care să-mi spună dacă Integer.parseInt() va arunca o excepție de tip NumberFormatException înainte de a o apela? Atunci nu aș avea nicio problemă să înregistrez acest lucru, deoarece nu ar trebui să se întâmple niciodată.

Nu din câte știu eu. Țineți cont de faptul că, dacă ar exista, probabil că veți ajunge să analizați valoarea de două ori (o dată pentru a o valida și o dată pentru a o analiza). Înțeleg că doriți să evitați excepția, dar în acest caz, aceasta este prinderea excepției este idiomul standard în Java și nu oferă altul (cel puțin din câte știu eu).

Dacă pur și simplu nu prind excepția, valabilitatea nu va fi atribuită? Atunci îl voi inițializa pur și simplu la valoarea pe care o doresc atunci când nu este un număr și nu voi prinde excepția.

Trebuie să prindeți excepția (chiar dacă nu face nimic) sau aceasta va scăpa din bloc și va fi aruncată prin stivă.

Există o modalitate de a marca cumva excepția în mod explicit că nu-mi pasă de ea? Mă gândesc că acest lucru ar fi ceva similar cu AWTEvent.consume(). Dacă da, atunci voi face acest lucru pentru ca Google CodePro să nu vadă acest lucru ca fiind „unlogged”.

Nu știu de nici unul. Aș folosi metoda de conveniență de mai sus (am ceva similar într-o mică colecție de utilități generale pe care le am la dispoziție pentru a le folosi în toate proiectele mele).

Nu l-aș înregistra dacă este cu adevărat o condiție normală pe care o gestionați. Nu sunt familiarizat cu Google CodePro, dar aș spera că există o modalitate de a suprima avertismentul, de exemplu, un fel de adnotare/cuvânt cheie @SuppressWarnings(„xxx”).


Editați: Am vrut să subliniez aceste comentarii în comentariile de mai jos

Această abordare încă nu gestionează excepția. Este o formă proastă să prinzi o excepție și să nu faci nimic cu ea. Acesta este motivul pentru care caut o soluție mai bună

.

… Excepția (situația) este gestionată prin returnarea valorii indicate „valueIfInvalid”. Adresa „formă proastă” la care vă referiți la practica proastă de a scrie orbește și nechibzuit blocuri catch goale. și de a nu se mai întoarce niciodată pentru a lua în considerare și a aborda cu adevărat cazul. În cazul în care situația de excepție este luată în considerare și se face ceea ce trebuie pentru situația respectivă (chiar dacă ceea ce este corect este să nu faci nimic), atunci ați „gestionat” excepția.

Comentarii

  • Această abordare tot nu gestionează excepția. Nu este bine să prinzi o excepție și să nu faci nimic cu ea. Acesta este motivul pentru care caut o soluție mai bună. –  > Por Erick Robertson.
  • Nu este o formă greșită dacă știi că nu vrei să faci nimic cu ea. Este doar o formă proastă să ignori excepțiile cu care ar trebui să faci ceva util. –  > Por Cameron Skinner.
  • @Erick – Sunt de acord cu @Cameron. Excepția (situația) este tratată prin returnarea indicată valueIfInvalid. Noțiunea generală de „excepție netransmisă” se referă la practica proastă de a scrie orbește și fără să se gândească blocuri catch goale și de a nu se întoarce niciodată pentru a lua în considerare și a aborda cu adevărat cazul. Dacă situația de excepție este luată în considerare și se face ceea ce este corect pentru situația respectivă (chiar dacă ceea ce este corect este să nu faceți nimic), ați „tratat” excepția. –  > Por Bert F.
  • @Bert F- ce înseamnă excepție finală? –  > Por palAlaa.
  • @ Steve Kuo- final nu poate fi dezordine –  > Por palAlaa.
Marcus Leon

Ar trebui să prindeți Excepția așa cum o faceți. Este enervant, dar este cea mai bună abordare.

Nu există nicio metodă Java API care să returneze 0 atunci când șirul nu este un int valid.

Atunci când șirul nu este un int, se va lansa o excepție, astfel încât variabila int nu va fi setată decât dacă prindeți excepția așa cum faceți.

Comentarii

  • Atunci ce fac cu ea după ce o prind? Nu vreau să o înregistrez în jurnal, pentru că este normală. Nu este un caz de excepție. Să nu o lăsați în jurnal funcționează, dar să prindeți o excepție și să nu faceți nimic cu ea este o formă proastă. Caut un răspuns mai bun. –  > Por Erick Robertson.
Peter Lawrey

Dacă nu este clar cum ar trebui să o tratezi din partea celui care o primește, nu ar trebui să o prinzi și să lași apelantul să se ocupe de ea. Dacă știi cum ar trebui să fie tratat, ar trebui să faci asta. În acest caz, este posibil ca înregistrarea să nu fie necesară sau foarte utilă.

Înregistrarea unei excepții este mai utilă în cazul în care nu știți cum să gestionați excepția și lăsați persoana care citește jurnalele să se ocupe de aceasta.

Comentarii

  • În mod precis. Acesta este motivul pentru care caut o modalitate de a marca excepția ca fiind gestionată fără a o înregistra. –  > Por Erick Robertson.
darioo

Primul dvs. bloc de cod este corect. i nu va fi implicit convertit la 0 atunci când apare o excepție și trebuie să prindeți acea excepție. Setarea i la 0 în interiorul catch este corectă; deși puteți înlocui pur și simplu i = 0; cu return 0;. În acest caz, nu puteți evita tratarea excepțiilor.

Pentru a clarifica, puteți utiliza acest lucru:

private int getCurrentPieceAsInt() {
    int i = 0;
    try {
        i = Integer.parseInt(this.getCurrentPiece());
    } catch (NumberFormatException e) {
        // log that an exception occured if it's needed
        return 0;
    }
    return i;
}

Comentarii

  • Ce pot face cu excepția pentru a o marca în mod explicit ca fiind gestionată? Este o formă proastă să prinzi o excepție și să nu faci nimic cu ea, așa că sunt în căutarea unei soluții mai bune. –  > Por Erick Robertson.
  • nu, nu este o formă proastă să prinzi o excepție și să nu faci nimic cu ea. Scopul excepțiilor bifate este acela de a le putea prinde și de a le trata așa cum are nevoie aplicația dumneavoastră – uneori acest lucru implică logarea sau recuperarea, dar alteori știți că nu contează. –  > Por nojo.
rob

După cum au menționat și alții, nu există o metodă încorporată în API Java de bază pe care să o puteți apela pentru a valida un număr întreg, dar puteți utiliza metoda Character pentru a vă valida datele introduse fără a utiliza gestionarea excepțiilor. De exemplu:

package com.example.parseint;

public class ValidateIntExample {
    public static boolean isInteger(String s) {
        if (s == null) {
            return false;
        }

        s = s.trim();

        if (s.length() == 0) {
            return false;
        }

        int start = 0;
        if (s.charAt(0) == '-') { // handle negative numbers
            if (s.length() == 1) {
                return false;
            }
            else {
                start = 1;
            }
        }

        for (int i = start; i < s.length(); i++) {
            if (! Character.isDigit(s.charAt(i))) {
                return false;
            }
        }

        return true;
    }
}

De fapt, parseInt utilizează ea însăși Character.isDigit în mod intern, lucru pe care îl puteți verifica în codul sursă JRE. (Îmi pare rău, aș fi inclus și codul parseInt metoda aici, dar nu sunt sigur dacă îmi este permisă de termenii licenței). Dacă folosiți Eclipse și aveți codul sursă JRE atașat la proiect, puteți face clic dreapta pe metoda Integer.parseInt în codul dvs. și faceți clic pe Open Declaration.