Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
ich wollte eine einfache Übung machen um das behandeln von Exceptions zu erlernen doch ich komme damit nicht zurecht
Mein versuch ist eine Methode zu entwickeln die mit die Fakultät berechnet. Das ganze würde ich gerne mit Preconditions (Exceptions) und Postconditions (Assertions) absichern.
Also die Fakultät ist immer >= 0, das Ergebnis ist damit auch immer >= 0, eine Zweite Fakultätsmethode sollte das selbe Ergebnis liefern wie diese, wenn der Variablenbereich überschritten wird soll eine Exceptioin auch noch raus geworfen werden.
Das ganze habe ich bis jetzt so gestaltet:
Java:
public static int fak(int n) throws Exception {
if(n<0)
throw new InputException();
int erg=1;
int tmp=n;
while(tmp>0) { //hier muss noch geprüft werden wenn Integer.MAX_VALUE überschritten wurde wirf: //MaxValueException ()
erg=erg*tmp;
tmp--;
}
assert erg>=0: "Ergebnis muss Positiv sein";
assert erg == fakRekursiv(n);
return erg;
}
public static int fakRekursiv(int n) {
if (n==0)
return 1;
else return n*fakRekursiv(n-1);
}
Wie müsste ich das mit dem Interger.MAX_VALUE machen und wie muss ich den try und catch block nutzen? Ich verstehe das Thema leider irgendwie nicht so richtig
public static int fak(int n) throws Exception {
if(n<0)
throw new InputException();
long erg=1;
int tmp=n;
while(tmp>0) {
if(erg>Integer.MAX_VALUE)
throw new MaxValueException();
erg=erg*tmp;
tmp--;
}
assert erg>=0: "Ergebnis muss Positiv sein";
assert erg == fakRekursiv(n);
return (int) erg;
}
public static int fakRekursiv(int n) {
if (n==0)
return 1;
else return n*fakRekursiv(n-1);
}
public static void main(String[] args) throws Exception {
try {
System.out.println(fak(0));
}
catch (InputException ex){
System.out.println("Falsche Zahl eingegeben!");
}
catch (MaxValueException ex) {
System.out.println("Die Zahl ist nicht mehr darstellbar!");
}
}
Dennoch habe ich Fragen zum Thema: 1. Wie kann ich try und catch in die Methode schreiben damit die Fehlermeldung schon dort abgefangen werden?
2. Wieso muss ich in der Main dann throws Exception schreiben? sollte man das dann immer in der Main machen?
while(tmp>0 && erg <= Integer.MAX_VALUE) {
erg=erg*tmp;
tmp--;
}
if (erg > Integer.MAX_VALUE) {
System.err.println("Großer Mist");
// und/oder auch
// throw new MaxValueException();
}
2. Nein und nein.
Bei der main-Methode anzugeben, dass sie eine Exception wirft, ist keine gute Idee. Das verwendet man eigentlich nur, wenn man ein kleines (Test-)Programm hat, bei dem man sich nicht noch um das Exceptionhandling kümmern will.
Gute Frage mein Problem ist das ich mir das Thema zwar angeschaut habe doch keine Übung damit habe und dann stehe ich da wie ein KLEINES KIND und weis nicht was ich tun muss/soll
So habe ich nun mal die Methode abgeändert:
Java:
public static int fak(int n) throws InputException, MaxValueException {
if(n<0) throw new InputException();
int tmp=n; int erg=1;
while(tmp>0 && erg <= Integer.MAX_VALUE) {
erg=erg*tmp;
tmp--;
}
if (erg > Integer.MAX_VALUE)
throw new MaxValueException();
assert erg>=0: "Ergebnis muss Positiv sein";
assert erg == fakRekursiv(n);
return (int) erg;
}
Jetzt werden Exceptions geworden sobald eben eine Fehlerquelle auftritt.
Wie fängt man diese nun ab? Da ich diese Funktion ja nur in der Main ausführe sieht die Main immer noch so aus :
Java:
public static void main(String[] args) throws Exception {
try {
System.out.println(fak(13));
System.out.println(3/0);
}
catch (InputException ex){
System.out.println("Falsche Zahl eingegeben!");
}
catch (MaxValueException ex) {
System.out.println("Die Zahl ist nicht mehr darstellbar!");
}
catch (Exception ex) {
System.out.println("Da lief etwas schief!");
}
}
Leider weiß ich nicht wie ich es anders machen kann / muss
Wir haben zu diesem Thema leider noch keine Übungen gehabt und ich finde auch keine Ordentliche Übungen im Internet also entweder aus den Fingern saugen
LG
HAHA
ich hab einfach eine output Methode geschrieben die dann try und catch macht
Jetzt stellt mir eine nächste Frage wieso muss ich oben bei der Methode fakOutput nicht die Excetpions angeben? Weil sie von Exception abgeleitet sind und damit impliziert mit aufgenommen sind denn Exception oder RuneTimeException und der gleichen schreibt man ja auch nicht hinter jede Methode (was ein glück)?
Ja das weiß ich. Schau mal oben dort hatte ich es in ein Long geschrieben und später in ein int gecastet ist zwar nicht schön aber es läuft.
Eine letzte kleine Frage habe ich noch wie kann man das besser Üben?
Denn das Thema mit der Vererbung musste ich auch erstmal 10x durchkauen bis ich es halbwegs jetzt verstanden habe
hihi danke euch beiden
Darum ging es mir in diesem Beispiel nicht wirklich.
Java:
public static int fak(int n) throws InputException, MaxValueException{
if(n<0)
throw new InputException();
long erg=1;
int tmp=n;
while(tmp>0) {
if(erg>Integer.MAX_VALUE)
throw new MaxValueException();
erg=erg*tmp;
tmp--;
}
assert erg>=0: "Ergebnis muss Positiv sein";
assert erg == fakRekursiv(n);
return (int) erg;
}
So sollte es gehen denn ab Fakultät von 13 passiert ein Überlauf! Da 6...... größer ist als 2...... Das ist zwar nicht schön mit dem Cast doch auf die Schnelle war mir heute nichts besseres eingefallen.
Ich hab noch ein anderes Problem das würde hier aber nicht hin gehören soll ich dafür jetzt aber wirklich erneut ein Thema erstellen?
in einer Klasse steht folgendes:
Code:
protected void f(X a) {
a = this;
}
Das steht in der Klasse Y als Methode.
Es existiert eine Klasse X und Y ist davon abgeleitet.
In X ist ein Datenelement
Java:
protected int a = 2;
Wenn die Methode oben aufgerufen wird was besagt dann aber a = this? Klar weiß ich das a die Referenzvariable von X ist. Kann nur leider mit a = this nicht viel anfangen.
Da braucht man nicht viel zu üben. Man muss sich nur klar machen, dass Exceptions nichts anderes als alternative Rückgabewerte sind.
Wenn Du Deine fak()-Methode ansiehst, dann gibt es unter anderem die Vor-/Nachbedingung: gib mir ein positives int, dann bekommst Du ein positives int.
Du könntest jetzt hergehen und den Spaß erweitern: wenn Du mir kein positives int gibst, dann geb ich dir auch kein positives int, sondern 0. Und falls das Ergebnis nicht mehr in ein int passt, dann kriegst Du halt -1. Man kann also Fehler durch spezielle Rückgabewerte anzeigen.
Das hat allerdings zwei Nachteile:
1. Man muss ständig Code zur Überprüfung schreiben:
Java:
int erg = fak(n);
if (erg > 0) {
/* ok */
} else {
/* Fehler */
}
Vergisst man das, kackt die Anwendung ggf. erst viel später an ganz anderer Stelle ab, weil mit falschen Werten weitergerechnet wird; das hat teils verheerende Folgen (s. z. B. Ariane-Rakete)
2. Was tun, wenn der Wertebereich der Funktion keine (oder zu wenige) speziellen Fehlerwerte zulässt?
Nehmen wir mal beispielhaft die Multiplikation an, konkret eine Methode der Form int multiply(int a, int b); Hier kannst Du keine Fehler durch einen speziellen Rückgabewert darstellen, ohne den Wertebereich zusätzlich einzuschränken.
Statt einfach ein int zurückzugeben, könnte man aber ein Objekt liefern, das sowohl das Ergebnis (falls existent) als auch einen Fehler speichern kann. Dieses Objekt kann also zwei verschiedene Rückgabewerte darstellen, die sich auch bzgl. ihres Typs unterscheiden können. So könnte ein solches Objekt für den Funktionswert ein int speichern, und darüber hinaus ein Fehlerobjekt, sagen wir mal vom Typ Exception.
Die multiply-Methode sähe fiktiv dann so aus:
Java:
public Result multiply(int a, int b) {
long value = a * b;
if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
return new Result(0,
new OutOfBoundsException("Ergebnis außerhalb des Wertebereichs"));
} else {
return new Result((int) value);
}
}
Der aufrufende Code könnte jetzt in etwa folgendes machen:
Java:
Result r = multiply(a, b);
if (r.success()) {
int ergebnis = r.value();
// mach mit ergebnis weiter
} else {
Exception ex = r.getException();
if (ex instanceof OutOfBoundsException) {
// aha, Wertebereich nicht eingehalten
} else {
// anderer, unbekannter Fehler
}
}
Das würde funktionieren, ist aber relativ umständlich (und hat den Nachteil, dass man den Rückgabetyp nur sehr allgemein angeben kann. Außerdem kann so das Problem aus 1. nicht gelöst werden.)
Das Ganze wird nun dadurch vereinfacht, dass man in Java kein Result-Objekt benötigt, sondern bei der Methode einfach zusätzliche Rückgabetypen (Typen!) deklarieren kann, indem man der Methoden-Deklaration "throws" anfügt:
Java:
R methode() throws T1, T2, ... {
...
}
Die Methode liefert entweder einen Wert vom Typ R (der normale Rückgabwert) oder einen Wert vom Typ T1, oder vom Typ T2 usw. Voraussetzung: T2, T3, ... müssen Subtypen von Throwable sein.
Die multiply()-Methode ändert sich damit einfach zu
Code:
int multply(int a, int b) throws OutOfBoundsException { ... }
^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
vorhin Result.value vorhin Result.exception
bzw. im Zusammenhang:
Java:
public int multiply(int a, int b) throws OutOfBoundsException {
long value = a * b;
if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) {
throw new OutOfBoundsException("Ergebnis außerhalb des Wertebereichs"));
} else {
return (int) value;
}
}
Im then-Zweig gibt die Methode also ein Objekt vom Typ OutOfBoundsException zurück, im else-Zweig dagegen einen primitiven Wert vom Typ int. Spätestens jetzt sollte klar sein, dass "throws" einfach alternative Rückgabetypen einer Methode deklariert.
Der Code des Aufrufers hat jetzt (nicht ganz zufällig ) verblüffende Ähnlichkeit zum Code von vorhin. In der Gegenüberstellung:
Java:
// Object result = multiply(a,b);
try { // if (result.success()) {
int ergebnis = multiply(a, b); // int ergebnis = result.value();
// else {
// Exception ex = result.exception();
} catch (OutOfBoundsException ex) { // if (ex instanceof OutOfBoundsException) {
// aha, Wertebereich... // // aha, Wertebereich...
} catch (Exception ex) { // } else {
// unbekannter Fehler // // unbekannter Fehler
} // }
// }
Kommen wir von "alternativen Rückgabetypen" zurück zum normalen Sprachgebrauch: throws gibt einfach an, dass eine Methode Exceptions auslösen (werfen) kann und vom welchem Typ diese Exceptions sind.
Wie wird nun das unter 1. angeführte Problem gelöst?
Mit Ausnahmen gilt in Java: hat eine Methode m per throws deklariert, dass sie Exceptions auslösen kann, müssen diese vom Programmierer bei der Verwendung von m behandelt werden.
Zur Behandlung gibt es zwei Möglichkeiten:
der Programmierer fängt die Exception(s) ab, dazu verwendet er try-catch; Beispiel siehe oben.
falls der Aufruf von m in einer Methode stattfindet, kann der Programmierer sich dazu entscheiden, eine von m geworfene Exception einfach weiter zu reichen. Dazu deklariert er einfach den Typ der Exception mittels throws bei der Methode, die m aufruft. Hört sich fürchterlich kompliziert an, ist aber ganz einfach:
Java:
public int calc() throws OutOfBoundsException {
return multiply(x, y);
}
Wird calc() aufgerufen und löst multiply(x,y) tatsächlich eine OutOfBoundsException aus, wird diese Exception einfach an den Aufrufer von calc durchgeschleift. Der muss sich jetzt darum kümmern, schließlich hat calc per throws deklariert, dass eine OutOfBoundsException auftreten kann.
Zum Abschluss noch kurz zu den oben angesprochenen Ausnahmen. Für alle Errors (Subtypen von java.lang.Error) und alle RuntimeExceptions (Subtypen von java.lang.RuntimeException) ist keine Deklaration per throws notwendig und der Programmierer wird vom Compiler nicht dazu gezwungen, diese Exceptions explizit zu behandeln. Vielmehr erfolgt ein implizites Durchschleifen dieser Exceptions.
Wenn Du das in Action sehen willst, teile einfach mal eine Zahl durch 0
Übrigens: Exceptions, die vom Programmierer zwangsweise behandelt werden müssen, nennt man auch "checked" Exceptions, die anderen "unchecked".