Archiv verlassen und diese Seite im Standarddesign anzeigen : Laden/Speichern in Java
ravage
2006-04-26, 20:44:50
Hi Java Profis (HellHorse ich zähl auf dich ;))
Ich hab mich mal wieder dazu durchgedrungen, nach meinem ersten Schritt in der Welt von Java (Meine ersten Java Gehversuche (http://www.forum-3dcenter.org/vbulletin/showthread.php?t=241157) - Vieeel Quelltext) den zweiten zu machen: Den kram den ich mir in meinen Tools zusammenklicke will ich jetzt sichern, und später wieder aufrufen können.
Die Fachbegriffe dafür sind wohl Serialisieren und Deserialisieren. Doch ich komm keinen schritt weiter. Jetzt bin ich erst mal auf der suche nach einem wirklich brauchbaren HowTo, wo auch ein gutes Beispiel dabei ist.
Und obwohl ich mich irgendwo schon damit abgefunden hab, dass ich vieles komplett neu machen muss, hätte ich noch gern gewusst, wie kompliziert es eurer meinung ist, in meine Tools eine Save/Load Funktionalität einzubauen.
Den Quellcode von einem der beiden Tools ist im Anhang zu finden.
Danke schonmal für alle Antworten, und macht mir Mut ;)
Senior Sanchez
2006-04-26, 22:03:09
Eine der besten Quellen wie ich finde:
http://www.galileocomputing.de/openbook/javainsel4/javainsel_12_013.htm#Rxx365java12013040004031F014100
Monger
2006-04-26, 23:34:49
Speichern und Laden ist sehr, SEHR simpel. Wesentlich einfacher als irgendwas in Klartext als Text oder XML oder so zu speichern...
Das folgende ist der Code den ich gerade verwende. Der ist natürlich auch aus irgendeinem Tutorial geklaut, wahrscheinlich sogar direkt von Galileocomputing:
public class Serialisierung {
private static Object mutex = new Object();
public static void toFile(File file, Object saveFile){
try{
synchronized (mutex) {
FileOutputStream out = new FileOutputStream(file);
ObjectOutputStream s = new ObjectOutputStream(out);
s.writeObject(saveFile);
s.flush();
s.close();
out.close();
}
}
catch(Exception e){
System.out.println("Fehler aufgetreten: " + e.toString());
}
System.out.println("Datei erfolgreich gespeichert");
}
@SuppressWarnings("unchecked")
public static Object fromFile(File file){
Object thingy = null;
try{
synchronized (mutex) {
FileInputStream in = new FileInputStream(file);
ObjectInputStream s = new ObjectInputStream(in);
thingy = s.readObject();
s.close();
in.close();
}
}
catch (Exception e) {
System.out.println("Es ist beim laden ein Fehler aufgetreten: " + e.toString());
}
return thingy;
}
}
Das Konzept sollte klar sein: du nimmst irgendein Objekt, und stopfst da alle Infos rein die du speichern möchtest. Das Objekt selbst muss "Serializable" implementieren, und alle Daten die darin gespeichert sind, ebenfalls. Dann öffnest du auf einem bestimmten Pfad eine Datei, und schreibst die binären Daten von diesem Objekt auf die Datei raus. Wenn du lädst, machst du es ganz genau umgekehrt.
Lass dich nicht davon irritieren, dass ich den Code oben über eine Semaphore synchronisiert habe.
Der knifflige Teil beginnt da, die Daten (und zwar GENAU die) die brauchst zu speichern, und alles andere wegzulassen. Gerade bei Java ist oft alles mit allem referenziert. Wenn du also bestimmte Referenzen drin hängen hast, kann es sein dass du dir Zeug speicherst von dem du keine Ahnung hast. Wenn du aber zu wenig speicherst, bringt dich ein laden der Datei nicht genau an den Punkt wo du vorher gespeichert hast, sondern irgendwo anders hin. Das kann unangenehm sein. Deshalb musst du das Speicherobjekt sehr gezielt aufbauen, und die Abhängigkeiten auf ein Minimum reduzieren.
Die Pfadangabe ziehst du dir am einfachsten aus vorgegebenen Elementen wie z.B. den JFileChooser raus.
HellHorse
2006-04-27, 17:49:00
private static Object mutex = new Object();
synchronized (mutex) {
.....
Was solln der Scheiss?
@SuppressWarnings("unchecked")
WTF?!? Das gibt's ja nicht mal einen Cast, geschweige denn einen unchecked.
Der knifflige Teil beginnt da, die Daten (und zwar GENAU die) die brauchst zu speichern, und alles andere wegzulassen.
transient, ansonsten hilft es manchmal auch wenn man GUI und Model trennt :rolleyes:
Btw, hat irgend wann irgend jemand schon mal erwähnt dass Exceptions verschlucken pöse ist?
Monger
2006-04-27, 18:04:18
Was solln der Scheiss?
:rolleyes:
Okay, sag mir wie es richtig geht.
Oh Dummheit. :ucrazy:
Zugriff auf statische Methoden sind immer synchronisiert, nicht wahr? Ich seh schon, ich hab an den Methoden zu lange rumgedoktert. Ich konnte mich irgendwie nicht entscheiden, ob ich sie statisch oder nicht haben wollte...
WTF?!? Das gibt's ja nicht mal einen Cast, geschweige denn einen unchecked.
Hö? Ich war mir ziemlich sicher, dass er ohne rumgemeckert hat...
Btw, hat irgend wann irgend jemand schon mal erwähnt dass Exceptions verschlucken pöse ist?
Was meinst du damit? Weil ich intern ein Try/Catch verwende statt die Methode selbst eine Exception werfen zu lassen?
Gnafoo
2006-04-27, 20:13:02
Was meinst du damit? Weil ich intern ein Try/Catch verwende statt die Methode selbst eine Exception werfen zu lassen?
Ich denke mal, dass er meint, dass du (a) jede mögliche Exception abfängst und nicht nur die nötigen und (b) dass es für den Aufrufer der Methode keine Möglichkeit gibt, herauszufinden, ob was schief gelaufen ist. Damit gibt es keine Möglichkeit dem User eine Rückkmeldung, oder alternative Entscheidungsmöglichkeit zu geben. Eigentlich sollte die Methode doch wohl eher die Exceptions nicht abfangen und dem Aufrufer der Methode die Fehlerbehandlung im konkreten Kontext überlassen.
Eigentlich sollte die Methode doch wohl eher die Exceptions nicht abfangen und dem Aufrufer der Methode die Fehlerbehandlung im konkreten Kontext überlassen.
Das ist doch Käse, na klar sollte man Try/Catch verwenden. In einer wirklichen Anwendung würde man dann eben die Exception in ein Error Log schreiben oder eben ins Application Event Log von Windows. Und eine spezielle Exception im Catch Block abfangen ist schön und gut, aber nur dann wenn man auch gezwungen ist, darauf unterschiedlich zu reagieren. Wenn ich es nicht anders benötige verwende ich in meinen Anwendungen auch nur noch generische custom Exceptions, die ich dann im catch schmeiße.
Man sollte aber auf keinenfall catch(Exception e) benützen, weil das alles fängt, auch das was man hier gar nicht behandeln sollte.
HellHorse
2006-04-27, 21:05:49
:rolleyes:
Okay, sag mir wie es richtig geht.
Was denn? Wie schon gesagt, ich habe keine Ahnung was das werden sollte.
Zugriff auf statische Methoden sind immer synchronisiert, nicht wahr?
Nayn.
Ich konnte mich irgendwie nicht entscheiden, ob ich sie statisch oder nicht haben wollte...
statisch passt schon
Hö? Ich war mir ziemlich sicher, dass er ohne rumgemeckert hat...
Ich wiederhole mich nur ungern: du hast nicht einen cast.
Was meinst du damit? Weil ich intern ein Try/Catch verwende statt die Methode selbst eine Exception werfen zu lassen?
Man kriegt überhaupt nicht mit ob das (de)serialisieren erfolgreich war oder nicht.
In einer wirklichen Anwendung würde man dann eben die Exception in ein Error Log schreiben oder eben ins Application Event Log von Windows.
Man sollte dem aufrufenden Code verdammt noch einmal mitteilen ob die (de) serialisation erfolgreich war. Und das nicht nur in einer richtigen Anwendung sondern immer.
Man sollte dem aufrufenden Code verdammt noch einmal mitteilen ob die (de) serialisation erfolgreich war. Und das nicht nur in einer richtigen Anwendung sondern immer.
Indem die Methode einfach einen boolschen Wert zurückgibt. Aber was hat das jetzt mit Exception Handling zu tun?
Man sollte aber auf keinenfall catch(Exception e) benützen, weil das alles fängt, auch das was man hier gar nicht behandeln sollte.
Das stimmt so aber keines Falls. Es ist viel eher so, zumindest bei mir, dass man bei einer Operation generell Fehler abfangen will, als nur spezifische. Wenn ich spezifische abfangen will/muss, dann spricht ja nichts dagegen das zu machen. Oft ist es aber so, dass du überhaupt nicht weißt, welche Exception in einem Codeteil überhaupt geworfen werden könnte, weil du vielleicht Fremdkomponenten verwendest etc. Außerdem macht es meiner Meinung nach nur Sinn, wenn du den Caller das mitteilen "musst".
Monger
2006-04-27, 22:11:10
Was denn? Wie schon gesagt, ich habe keine Ahnung was das werden sollte.
Okay, dann erklär mir bitte, wie ich den Datenzugriff richtig synchronisiere. Sofern es überhaupt nötig ist.
Edit: Was ich mich an der Stelle gefragt habe ist, ob ich beim laden um ein Casten herumkomme. Wahrscheinlich nicht, oder? Kann ich garantieren, dass der aufrufende Prozess wirklich nur den Objekttyp erhält den er auch erwartet?
HellHorse
2006-04-27, 22:34:39
Indem die Methode einfach einen boolschen Wert zurückgibt.
Das ist eine Möglichkeit. Das geht hier aber nicht, da man nicht gleichzeit an Objekt und einen bool zurückgeben kann, ok, wenn man jetzt Pointer hätte..... Aber für genau die Fälle gibt es in highlevel Sprachen ja Exceptions ;) (auch wenn Joel anderer Meinung ist).
Aber was hat das jetzt mit Exception Handling zu tun?
Das es hier eben nicht gemacht wird. Was wir hier haben ist das Java Gegenstück zu:
ON ERROR RESUME NEXT
(nein, ich kann kein VB)
Okay, dann erklär mir bitte, wie ich den Datenzugriff richtig synchronisiere. Sofern es überhaupt nötig ist.
Ist überhaupt nicht nötig da man überhaupt keine gesharten Daten hat.
Was ich mich an der Stelle gefragt habe ist, ob ich beim laden um ein Casten herumkomme. Wahrscheinlich nicht, oder?
Das ist einer der Paradefälle, warum man nie um casts erumkommt. Der cast passiert aber in der Methode, die #fromFile aufruft, nicht darin.
Kann ich garantieren, dass der aufrufende Prozess wirklich nur den Objekttyp erhält den er auch erwartet?
Ja, per cast ;)
HellHorse
2006-04-27, 22:35:51
Oft ist es aber so, dass du überhaupt nicht weißt, welche Exception in einem Codeteil überhaupt geworfen werden könnte
Genau aus diesem Grund gibt es ja checked Exceptions.
Genau aus diesem Grund gibt es ja checked Exceptions.
Erinner mich nicht daran, die sind mit Sicherheit das Ergebnis eine Forschungsarbeit unter der Fragestellung "kann die Lösung eines Problems schlimmer als das Problem selbst sein?".
Ein Knopf in der IDE der die für die Position aktuelle Liste der möglichen Exceptions ergibt wäre wohl zu benutzbar gewesen :(
HellHorse
2006-04-27, 23:56:21
Ein Knopf in der IDE der die für die Position aktuelle Liste der möglichen Exceptions ergibt wäre wohl zu benutzbar gewesen :(
Genau das machen IDEs ja.
Das ist eine Möglichkeit. Das geht hier aber nicht, da man nicht gleichzeit an Objekt und einen bool zurückgeben kann, ok, wenn man jetzt Pointer hätte.....
Man kann aber null zurückgeben.
Aber für genau die Fälle gibt es in highlevel Sprachen ja Exceptions ;) (auch wenn Joel anderer Meinung ist).
Gegen Exceptions spricht überhaupt nichts, es ging ja um die Behandlung. Ich sehe das auch nicht als überflüssig an, überhaupt nicht. Aber es gibt i.d.R. viele Fälle, da gibt es einfach nur Fehler oder kein Fehler bzw. Weiterausführen oder Abbruch. Wenn man eine Anwendung hat, die nonstop laufen muss und wo man weiß, an jener Stelle können diese und jene Fehler auftreten und man darauf unterschiedlich reagieren muss, damit im Falle eines Fehlers die Anwendung weiterläuft, dann ist der Einsatz von differenzierten Exceptions im catch vollkommen richtig. Aber oft ist das eben auch nicht so, da gibts nur DEN Fehler, der Protokolliert werden muss oder ggf. an den Caller weitergereicht werden muss. In dem Fall wäre es ja vollkommen sinnlos, performancefressend und sowieso zig Exceptionsunterscheidungen im catch abzufragen, die dann auch noch alle die selbe Operation ausführen.
Ich halte es in dem Fall für wesentlich sinnvoller, eine custom Exception zu schmeißen. Die nimmt dann im Konstruktor die generische Framework Exception entgegen und noch etwas mehr Metainformationen zur Kennzeichnung der Codestelle. Ansonsten hat man dann alles, Stacktrace, Name der Exception, Exception Text etc., das kann die Exception ja dann irgendwo speichern (Event Log etc.). Mehr bieten die meisten Exceptions auch sowieso nicht an, da spielt es keine Rolle, ob es Typ X, Y oder Z ist.
HellHorse
2006-04-28, 10:09:44
Man kann aber null zurückgeben.
Man kann auch null serialisiert haben, woher willst du den Unterschied wissen?
Man kann auch null serialisiert haben, woher willst du den Unterschied wissen?
Dann bekomme ich eben ein null zurückgeliefert. Ich sage ja nicht, dass man es so implementieren muss. Entweder übergehe ich z.B. eine mögliche File Exception und gebe dort ebenfalls null zurück, weil es für den Caller unbedeutend ist, da er immer ein Ergebnis =! null erwartet oder ich muss eben noch eine Exception schmeißen. Das war aber auch nicht der Punkt, sondern ob man beim Exception Handling im catch auf alle möglichen Exception abfragen muss oder nicht.
HellHorse
2006-04-28, 11:33:35
Das war aber auch nicht der Punkt, sondern ob man beim Exception Handling im catch auf alle möglichen Exception abfragen muss oder nicht.
WTF?!? Das ist eine (IOException) oder höchstens zwei (zusätzlich noch FileNotFoundException was eine sinnvolle Fehlermeldung ermöglichen würde). Abfragen muss man da gar nichts.
Und das mehere catchs die Performance verschlechtern muss erst noch bewiesen werden.
Edit:
Ok eine mehr ClassNotFoundException
Genau das machen IDEs ja.
Ja und nein. Ich halte checked Exceptions für überflüssig bis schädlich. Falscher Fehlerbehandlungscode aus Zwang geschrieben ist schlechter als garkeiner und auch im Nachhinein viel schwieriger zu finden, hinter jede Funktion "throws Exception" zu schreiben umgeht das zwar, ist auch nicht so das wahre, dann funktioniert der Knopf in der IDE nämlich nichtmehr brauchbar.
Den Knopf in der IDE hätte ich gern, aber ohne checked Exceptions.
Das ist eine (IOException) oder höchstens zwei (zusätzlich noch FileNotFoundException was eine sinnvolle Fehlermeldung ermöglichen würde).
Ist doch vollkommen irrelevant, ob 2, 3 oder mehr. Und...
Edit:
Ok eine mehr ClassNotFoundException
Zeigt doch nur, dass du es selbst nicht aus dem Stehgreif wusstet. Kommt noch ein edit2, edit3, edit4? Das ist der Grund warum man bei einem Try/Catch Block den Catch Block mit der generischen Framework Exception Abfrage abschließen sollte, damit diese eben nicht unbehandelt durchfällt. Bsp:
catch(IOException ex1)
{}
catch(ClassNotFoundException ex2)
{}
catch(Exception ex3) // Falls noch nicht behandelt, hier auf jeden Fall
{}
Wenn du nun auf jede einzelne Exception abfragst, dann doch hoffentlich, weil dein Programm hoch komplex ist und in den catch Blöcken dann wichtige Dinge erledigt? In jedem catch Block lediglich durch ein throw noch mal die gecatchte exception zu schmeißen oder nur einen Fehlertext zu loggen, ist ja ziemlich unsinnig, redundant, überflüssig. Zeig doch mal ein Codebeispiel, damit man sich von der Notwendigkeit dieser Vorgehensweise als ausnahmslose Regel überzeugen lassen kann.
Das ist der Grund warum man bei einem Try/Catch Block den Catch Block mit der generischen Framework Exception Abfrage abschließen sollte, damit diese eben nicht unbehandelt durchfällt. Bsp:
catch(IOException ex1)
{}
catch(ClassNotFoundException ex2)
{}
catch(Exception ex3) // Falls noch nicht behandelt, hier auf jeden Fall
{}
Es ist normalerweise sinnvoll, Exceptions die man nicht behandelt einfach durchzureichen. Zumindest bis zu einem Punkt an dem "safe recovery" möglich ist, also das Programm im Fehlerfall in einen stabilen Zustand übergehen kann.
Im Falle einer Speicherfunktion ist das normalerweise dort wo der Speichervorgang eingeleitet wird. Der User klickt auf Speichern, Fehler tritt auf, eine Fehlermeldung erscheint, Programm ist im selben Zustand wie vor dem Speichern. Der Dateiinhalt zwar nicht unbedingt, aber wer das auch noch benötigt muss eben Transactions implementieren.
In der Regel soll diese Fehlermeldung aber nicht pro gespeichertem Objekt erscheinen und der Speichervorgang auch nicht unbekümmert mit dem nächsten Objekt fortgesetzt werden.
Es ist normalerweise sinnvoll, Exceptions die man nicht behandelt einfach durchzureichen. Zumindest bis zu einem Punkt an dem "safe recovery" möglich ist, also das Programm im Fehlerfall in einen stabilen Zustand übergehen kann.
Dagegen spricht nichts, hat aber auch nichts mit der eigentlichen Diskussion zu tun. Es ist einfach sinnbefreit, für jede mögliche Exception ein catch zu schreiben, wenn man dort gar nicht speziell auf die spezifische Exception sinnvoll reagiert. Ich würde es so machen:
try
{...}
catch(Exception e)
{
throw new MyException(e, "Error occured while doing xyz");
}
Damit habe ich auch gleich die InnerException und alle nötigen Informationen. MyException könnte dann auch gleich den Namen der InnerException, Text, Stacktrace etc. in eine Log Datei/Event Log schreiben.
Differenziert würde ich nur reagieren, wenn man es wirklich auf spezifische Exceptions reagieren muss.
HellHorse
2006-04-28, 18:26:50
Falscher Fehlerbehandlungscode aus Zwang geschrieben ist schlechter als garkeiner und auch im Nachhinein viel schwieriger zu finden,
ACK, genau das bemängle ich ja am Code von Monger.
hinter jede Funktion "throws Exception" zu schreiben umgeht das zwar, ist auch nicht so das wahre,
Das ist extrem doof und hat nichts mit checked Exceptions zu tun.
Den Knopf in der IDE hätte ich gern,
Es gibt ihn ja!
aber ohne checked Exceptions.
Das wird nur funktionieren wenn du den kompletten Sourcecode aller Libraries hast. Die IDE muss dann den parsen, viel Spass bei der Java Library.
Zeigt doch nur, dass du es selbst nicht aus dem Stehgreif wusstet.
Natürlich weiss ich nicht auswendig, für jeden Konstruktor oder jede Methode welche checked Exceptions sie werfen kann. Dazu habe ich eine IDE.
Kommt noch ein edit2, edit3, edit4
Nein, siehe oben.
Das ist der Grund warum man bei einem Try/Catch Block den Catch Block mit der generischen Framework Exception Abfrage abschließen sollte, damit diese eben nicht unbehandelt durchfällt.
Nein, das ist der Grund warum man eine IDE verwenden sollte.
Wenn du nun auf jede einzelne Exception abfragst, dann doch hoffentlich, weil dein Programm hoch komplex ist und in den catch Blöcken dann wichtige Dinge erledigt? In jedem catch Block lediglich durch ein throw noch mal die gecatchte exception zu schmeißen oder nur einen Fehlertext zu loggen, ist ja ziemlich unsinnig, redundant, überflüssig.
Darum greifft ja Vererbung. Da FileNotFoundException von IOException erbt kann ich FileNotFoundException gleich mit catch (IOException) behandeln. Natürlich greifft das nicht, wenn die Exception Hierarchie scheisse ist (es gibt keine allgeine IntrospectionException). Aber man kann den Fehlerbehandlungcode ja in eine Methode packen, die man aus dem catch-Block aus aufruft.
Zeig doch mal ein Codebeispiel, damit man sich von der Notwendigkeit dieser Vorgehensweise als ausnahmslose Regel überzeugen lassen kann.
public void load(String filename) {
try {
this.model = fromFile(filename);
} catch (FileNotFoundException ex) {
this.inform("Die ausgewählte Datei existiert nicht.");
} catch (IOException ex) {
this.inform("Die Daten konnten nicht geladen werden. Eventuell ist die Datei beschädigt oder sie haben nicht die notwendigen Berechtigungen.");
} catch (ClassNotFoundException ex) {
this.inform("Die Daten konnten nicht geladen werden. Vermutlich wurden sie mit einer anderen Version abgespeichert oder sie haben nicht die erforderlichen Plug-ins");
}
}
Wie man hier sieht, wird wirklich etwas gemacht, und nicht einfach nur geloggt, was kaum besser ist als err.printStacktrace().
HellHorse[/POST]']
Das wird nur funktionieren wenn du den kompletten Sourcecode aller Libraries hast. Die IDE muss dann den parsen, viel Spass bei der Java Library.
Unsinn. Erstens reicht der Bytecode und zweitens muss man das nicht auf Textebene implementieren (solltest du als Smalltalk-Kenner eigentlich wissen).
Checked Exceptions bringen einem nix was man nicht sowieso schon haben kann. Im Gegenzug führen sie tendenziell zu falscher statt fehlender Fehlerbehandlung und selbst wenn man sie "richtig" benutzt führen sie zu schwerer restrukturierbarem und/oder längerem Sourcecode.
HellHorse
2006-04-28, 21:43:43
Unsinn. Erstens reicht der Bytecode und zweitens muss man das nicht auf Textebene implementieren (solltest du als Smalltalk-Kenner eigentlich wissen).
Ja schon, aber weiss du was für ein Aufwand das ist? Du kannst nicht einfach kurz mal den bytecode aller direkt in Frage kommender Methoden nach Exception Klassen scannen. Du musst wirklich wissen was einem throw übergeben wird. Dann musst du natürlich noch all die Methoden durchgehen, die indirekt aufgerufen werden können. Dazu brauchst du jede Menge statischer Typinformation, die dir ein normaler AST nie biet. Ich sehe nicht wie das ohne Dekompilation auch nur ansatzweise gehen sollte. Womit wir wieder auf dem Source Level sind.
Und wenn wir gerade bei dynamischen Sprachen wie Smalltalk sind, dort fällt zwar der ganze statische Kram weg, dadurch wird es aber um einiges schwerer zu bestimmen, welche Methoden wirklich aufgerufen werden und welche Exceptions dadruch wirklich geworfen werden können (bei ruby und co ist es noch einmal schwerer). Daneben werden dort Exceptions ja noch für andere Sachen wie z.B. dynamische Variablen verwendet. Darum lautet die Regel, wenn man rausfinden will welche Exceptions eine Methode werfen kann ja auch das Paket nach Exceptions zu browsen und deren Referenzen anzuschauen und dann ein paar mal senders und implementors zu browsen und wenn man Glück hat, findet man das richtige (irgendwie habe ich das Gefühl, das wird in einer zukünftigen Diskussion auf micht zurückkommen ;) ).
Schlussendlich läuft es darauf raus, dass du die gleiche statische Analyse machen musst wie der Compiler bei checked exceptions. Nur dass du vorher noch dekompilieren musst und es nicht im Sourcode dokumentiert und persistent ist. Zudem ist es schwer zwischen "wichtigen" (den jetzigen checked exceptions) und "unwichtigen" (den jetztigen uncheck exceptions) zu unterscheiden. Das sieht mittlerweise wirklich verdammt ähnlich aus wie checked exceptions.
Im Gegenzug führen sie tendenziell zu falscher statt fehlender Fehlerbehandlung
Was noch zu beweisen wäre. Idioten können alles misbrauchen auch Temps. Deswegen sind aber Temps nicht schlecht.
führen sie zu schwerer restrukturierbarem
Da brauchst halt Toolsupport wie die böse gehypte IDE. Aber die bietet dir ja auch den Button und den nötigen Toolsupport um die statische Analyse zu machen (abgesehen von Dekompilation).
und/oder längerem Sourcecode
Diese zwei, drei Tokens im Methodenheader machen den Kuchen dann auch nicht mehr fett. Wenn ich mir anschaue wie viel da sonst für Scheiss wie modifiers und annotations aufgewendet wird. Und es im Kommentar zu dokumentieren wäre sowieso noch ein grösserer Aufwand.
HellHorse[/POST]']
Darum greifft ja Vererbung. Da FileNotFoundException von IOException erbt kann ich FileNotFoundException gleich mit catch (IOException) behandeln.
Mir ergibt sich die ganze Logik nicht, die du hier vermitteln willst. Auf der einen Seite willst du differenziert reagieren, auf der anderen Seite willst du dir die Vererbungshierachie zu Nutze machen und Abkürzungen nehmen. Dann könntest du gleich auf Exception abfragen, weil ja IOException ebenfalls davon abgeleitet ist.
public void load(String filename) {
try {
this.model = fromFile(filename);
} catch (FileNotFoundException ex) {
this.inform("Die ausgewählte Datei existiert nicht.");
} catch (IOException ex) {
this.inform("Die Daten konnten nicht geladen werden. Eventuell ist die Datei beschädigt oder sie haben nicht die notwendigen Berechtigungen.");
} catch (ClassNotFoundException ex) {
this.inform("Die Daten konnten nicht geladen werden. Vermutlich wurden sie mit einer anderen Version abgespeichert oder sie haben nicht die erforderlichen Plug-ins");
}
}
Wie man hier sieht, wird wirklich etwas gemacht, und nicht einfach nur geloggt, was kaum besser ist als err.printStacktrace().
Und was soll das bringen? Dass du einfach noch eine deutsche Übersetzung zum sowieso vorhandenen Fehlertext einer Exception mitgegeben hast?
Sofern man nicht auf spezielle kritische Exceptions umgehend reagieren muss, lässt sich das alles so einfach reduzieren:
try {
this.model = fromFile(filename);
} catch (Exception ex) {
this.inform(ex); // inform kann dann den z.B. ex.getMessage() abfragen
}
Monger
2006-04-29, 08:55:58
@Hellhorse:
mit "this.inform" meinst du eine Fehlerbehandlung durch das Model, nicht wahr? Sowas, dass in der View dann eine Infobox hochpopen lässt und einem sagt: "Das Laden wurde abgebrochen, weil dies kein gültiger Speicherstand ist."
Oder so ähnlich. Habe ich dich so richtig verstanden?
HellHorse
2006-04-29, 15:01:53
Gast[/POST]']Mir ergibt sich die ganze Logik nicht, die du hier vermitteln willst. Auf der einen Seite willst du differenziert reagieren, auf der anderen Seite willst du dir die Vererbungshierachie zu Nutze machen und Abkürzungen nehmen.
Indem ich die Exceptions nicht mit einer genersichen Exception wrappe erhalte ich mir Flexibilität. Der aufrufende Code kann dann selbst entscheiden ob er IOException und FileNotFoundException gesondert behandlen möchte oder nicht. Zum Beispiel im interaktiven Modus für den Fall einer FileNotFoundException überprüfen will, ob das File ein Verzeichnis war oder noch einmal einen FileDialog anzeigen will. Wogegen im Batch Modus dieser Unterschied keine Rolle spielt.
Gast[/POST]']
Und was soll das bringen? Dass du einfach noch eine deutsche Übersetzung zum sowieso vorhandenen Fehlertext einer Exception mitgegeben hast?
Nein, der Fehlertext ist technisch hat meist keine Angaben über Gründe und macht keine Vorschläge zur Lösung. Den willst du nicht dem User präsentieren. Zudem sind Exceptions ja auch kontextabhängig. Eine IOException beim Speichern bedeutet meist etwas anderes und hat andere mögliche Ursachen als eine beim Laden. Während z.B beim Laden die Leserechte das Problem sein können, sind es beim Speichern die Schreibrechte. Man kann im Falle einer IOException das überprüfen und so eine bessere Fehlermeldung anzeigen.
Gast[/POST]']
Sofern man nicht auf spezielle kritische Exceptions umgehend reagieren muss, lässt sich das alles so einfach reduzieren:
Wenn man deinen Anstatz weiterverfolgt, kann man dem User ja auch gleich einen Fehlercode anzeigen, den er dann im Handbuch nachschlagen oder bei der Hotline nachfragen kann.
HellHorse[/POST]']Indem ich die Exceptions nicht mit einer genersichen Exception wrappe erhalte ich mir Flexibilität. Der aufrufende Code kann dann selbst entscheiden ob er IOException und FileNotFoundException gesondert behandlen möchte oder nicht.
Da geht natürlich auch so, indem du einfach auf die InnerException abfragst.
Aber ich habe ja auch schon x mal gesagt, dass man gesondert reagieren kann, wenn man eben muss. Nur wegen Fehlertext und Logging würde ich es nicht machen, da es meiner Meinung nach zu viele Nachteile hat.
Anders herum kannst du es nämlich immer noch ändern, falls nötig. Wenn der Code aber dann schon mal vollgehunzt von zig Catchs an zig Codestellen ist, musst du dann alles auch immer schön aufwendig pflegen, je nach dem wie generisch man es macht.
Nein, der Fehlertext ist technisch hat meist keine Angaben über Gründe und macht keine Vorschläge zur Lösung. Den willst du nicht dem User präsentieren.
Selbst dann brauche ich nicht mehrere Catchs, sondern habe eine generische Klasse, die sich anhand des InnerException Typs eben die entsprechenden Texte heraussucht. Wegen sowas würde ich mir den Code nicht verhunzen (redundant, unübersichtlich...).
Zudem sind Exceptions ja auch kontextabhängig. Eine IOException beim Speichern bedeutet meist etwas anderes und hat andere mögliche Ursachen als eine beim Laden. Während z.B beim Laden die Leserechte das Problem sein können, sind es beim Speichern die Schreibrechte. Man kann im Falle einer IOException das überprüfen und so eine bessere Fehlermeldung anzeigen.
In dem Fall würde ich einer custom Exception einen Fehlercode für die Stelle mitgeben, also z.B. Laden oder Speichern. Zusätzlich wird noch die auslösende Exception mitgegeben. Die custom Exception kann dann ausgehend vom Fehlercode und dem Typ der auslösenden Exception genau den Kontext herstellen.
HellHorse
2006-04-30, 10:52:31
Gast[/POST]']Da geht natürlich auch so, indem du einfach auf die InnerException abfragst.
Lass mich raten, instanceof oder switch über den Fehlercode? :ugly:
Gast[/POST]']
In dem Fall würde ich einer custom Exception einen Fehlercode
:ugly:
HellHorse[/POST]']Lass mich raten, instanceof oder switch über den Fehlercode? :ugly:
Was glaubst du denn, was dein Compiler mit deinem Catch macht? Natürlich wird dort auch eine Typüberprüfung vorgenommen, wie soll das auch anders funktionieren.
HellHorse
2006-04-30, 20:04:37
Gast[/POST]']Was glaubst du denn, was dein Compiler mit deinem Catch macht? Natürlich wird dort auch eine Typüberprüfung vorgenommen, wie soll das auch anders funktionieren.
Nein, der Compiler hat statische Typinformation, die du wegwirst. Dadurch kann er sicherstellen, dass kein möglicher Fall übersehen wurde oder ein unmöglicher Fall behandelt wurde. Etwas was du nicht mal im Anstatz kannst. Soviel zum Thema wartbar.
Exception Handling ist fest mit der VM verzahnt, der Compiler muss also keine instanceof oder casts erzeugen.
Aber wenn du ernsthaft switch und instanceof propagierst hat es wohl keinen Sinn weiterzudiskutieren.
HellHorse[/POST]']Nein, der Compiler hat statische Typinformation, die du wegwirst.
Bei einer Nicht-VM Sprache wie C++ ist das natürlich Angelegenheit des Compilers bzw. welche Exception Callback er beim OS registriert und wie dann weiterverfahren wird. Bei einer VM mag das anders sein, trotzdem wird in dem Falle eine Typüberprüfung vorgenommen zu welchem Typ im Catch die geworfene Exception passt.
"Exception Callbacks" vom Betriebssystem gibts nur bei Hardware-Exceptions.
HellHorse hat übrigens recht, das ist purer Müll was du hier propagierst.
Coda[/POST]']"Exception Callbacks" vom Betriebssystem gibts nur bei Hardware-Exceptions.
http://www.codeproject.com/cpp/exceptionhandler.asp
HellHorse hat übrigens recht, das ist purer Müll was du hier propagierst.
Schön für dich. Ich kaufe das euch trotzdem nicht ab, dass ihr bei jedem try/catch auf alle möglichen Exceptions abfragt. Außer euer Code ist recht trivial.
vBulletin®, Copyright ©2000-2024, Jelsoft Enterprises Ltd.