2013-09-08 9 views
27

Ich habe schon seit einiger Zeit in Java programmiert. Aber manchmal verstehe ich nicht, wann ich die Ausnahme auslösen soll und wann ich die Ausnahme abfangen soll. Ich arbeite an einem Projekt, in dem es viele Methoden gibt. Die Hierarchie ist so etwas wie this- SoWann die Ausnahme vs Wann die Ausnahmen zu fangen?

Method A will call Method B and Method B will call some Method C and Method C will call Method D and Method E. 

zur Zeit, was ich tue ist-ich Ausnahmen in allen Methoden zu werfen und es in Verfahren A zu kontrollieren und dann als Fehler anzumelden.

Aber ich bin mir nicht sicher, ob dies der richtige Weg ist, es zu tun? Oder sollte ich Ausnahmen in allen Methoden abfangen? Deshalb begann diese Verwirrung in meinem- Wann sollte ich die Ausnahme vs Wann sollte ich die Ausnahmen werfen. Ich weiß, dass es eine dumme Frage ist, aber irgendwie kämpfe ich darum, dieses wichtige Konzept zu verstehen.

Kann mir jemand ein detailliertes Beispiel von When to catch the Exception vs When to throw the Exceptions geben, damit meine Konzepte auf diesem Weg geklärt werden? Und in meinem Fall, sollte ich weiterhin die Ausnahme werfen und dann in der Hauptberufungsmethode A fangen?

+2

Sie sollten immer auf der Ebene fangen, wenn es möglich ist, die Situation zu behandeln, die zu einer Ausnahme führt, die richtig ist ... – ppeterka

+0

Es ist nicht eine Frage der einen oder anderen. Sie können Ausnahmen abfangen, etwas verarbeiten und dann erneut ausführen. Sie sollten wahrscheinlich einige konkrete Beispiele dafür finden, worüber Sie nachdenken. Veröffentlichen Sie ein Beispiel wie hier empfohlen: http://www.sscce.org/ – dcaswell

Antwort

4

Im Allgemeinen fangen auf der Ebene, wo Sie etwas Nützliches darüber tun können. Beispiel: Der Benutzer versucht, eine Verbindung zu einer Datenbank herzustellen, und er schlägt in Methode D fehl.

Wie möchten Sie damit umgehen? Vielleicht indem Sie den Dialog "Sorry, kann nicht mit SERVER/DB verbinden" oder was auch immer sagen. Ist die Methode A, B oder C, die diese SERVER/DB-Informationen erstellt hat (zB indem sie eine Einstellungsdatei gelesen oder nach Benutzereingaben gefragt hat) und die Verbindung versucht hat? Das ist wahrscheinlich die Methode, die die Ausnahme behandeln sollte. Oder mindestens 1 weg von der Methode, die damit umgehen sollte.

Es hängt wirklich von Ihrer Anwendung ab, daher kann dies nur ein sehr allgemeiner Hinweis sein. Die meiste Erfahrung habe ich mit Swing-/Desktop-Apps, und man kann normalerweise ein Gefühl dafür bekommen, welche Klassen Programmlogik machen (z. B. "Controller" -Sachen) und wer Dialogfelder aufstellt (z. B. "View" -Stuff). Normalerweise sollte der "Controller" die Ausnahme abfangen und versuchen, etwas zu tun.

In einer Web-App kann dies anders sein.

Einige sehr skelettierten Code, die meisten Klassen existieren nicht, und ich bin mir nicht sicher, ob eine URL für die DB sogar sinnvoll ist, aber Sie bekommen die Idee. Vage Swingish ...

/* gets called by an actionListener when user clicks a menu etc... */ 
public URL openTheDB() { 
    URL urlForTheDB = MyCoolDialogUtils.getMeAURL(URL somePreviousOneToFillInTheStart); 
    try { 
    verifyDBExists(urlForTheDB); 
    // this may call a bunch of deep nested calls that all can throw exceptions 
    // let them trickle up to here 

    // if it succeeded, return the URL 
    return urlForTheDB; 
    } 
    catch (NoDBExeption ndbe) { 
    String message = "Sorry, the DB does not exist at " + URL; 
    boolean tryAgain = MyCoolDialogUtils.error(message); 
    if (tryAgain) 
     return openTheDB(); 
    else 
     return null; // user said cancel... 
    } 
    catch (IOException joe) { 
    // maybe the network is down, aliens have landed 
    // create a reasonable message and show a dialog 
    } 

} 
37

