LGS
try, catch, throw
)double[][] A = new double[n][n]
oder ohne
new
z.B. durch double[][]
A={{1,2,3},{-2,3,0},{2,3,-1}};
erfolgt.
In der linearen Algebra werden die Zeilen und Spalten einer (m x
n)-Matrix von 1 bis m und 1 bis n durchnumeriert. In Java werden
dagegen die Komponenten der Felder (z.B. double[][] A= new
double[m][n];
) bei 0 beginnend und bei m-1
bzw. n-1 endend indiziert. Auf diese wird mit A[i][j]
i=0,1,...,m-1, j=0,1,...,n-1 zugegriffen. Bei allen Java-Implementierungen
von Algorithmen der numerischen Linearen Algebra muss man also meist
einen (ärgerlichen) Shift der Indizes durchführen.
Man kann auch nichtrechteckige Felder allokieren. Z.B. durch
oder durchint n=5; double[][] A = new double[n][]; for(int j=0;j<n;j++) A[j]= new double[j+1];
werden dreieckige Felder in Form unterer Dreiecksmatrizen allokiert.double[][] A={{1},{1,2},{1,2,3}};
Exceptions
Es gibt sehr strukturierte Möglichkeiten, Laufzeitfehler
aufzufangen, ohne dass das Programm zwingend abbricht. Die
häufigsten Laufzeitfehler, die bisher auftraten, sind
z.B. IndexOutOfBoundsException
beim versehentlichen
Zugriff auf Komponenten von Feldern außerhalb der definierten
Grenzen oder NullPointerException
, wenn ein Objekt nur
deklariert, aber nicht allokiert wurde, aber dennoch auf dessen Daten
oder Methoden zugegriffen wird, oder auch
ArithmeticException
, etwa bei (int
-)
Division durch Null. Alle diese Laufzeitfehler sind Unterklassen der
Klasse Exception
. Wenn diese Fehler auftreten, wird die
Ausführung des Programms mit einer entsprechenden Meldung des
Fehlertyps abgebrochen.
Dies kann mit der try-catch
-Anweisung verhindert werden.
Durch die catch
-Anweisung wird der Fehler
"behandelt". Zuvor kann er mit Hilfe einer throw
-Anweisung
auch "weitergegeben" werden. Eine genauere Erörterung
dieser Fehlerbehandlung kann hier nicht erfolgen, sondern muss
in einem Lehrbuch nachgelesen werden. Ich werde mich hier
mit Beispielen begnügen:
In Zeile 2 wird durch1 class fehler1{ 2 static double w(double x) throws Exception{ 3 if (x<0) throw new Exception>("Das Argument "+x+" ist negativ!"); 4 return Math.sqrt(x); 5 } 6 static void main(String[] args){ 7 try{ 8 for(int i=0;i<h;10;i++) 9 System.out.println(w(Math.sin(i*3.1))); 10 } 11 catch(Exception e){System.out.println(e);} 12 }//Ende main() 13}//Ende class fehler1
throws Exception
die "Weitergabe" eines Fehlers des allgemeinen Typs Exception
angekündigt, der in Zeile 3 definiert wird, wenn das Argument
der "Wurzel"-Methode w()
negativ ist (ohne diese
"Ausnahmeweitergabe" würde der Wert NaN
in Zeile 5
zurückgegeben werden). Der Konstruktor von Exception
(Zeile 3) sieht die Übergabe eines Strings vor, der in Zeile 11
ausgegeben wird. Genauer: Jedes Java-Objekt kennt die
Methode String toString()
, die immer zur Anwendung
kommt, wenn das Objekt als Parameter von System.out.println()
auftritt.
Vielleicht wird dies klarer, wenn man eine eigene Fehlerklasse, z.B.
durch
class EigenerFehler extends Exception{
String Grund;
EigenerFehler(String Grund){
this.Grund=Grund;
}//Ende Konstruktor
public String toString(){
return Grund;
}//Ende Ueberlagerung von toString()
}//Ende class EigenerFehler
definiert, den man etwa durch throw new Eigenerfehler("Pivotelement
verschwindet");
weitergeben kann.
Nun zur try-catch
-Anweisung. Falls in Zeile 9 der
Aufruf von w()
zu einem Fehler (in Zeile 3) führt,
wird dieser "behandelt", indem
der try
-Block sofort verlassen und die
catch
-Anweisung in Zeile 11 angesteuert wird, sofern
der aufgetretene Fehler von dem Typ ist, der in den runden
Klammern hinter catch
steht. Hier ist dies der Fall,
weil unser Fehler vom allgemeinsten Typ Exception
ist. Ausgeführt wird dann der catch
-Block
(hier eine Ausgabe des Fehlers samt mit ihm verbundener in Zeile 3
festgelegten "individuellen" Text).
Danach würde das Programm in Zeile 12 fortfahren, ein Abbruch
wie bei einem nicht behandelten Laufzeitfehlers findet also nicht
statt, es sei denn, der catch
-teil enthält den
Befehl System.exit(1);
.
Das folgende Beispiel behandelt den Laufzeitfehler
ArithmeticException
:
for (int j=-3;j<3;j++)
try{
System.out.println(1/j);
}
catch(ArithmeticException e){System.out.ptintln(e);}
Dieser Programmteil würde zu der folgenden Ausgabe führen:
0
0
-1
java.lang.ArithmeticException: / by zero
1
0
Grundsätzlich könnten Fehlerbehandlungen auch konventionell
mit Hilfe vieler Verzweigungen (if, switch
) erfolgen.
Das hier geschilderte Vorgehen hat den Vorteil, dass Verzweigungen
nur zur Ablaufsteuerung des Algorithmus verwendet werden.
Im Kap.4 über lineare Gleichungssysteme werden wir
die hier besprochene Fehlerbehandlung u.a. auf das
Auftreten verschwindender Pivotelemente beziehen.
Hier geben wir einen Auszug der Klasse LGS
wieder, die ebenfalls nur
statische Methoden enthält:
public class LGS{
//Alle Routinen mit Ueberschreibung der Felder
//Es geht nur um quadratische Matrizen
static int n; //Dimension
//Im folgenden wird a ueberschrieben (Kein Zeilentausch):
public static void LRZerlegung(double[][] a) throws Exception{
n=a.length;
for(int k=0;k=0;k--){
for (int j=n-1;j>=k+1;j--) b[k]-=R[k][j]*b[j];
b[k]/=R[k][k];
}//Ende k
}//Ende rw()
public static void LoeseLGS(double[][] a,double[] b){
try{
LRZerlegung(a);
vw(a,b);
rw(a,b);
}
catch(Exception e){
System.out.println(e);System.exit(1);
}
}//Ende LoeseLGS()
public static void main(String[] args){
//Test:
double[][] A1={{4,-1,2,0},{-1,3,1,-1},{1,0,5,3},{0,-1,0,2}};
double[] b1={5,2,9,1};
LoeseLGS(A1,b1); //Loesung ist (1,1,1,1)
for (int k=0;k<=3;k++) System.out.println(b1[k]);
}//Ende main()
}//Ende class LGS
Für die nachfolgenden numerischen Probleme (Lineare Optimierung,
Lineare Ausgleichsprobleme, nichtlineare Gleichungen und
Gleichungssysteme) wurden keine neuen Javaaspekte behandelt. Daher
fehlen hier entsprechende Demonstrationsprogramme.