|
Das einfachste Java-Analogon zu dem mathematischen Begriff einer reellen Funktion
wie f(x)=sin(x) oder f(x)=x3-x+3 ist das einer
Methode mit Parameter (entspricht
dem Argument x der Funktion) und mit Rückgabewert
(entspricht dem Funktionswert f(x)) vom Typ double.
Nehmen wir an, wir wollen eine Wertetabelle für die Funktion
f(x)=sin(2x)+cos(x) anlegen. Dann muss f(x) wiederholt
ausgewertet werden. Dabei wird die Abbildungsvorschrift nur einmal separat abgespeichert
- als Methode:
static double f(double x){
return Math.sin(2*x)+Math.cos(x);
}//Ende des Methodenblocks
f ist der Bezeichner der Methode, x
der Parameter. Das erste double kenzeichnet den Typ des Rückgabewertes.
Mit return wird der Rückgabewert der Methode "retourniert".
Man achte auf die geschweiften Klammern des Methodenblocks.
Ein Javaprogramm, das eine Wertetabelle mit Hilfe eines Aufrufs dieser Methode
erstellt, kann so aussehen:
class Methode1{
static double f(double x){
return Math.sin(2*x)+Math.cos(x);
}//Ende des Methodenblocks
public static void main(String[] args){
double x=0;
while (x<1) {
System.out.println(
"x="+x+" f(x)="+f(x));
x+=0.1;
}//Ende while
}//Ende main()
}//Ende class Methode1
Zunächst wird die Methode f vereinbart.
Der Zusatz (Modifier) static muss wie bei der Methode
main() stehen, weil es sich um eine Klasse handelt, von der keine
Instanz gebildet werden soll, also um eine reine Applikationsklasse. Verstehen
kann man dies erst, wenn mit Objekten gearbeitet wird.
Man achte darauf, wie im main()-Block die Methode zur Auswertung
der Funktion aufgerufen wird: genauso, wie man es intuitiv machen würde.
In obigem Beispiel war x sowohl ein Bezeichner für
den Parameter der Methode f als auch für die Variable
im main-Block, die als Parameter in f eingesetzt wird.
Das muss nicht sein:
class Methode1a{
static double f(double x){
return Math.sin(2*x)+Math.cos(x);
}//Ende des Methodenblocks
public static void main(String[] args){
double y=0;
while (y<1) {
System.out.println(
"x="+y+" f(x)="+f(y));
y+=0.1;
}//Ende while
}//Ende main()
}//Ende class Methode1a
Verzweigungen erlauben die bedingte Ausführung von Anweisungen und sind
damit unerlässlich für die Steuerung von Programmabläufen.
Reelle Funktionen haben zuweilen einen eingeschränkten Definitionsbereich.
So muss bei der Wurzelfunktion das Argument nichtnegativ sein, bei rationalen
Funktionen darf der Nenner nicht verschwinden. Dies kann im Methodenblock realisiert
werden:
static double f(double x){
double y; //wird durch y=0 initialisiert
if ((x>=0) & (x!=4)){
y= 1/(Math.sqrt(x)-2);
}//Ende des if-Blocks
return y; //Muss ausserhalb des if-Blocks stehen
}//Ende des Methodenblocks
Der if-Block umfasst mehr als eine Anweisung und muss
daher durch geschweifte Klammern eingeschlossen werden. Bei nur einer Anweisung
können diese Klammern fehlen. Die Syntax einer if-Verzweigung
lautet if (A) B. Dabei ist A ein Boole'scher Ausdruck und
B ist ein Block von Anweisungen. Wenn A false ist, bewirkt
die if-Verzweigung gar nichts.
Der Compiler achtet bei einer Methode mit Rückgabewert streng darauf, dass
in jedem Fall ein Wert zurückgegeben wird. Wenn die return y -Zeile
in den if-Block wechselt, hat dies eine Fehlermeldung bei der Compilierung
zur Folge. Unsere Methode hat den offensichtlichen Nachteil, dass der Wert y=0
zurückgegeben wird, wenn x=4 oder x<0. Mit einem
else-Zusatz wird dies anders (s.u.).
Allgemein dienen Verzweigungen dazu, bestimmte Programmteile beim Eintreten
gewisser Bedingungen, die erst zur Laufzeit bekannt sind, ausführen zu lassen.
In Ergänzung mit else kann die Verzweigung variabler
gehandhabt werden:
//Methode2
static double f(double x){
if ((x>=0) & (x!=4)){
double y= 1/(Math.sqrt(x)-2);
return y;
}//Ende des if-Blocks
else {
System.out.println(
"x="+x+" ist nicht im Definitionsbereich");
return Double.NaN;
}//Ende else-Block
}//Ende des Methodenblocks
Die Syntax einer if-else-Anweisung lautet: if (A) B else C.
Dabei sind B und C Blöcke von Anweisungen.
Ohne den return-Befehl in vorletzten Zeile hätte
es den Compilerfehler Return required at end of double f(double)
gegeben. Doch was soll zurückgegeben werden, wenn der Parameter x
nicht im Definitionsbereich der Funktion f ist? Zum Glück kennt Java
die Konstante Double.NaN, wobei NaN für Not a Number steht und die als double-Rückgabewert akzeptiert wird.
Will man mehrere verschiedene Fälle abarbeiten (Mehrfachverzweigung), sollte man switch verwenden.
Unter Umständen reichen aber reine wahr - falsch Bewertungen, wie bei if oder if-else, nicht aus, den Programmfluss zu beeinflussen. Dann ist der Einsatz von switch-case Konstrukten gefragt.
In Abhängigkeit einer integer Variablen können beliebig viele verschiedene Fälle betrachtet werden.
Betrachten wir einmal folgenden Fall: Sie wollen Ihre Ausgabe anpassen und den jeweiligen Wochentag ausgeben:
//Methode3
int tag;
switch (tag) {
case 1 : System.out.println("Montag");
break;
case 2 : System.out.println("Dienstag");
break;
case 3 : System.out.println("Mittwoch");
break;
case 4 : System.out.println("Donnerstag");
break;
case 5 : System.out.println("Freitag");
break;
case 6 : System.out.println("Samstag");
break;
case 7 : System.out.println("Sonntag");
break;
} // Ende switch
Jeder Anweisungsblock sollte (muss nicht!) mit einem break; abgeschlossen werden. Das Wort bedeutet: geh an das Ende der switch Anweisung.
Sollen mehrere Werte betrachtet werden, so können diese zusammengefasst werden:
//Methode4
int tag;
switch (tag) {
case 1 :
case 2 :
case 3 :
case 4 :
case 5 : System.out.println("Werktag");
break;
case 6 :
case 7 : System.out.println("Wochenende");
break;
} // Ende switch
Auch hier wird die Bearbeitung der switch Anweisung erst beendet, wenn ein break; erreicht wird.
Bitte beachten Sie aber, dass Auswertungen oder Vergleiche wie z.B. switch (tag) { case tag<5: ...} nicht erlaubt sind!
Ein anderer, manchmal sehr nützlicher Bestandteil der switch Anweisung ist die Option default. Stellen Sie sich vor, dass der Wert der Ganzzahl den Wert 7 überschreitet. Jedes ordentliche Programm sollte diesen Fall abfangen und darauf achten, dass nichts Unsinniges passiert. Erweitern wir also das Beispiel Methode3 um diesen Fall:
//Methode3
int tag;
switch (tag) {
case 1 : System.out.println("Montag");
break;
case 2 : System.out.println("Dienstag");
break;
case 3 : System.out.println("Mittwoch");
break;
case 4 : System.out.println("Donnerstag");
break;
case 5 : System.out.println("Freitag");
break;
case 6 : System.out.println("Samstag");
break;
case 7 : System.out.println("Sonntag");
break;
default : System.out.println("Ungültiger Tag");
break;
} // Ende switch
Wenn die switch Anweisung keine default-Option enthält, und kein Fall dem aktuellen Wert der Variablen entspricht, werden alle Optionen ignoriert. Die switch Anweisung ist sehr nützlich, aber leider nicht so flexibel, wie in anderen Programmiersprachen.
Da Methoden ein zentraler Begriff auch des OOP ist, soll der erste Umgang mit ihnen sicherer werden.
Zunächst ein Beispiel für eine Methode mit zwei Parametern und einem Rückgabewert - sämtlichst vom Typ int:
//Methode5
static int modulo(int m, int n){
int M=m;
while (M>=n) M-=n;
return M;
}//Ende modulo
Diese Methode modulo berechnet m modulo n (das ist der Rest der Division von m durch n). So, wie die Methode hier programmiert wurde, müssen beide Argumente positiv sein, um eine Endlosschleife zu vermeiden. Java hat hierfür einen eigenen arithmetischen Operator % vorgesehen, so dass es einer Programmierung wie der obigen nicht bedarf.
Es gibt auch Methoden ohne Rückgabewert wie die Methode main(). Diese müssen den Zusatz void tragen. Ein weiters Beispiel einer Methode ohne Rückgabewert ist die Methode System.out.println(). Diese könnte man durch die folgende Methode etwas kürzer mit schreibe() fassen, wenn man Schreibarbeit an der Tastatur sparen will:
static void schreibe(String s){
System.out.println(s);
}//Ende schreibe()
|