Sie sollten die Ausnahme abfangen, wenn Sie in der Methode sind, die weiß, was zu tun ist.

Zum Beispiel, vergessen Sie, wie es tatsächlich im Moment funktioniert, nehmen wir an, Sie schreiben eine Bibliothek zum Öffnen und Lesen von Dateien.

So haben Sie eine Klasse, sagen:

public class FileInputStream extends InputStream { 
    public FileInputStream(String filename) { } 
} 

können nun sagen, dass die Datei nicht existiert. Was sollte man tun? Wenn Sie Schwierigkeiten haben, an die Antwort zu denken, dann liegt das daran, dass es keinen gibt ... der FileInputStream weiß nicht, was er tun soll. Also:

public class FileInputStream extends InputStream { 
    public FileInputStream(String filename) throws FileNotFoundException { } 
} 

Jetzt sagen wir, jemand benutzt Ihre Bibliothek.Sie könnten Code haben, der wie folgt aussieht:

public class Main { 
    public static void main(String... args) { 
     String filename = "foo.txt"; 
     try { 
      FileInputStream fs = new FileInputStream(filename); 

      // The rest of the code 
     } catch (FileNotFoundException e) { 
      System.err.println("Unable to find input file: " + filename); 
      System.err.println("Terminating..."); 
      System.exit(3); 
     } 
    } 
} 

Hier ist der Programmierer weiß, was zu tun ist, so fangen sie die Ausnahme und damit umgehen.

+0

-1 Eine Nachricht an stderr zu drucken, die nicht einmal auf den Dateinamen verweist, gefolgt von einem Hard-Exit der JVM, "behandelt" die Ausnahme kaum . Bitte verbessern Sie Ihren Code. (Ich weiß, es ist nur ein Quickie-Beispiel, aber Sie können es besser machen ...) – user949300

+11

