wie behandele ich am besten auftretende Laufzeitfehler bei der Erzeugung von Objekten?
In meine speziellen Fall erzeuge und eröffne ich eine H2 Datenbank auf der SD-Karte meines Raspberry.
Dazu habe ich mir eine Klasse geschrieben, die mir im Konstrukor die Datenbank erzeugt öffnet und
ggf auch Tabellen anlegt.
Wird das Objekt auch erzeugt, wenn dieser Konstruktor auf einen Fehler läuft (z.B. zu wenig Platz auf der
SD-Karte, Schreibprobleme usw)?
Ist es besser, ev. Fehler mit Throw weiterzureichen? oder kann ich die Objekterzeugung abbrechen?
Bin für jeden Hinweis dankbar.
famco
ist technisch recht unspektakulär, denke ich,
vergleichbar mit einer Methode, die ein Objekt in einer lokalen Variable ablegt, vor Rückgabe aber wird die Methode per Exception beendet -> Objekt weg
innerhalb des Konstruktors ist das Objekt schon konkret vorhanden und fertig, wenn es dort (vor der Exception) in einer (anderen/ statischen) Liste abgelegt wird,
dann auch nach Fehler normal verfügbar, sonst bei Exception weg, usw., kann auch alles getestet werden
wenn du schon nach ‘am besten’ fragst, dann sollten Konstruktoren der Lehre nach eher leer und fehlerfrei sein,
von minimalen Arbeiten bei so gut wie ausgeschlossenen Fehlern abgesehen,
alles was länger als paar ns dauert oder kompliziert oder try/catch erfordert (DB-Verbindung erfüllt viele böse Kritieren, bestimmt noch mehr), gehört da eher nicht hin
eine Factory-Methode scheint ideal angebracht hier,
dann könntest du frei von programmiertechnischen Zweifeln und ‘Best Practice’ hinsichtlich Konstruktoren agieren,
ob bei irgendwelchen Fehlern die Factory-Methode ein Objekt in von der Norm abweichenden Zustand zurückgeben soll, wäre aber evtl. immer noch offen,
das ist eine Entscheidung die allein bei dir liegt, da kann es keine Richtlinien geben
edit:
Fehler weiterzureichen ist eine übliche Möglichkeit bei allen Exceptions, ja,
‘so weit werfen bis eine Ebene erreicht ist, die damit etwas anfangen kann’
private final static LocalDatabase INSTANCE = new LocalDatabase();
public static LocalDatabase getInstance() {
return INSTANCE;
}
private Connection con;
private LocalDatabase() throws ClassNotFoundException, SQLException {
// falls DB nicht vorhanden, DB anlegen
Class.forName("org.h2.Driver");
con = DriverManager.getConnection("jdbc:h2:~/xyz", "sa", "");
}
}
*** Edit ***
Dann wäre es also günstiger, die Datenbank nicht im Konstruktor anzubinden, sondern eine eigene Methode dafür zu schreiben, die dann den Fehler mit THROW an den aufrufer zurück gibt?
es wäre nur günstiger hinsichtlich Lehrmeinung/ Sorgen zu Konstruktoren & Co.,
streng genommen hast du aber mit Methode hier nur mehr Code und exakt dasselbe Ergebnis…, nämlich Exception statt Objekt beim Aufrufer
bei so eindimensionalen Vorgehen ist das nicht wirklich wichtig, in anderen Fällen mag es anders sein
mit deinem statischen Singleton-Ansatz sieht es sowieso noch wieder anders aus, gibt Compilerfehler aktuell
es ist technisch gar nicht erlaubt, statisch Exception ‘ankommen zu lassen’,
wer sollte diese fangen wenn nicht du, was versprichst du dir von dem Weiterwerfen?
wenn hier die Verbindung versagt ist das ganze Programm kaputt, Ende,
da kannst du auch gleich Log-Ausgabe + System.exit(1); in ein catch setzen,
Alternative nur catch ohne Programmende, dann wird nach derzeitigen Aufbau/ geringfügiger Modifikationen
entweder INSTANCE null sein oder INSTANCE nicht null aber keine Connection haben,
und der Rest des Programms keine DB-Verbindung, und keine Möglichkeit eine neue aufzumachen, es ist halt Ende
interessanter wird es für Fehler zu Connection erst, wenn du eine GUI/ Schleife mit Konsoleneingabe/ Automatik-Logik laufen hast,
mehrfach versucht wird eine Connection zu erstellen usw.,
ein Programm in welchem jemand auf die Exception reagieren kann, und sei es nur mit Warten der restlichen Arbeit bis Connection steht
edit:
schöne Parallele ist DriverManager.getConnection(); selber mit ähnlichen wenn nicht denselben Fragen wie bei dir
da ist es keine statische Methode, sie kann mehrfach aufgerufen werden, Exception-Frage bekommt Sinn,
sollte hier ein kaputtes Connection-Objekt zurückgegeben werden oder Exception?
DriverManager.getConnection() ist eine Factory-Methode, kein Konstruktor
Danke erst mal für Deine hilfreichen Hinweise. Das will alles gut überlegt sein! Wenn der Raspberry die Datenbank auf der lokalen SD-Karte nicht erfolgreich ansprechen kann, ist sowieso keine sinnvolle Aktion dieses Gerätes mehr möglich. Ich werde also die DB- Anbindung in eine eigene Methode auslagern (dann wäre auch das Problem mit der ‘statischen Exception’ gelöst) mit einem Try Catch versehen und im Erfolgsfall ein true zurückgeben.
Die höhere Ebene muss dann auf dem LC-Display diesen (wirklich) fatalen Fehler melden, die IOs in einen unkritischen Zustand bringen und das Programm stoppen oder ev. einen Neustart versuchen.
wie gesagt nicht zwingend, ein try/catch im Konstruktor ginge schon auch,
um kein Objekt erstellen zu ‚müssen‘ könnte es eine RuntimeException geben, die ist erlaubt, eh nicht feststellbar,
wobei ich die weitere Verarbeitung dann selber falsch getippte hätte, es erfolgt:
public class Test {
public static void main(String[] args) {
try {
System.out.println("LocalDatabase: " + LocalDatabase.INSTANCE);
} catch (Error e) {
System.out.println("da war doch was1: " + e + ", " + e.getCause());
// Ausgabe: java.lang.ExceptionInInitializerError, java.lang.RuntimeException: hallo
// die Exception aus der statischen Initialisierung der zweiten Klasse kommt hier an?..
// als Error aber besser nicht abfangen
}
try {
System.out.println("LocalDatabase: " + LocalDatabase.INSTANCE);
} catch (Error e) {
System.out.println("da war doch was2: " + e + ", " + e.getCause());
// Ausgabe: java.lang.NoClassDefFoundError, null
// Klasse nicht weiter verwendbar.., ist ja auch besser so
}
}
}
class LocalDatabase {
final static LocalDatabase INSTANCE = new LocalDatabase();
private LocalDatabase() {
throw new RuntimeException("hallo");
}
}