@ user949300 Dies ist ein [sscce] (http://sscce.org) Es soll ein einfaches Beispiel sein, anstatt es mit anderen zu plumpsen Sachen. Sie machen jedoch einen guten Punkt über den 'Dateinamen', den ich behoben habe. – durron597

+1

@ user949300 auch feststellen, dass es in der 'main'-Methode ist, gibt es nicht wirklich viel zu tun. Offensichtlich wäre es nicht schwierig, die JVM tief in Code – durron597

1

In der Regel wird eine Ausnahme ausgelöst, wenn Sie den Aufrufer über die Methode einiger Fehler benachrichtigen möchten.

beispiels ungültige Benutzereingaben, Datenbankprobleme, Netzwerkausfälle, fehlende Dateien

3

Sie sollten die Ausnahme auf dem niedrigstmöglichen Niveau behandeln. Wenn die Methode die Ausnahme nicht richtig behandeln kann, sollten Sie sie werfen.

  • fangen Wenn Sie Methode haben, die auf Ressourcen verbindet (zB öffnet Datei/Netzwerk)
  • throw wenn Klasse höher in der Hierarchie Informationen über Fehler muss
0

Wie andere gesagt haben, als allgemeine Regel , sollten Sie eine Ausnahme fangen, wenn Sie tatsächlich damit umgehen können, andernfalls werfen Sie es einfach.

Zum Beispiel, wenn Sie Code schreiben, die aus einer Datei speichern Informationen über einen Verbindungs-Player liest und eines Ihrer E/A-Methoden wirft ein IOException, dann würden Sie diese Ausnahme und den Code werfen wollen, die die load aufgerufen Methode würde diese Ausnahme abfangen und entsprechend behandeln (z. B. den Player trennen oder eine Antwort an den Client senden usw.). Der Grund, warum Sie die Ausnahme in der load-Methode nicht behandeln möchten, liegt darin, dass Sie in der Methode die Ausnahme nicht sinnvoll behandeln können. Daher delegieren Sie die Ausnahme an den Aufrufer in der Hoffnung, dass sie damit umgehen können.

3

Ich werde ein Muster teilen, das meine Speck in einer Produktionsumgebung oder zwei gespeichert hat.

Motivation

Mein Ziel, dass der arme Kerl, um sicherzustellen, ist (vielleicht ich), die in um Mitternacht versucht, ein SEV1 Support-Ticket zu lösen, wird eine schöne Hierarchie von ‚verursacht durch‘ Fehler folgen Sie, vervollständigen Sie mit Daten wie IDs, alles ohne den Code zu überladen.

Methode

Um dies zu erreichen, fangen wir alle Ausnahmen geprüft und wieder werfen sie als nicht markiert Ausnahmen. Ich verwende dann einen globalen Fang an der Grenze jeder meiner Architekturschichten (normalerweise abstrahiert oder injiziert, so dass es nur einmal geschrieben wird). An diesen Punkten kann ich dem Fehlerstapel einen zusätzlichen Kontext hinzufügen oder entscheiden, ob ich eine benutzerdefinierte Überprüfung mit Variablen protokollieren und ignorieren oder eine benutzerdefinierte Ausnahme auslösen soll, um einen zusätzlichen Kontext zu halten. Auf Nebenbei bemerkt, lüge ich nur Fehler bei der oberen Schicht ‚Doppel Logging‘ auftritt (zB um den Cron-Job, der Feder-Controller für Ajax)

throw new RuntimeException(checked,"Could not retrieve contact " + id); 

Mit diesem Ansatz zu stoppen gibt es kein cluttering Ihrer GUI oder Business-Tier-Methodensignaturen, indem "throws" für datenbankbezogene Ausnahmen deklariert werden muss.

Ein Beispiel, wie dies in Real Life funktioniert:

Lets Job meinen Code sagen, ist ein automatisierter Prozess viele Versicherungspolicen zu erneuern.Die Architektur unterstützt eine GUI, um die Erneuerung für eine Richtlinie manuell auszulösen. Lassen Sie uns auch sagen, dass die Postleitzahl für den Rating-Bereich in der DB für eine dieser Richtlinien beschädigt ist.

Ein Beispiel für den Typ des Fehlerprotokolls, das ich erreichen möchte, wäre.

Log message: Flagging policy 1234 for manual intervention due to error:

From Stack Trace: Error Renewing Policy 1234. Rolling back the transaction ... This catch would also cover errors such as save errors, or generation of a letter.

From Stack Trace: Caused by: Error Rating Policy 1234 ... This catch would pickup errors retrieving many other objects, and algorithm errors such as NPE etc...

From Stack Trace: Caused by: Error Retrieving Rating Area 73932 ...

From Stack Trace: Caused by: JPA: unexpected null in field 'postcode'

5

Eine Ausnahme sollte ausgelöst werden, wenn bei einer Funktion ein Fehler auftritt, d. H. Ein Fehler.

Eine Funktion ist eine Arbeitseinheit, und Fehler sollten als Fehler oder auf Grund ihres Einflusses auf Funktionen betrachtet werden. Innerhalb einer Funktion f, ist ein Fehler, ein Fehler, wenn und nur wenn es f von der Erfüllung eines seiner Angerufenen Voraussetzungen, das Erreichen jeder f den eigenen Nachbedingungen oder Wiederherstellung jede invariant verhindert dass f die Verantwortung für die Wartung teilt.

Es gibt drei verschiedene Arten von Fehlern:

  • eine Bedingung, dass die Funktion von der Erfüllung einer Bedingung (beispielsweise eine Parameter Einschränkung) einer anderen Funktion verhindert, die aufgerufen werden muss;
  • eine Bedingung, die verhindert, dass die Funktion eine ihrer eigenen Nachbedingungen aufbaut (z. B. ist das Erzeugen eines gültigen Rückgabewerts eine Nachbedingung); und
  • eine Bedingung, die die Funktion daran hindert, eine Invariante wiederherzustellen, für die sie verantwortlich ist. Dies ist eine besondere Art von Nachbedingung, die insbesondere für Member-Funktionen gilt. Eine wesentliche Nachbedingung jeder nicht-privaten Elementfunktion ist, dass sie die Invarianten ihrer Klasse wiederherstellen muss.

Jede andere Bedingung ist nicht ein Fehler und sollte nicht als Fehler gemeldet werden.

Fehler melden, wenn eine Funktion einen Fehler erkennt, den sie selbst nicht beheben kann und der verhindert, dass sie in irgendeiner Form normal oder beabsichtigt fortgesetzt wird.

Behandeln Sie den Fehler an den Stellen, die über ausreichende Kenntnisse verfügen, um den Fehler zu behandeln, die in der Fehlerrichtlinie definierten Grenzen zu erzwingen, z. B. main oder Thread-Hauptlinien.