Kapitel 4. Methoden und Tests

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Bis jetzt haben wir Programme geschrieben, die nur eine Methode haben, die main heißt. In diesem Kapitel werden wir dir zeigen, wie du Programme mit mehreren Methoden organisieren kannst. Außerdem werfen wir einen Blick auf die Klasse Math, die Methoden für gängige mathematische Operationen bietet. Schließlich besprechen wir Strategien für die schrittweise Entwicklung und das Testen deines Codes.

Neue Methoden definieren

Einige Methoden führen eine Berechnung durch und geben ein Ergebnis zurück. Zum Beispiel liest nextDouble Eingaben von der Tastatur und gibt sie als double zurück. Andere Methoden, wie println, führen eine Folge von Aktionen aus, ohne ein Ergebnis zurückzugeben. Java verwendet das Schlüsselwort void um solche Methoden zu definieren:

public static void newLine() {
    System.out.println();
}

public static void main(String[] args) {
    System.out.println("First line.");
    newLine();
    System.out.println("Second line.");
}

In diesem Beispiel sind die Methoden newLine und main beide public, was bedeutet, dass sie von anderen Klassen aus aufgerufen (oder aufgerufen) werden können. Und sie sind beide void, was bedeutet, dass sie kein Ergebnis zurückgeben (im Gegensatz zu nextDouble). Die Ausgabe des Programms ist hier zu sehen:

First line.

Second line.

Beachte den zusätzlichen Abstand zwischen den Zeilen. Wenn wir mehr Platz zwischen den Zeilen haben wollen, können wir dieselbe Methode wiederholt aufrufen. Oder wir könnten eine weitere Methode (mit dem Namen threeLine) schreiben, die drei Leerzeilen anzeigt:

public class NewLine {

    public static void newLine() {
        System.out.println();
    }

    public static void threeLine() {
        newLine();
        newLine();
        newLine();
    }

    public static void main(String[] args) {
        System.out.println("First line.");
        threeLine();
        System.out.println("Second line.");
    }
}

In diesem Beispiel lautet der Name der Klasse NewLine. Klassennamen beginnen üblicherweise mit einem Großbuchstaben. NewLine enthält drei Methoden, newLine, threeLine und main. Erinnere dich daran, dass in Java zwischen Groß- und Kleinschreibung unterschieden wird. NewLine und newLine sind also nicht dasselbe.

Konventionell beginnen Methodennamen mit einem Kleinbuchstaben und verwenden die Großschreibung "Kamel", was ein netter Name für jammingWordsTogetherLikeThis ist. Du kannst jeden beliebigen Namen für Methoden verwenden, außer main oder eines der Java-Schlüsselwörter.

Ablauf der Ausführung

Wenn du dir eine Klassendefinition ansiehst, die mehrere Methoden enthält, ist es verlockend, sie von oben nach unten zu lesen. Aber das ist nicht der Ablauf der Ausführung oder die Reihenfolge, in der das Programm tatsächlich ausgeführt wird. Das Programm NewLine führt die Methoden in der umgekehrten Reihenfolge aus, in der sie aufgelistet sind.

Programme beginnen immer mit der ersten Anweisung von main, unabhängig davon, wo sie sich in der Quelldatei befindet. Die Anweisungen werden der Reihe nach ausgeführt, bis du zu einem Methodenaufruf gelangst, den du dir als Umweg vorstellen kannst. Anstatt zur nächsten Anweisung zu gehen, springst du zur ersten Zeile der aufgerufenen Methode, führst dort alle Anweisungen aus und kommst dann zurück und machst genau dort weiter, wo du aufgehört hast.

Das klingt einfach, aber erinnere dich daran, dass eine Methode eine andere aufrufen kann. In der Mitte von main geht das vorherige Beispiel los, um die Anweisungen in threeLine auszuführen. In threeLine führt es newLine aus. Dann ruft newLine println auf, was einen weiteren Umweg bedeutet.

Zum Glück kann Java gut verfolgen, welche Methoden gerade laufen. Wenn also println fertig ist, macht es dort weiter, wo es in newLine aufgehört hat; wenn newLine fertig ist, geht es zurück zu threeLine; und wenn threeLine fertig ist, kommt es zurück zu main.

Anfänger fragen sich oft, warum es die Mühe wert ist, andere Methoden zu schreiben, wenn sie alles in main erledigen können. Das Beispiel NewLine zeigt ein paar Gründe dafür:

  • Wenn du eine neue Methode erstellst, kannst du einen Block von Anweisungen benennen, was den Code leichter lesbar und verständlich macht.

  • Durch die Einführung neuer Methoden kann das Programm kürzer werden, da sich wiederholender Code entfällt. Um zum Beispiel neun aufeinanderfolgende Zeilenumbrüche anzuzeigen, könntest du threeLine dreimal aufrufen.

  • Eine gängige Problemlösungstechnik besteht darin, Probleme in Teilprobleme zu zerlegen. Mit diesen Methoden kannst du dich auf jedes Teilproblem einzeln konzentrieren und es dann zu einer Gesamtlösung zusammensetzen.

Am wichtigsten ist vielleicht, dass du durch die Aufteilung deines Codes in mehrere Methoden die Möglichkeit hast, einzelne Teile deines Programms separat zu testen. Es ist einfacher, ein komplexes Programm zum Laufen zu bringen, wenn du weißt, dass jede Methode richtig funktioniert.

Parameter und Argumente

Einige der Methoden, die wir verwendet haben, benötigen Argumente. Das sind die Werte, die du in Klammern angibst, wenn du die Methode aufrufst.

Die Methode println benötigt zum Beispiel ein Argument String. Um eine Nachricht anzuzeigen, musst du die Nachricht angeben: System.out.println("Hello"). Auch die Methode printf kann mehrere Argumente annehmen. Die Anweisung System.out.printf("%d in = %f cmn", inch, cm) hat drei Argumente: den Formatstring, den inch Wert und den cm Wert.

Wenn du eine Methode aufrufst, gibst du die Argumente an. Wenn du eine Methode definierst, gibst du die Parameter an. Das sind Variablen, die angeben, welche Argumente erforderlich sind. Die folgende Klasse zeigt ein Beispiel:

public class PrintTwice {

    public static void printTwice(String s) {
        System.out.println(s);
        System.out.println(s);
    }

    public static void main(String[] args) {
        printTwice("Don't make me say this twice!");
    }
}

Die Methode printTwice hat einen Parameter namens s mit dem Typ String. Wenn du printTwice aufrufst, musst du ein Argument mit dem Typ String angeben.

Bevor die Methode ausgeführt wird, wird das Argument dem Parameter zugewiesen. Im Beispiel printTwice wird das Argument "Don't make me say this twice!" dem Parameter s zugewiesen.

Dieser Vorgang wird als Parameterübergabe bezeichnet, weil der Wert von außerhalb der Methode an das Innere weitergegeben wird. Ein Argument kann jede Art von Ausdruck sein. Wenn du also eine String Variable hast, kannst du ihren Wert als Argument verwenden:

String message = "Never say never.";
printTwice(message);

Der Wert, den du als Argument angibst, muss denselben (oder einen kompatiblen) Typ haben wie der Parameter. Wenn du zum Beispiel Folgendes versuchst:

printTwice(17);  // syntax error

Du wirst eine Fehlermeldung wie diese erhalten:

File: Test.java  [line: 10]
Error: method printTwice in class Test cannot be applied
       to given types;
  required: java.lang.String
  found: int
  reason: actual argument int cannot be converted to
          java.lang.String by method invocation conversion

Diese Fehlermeldung besagt, dass ein int Argument gefunden wurde, aber der erforderliche Parameter sollte ein String sein. Im Fall von printTwice wandelt Java die Ganzzahl 17 nicht automatisch in die Zeichenkette "17" um.

Manchmal kann Java ein Argument automatisch von einem Typ in einen anderen umwandeln. Zum Beispiel erfordert Math.sqrt einen double, aber wenn du Math.sqrt(25) aufrufst, wird der Ganzzahlwert 25 automatisch in den Fließkommawert 25.0 umgewandelt.

Parameter und andere Variablen existieren nur innerhalb ihrer eigenen Methoden. In dem printTwice Beispiel gibt es kein s in der Methode main. Wenn du versuchst, sie dort zu verwenden, bekommst du einen Compilerfehler.

Auch innerhalb von printTwice gibt es keine message. Diese Variable gehört zu main. Da Variablen nur innerhalb der Methoden existieren, in denen sie definiert sind, werden sie oft als lokale Variablen bezeichnet.

Mehrere Parameter

Hier ist ein Beispiel für eine Methode, die zwei Parameter benötigt:

public static void printTime(int hour, int minute) {
    System.out.print(hour);
    System.out.print(":");
    System.out.println(minute);
}

Um diese Methode aufzurufen, müssen wir zwei ganze Zahlen als Argumente angeben:

int hour = 11;
int minute = 59;
printTime(hour, minute);

Anfänger machen manchmal den Fehler, die Argumente zu erklären:

int hour = 11;
int minute = 59;
printTime(int hour, int minute);  // syntax error

Das ist ein Syntaxfehler, denn der Compiler sieht int hour und int minute als Variablendeklarationen und nicht als Ausdrücke, die Werte darstellen. Du würdest die Typen der Argumente nicht deklarieren, wenn sie nur ganze Zahlen wären:

printTime(int 11, int 59);  // syntax error

Wenn du die Codefragmente zusammenfügst, erhältst du das vollständige Programm:

public class PrintTime {

    public static void printTime(int hour, int minute) {
        System.out.print(hour);
        System.out.print(":");
        System.out.println(minute);
    }

    public static void main(String[] args) {
        int hour = 11;
        int minute = 59;
        printTime(hour, minute);
    }
}

printTime hat zwei Parameter, die hour und minute heißen. Und main hat zwei Variablen, die ebenfalls hour und minute heißen. Obwohl sie die gleichen Namen haben, sind diese Variablen nicht identisch. Die hour in printTime und die hour in main beziehen sich auf unterschiedliche Speicherplätze und können unterschiedliche Werte haben.

Du könntest printTime zum Beispiel so aufrufen:

int hour = 11;
int minute = 59;
printTime(hour + 1, 0);

Bevor die Methode aufgerufen wird, wertet Java die Argumente aus; in diesem Beispiel sind die Ergebnisse 12 und 0. Dann ordnet es diese Werte den Parametern zu. In printTime ist der Wert von hour 12 , nicht 11, und der Wert von minute ist 0, nicht 59. Wenn printTime einen seiner Parameter ändert, hat diese Änderung keine Auswirkungen auf die Variablen in main.

Stapeldiagramme

Eine Möglichkeit, den Überblick über die Variablen zu behalten, ist das Zeichnen eines Stack-Diagramms, eines Speicherdiagramms (siehe "Speicherdiagramme"), das die aktuell ausgeführten Methoden zeigt. Für jede Methode gibt es ein Feld, das als Rahmen bezeichnet wird und die Parameter und lokalen Variablen der Methode enthält. Der Name der Methode erscheint außerhalb des Rahmens; die Variablen und Parameter erscheinen innerhalb.

Wie die Speicherdiagramme zeigen auch die Stapeldiagramme Variablen und Methoden zu einem bestimmten Zeitpunkt. Abbildung 4-1 ist ein Stack-Diagramm zu Beginn der Methode printTime. Beachte, dass main ganz oben steht, weil es zuerst ausgeführt wurde.

Abbildung 4-1. Stack-Diagramm für printTime(hour + 1, 0).

Stack-Diagramme helfen dir, den Geltungsbereich einer Variablen zu visualisieren, also den Bereich eines Programms, in dem eine Variable verwendet werden kann.

Stack-Diagramme sind ein gutes mentales Modell dafür, wie Variablen und Methoden zur Laufzeit funktionieren. Wenn du lernst, die Ausführung eines Programms auf Papier (oder auf einem Whiteboard) zu verfolgen, ist das eine nützliche Fähigkeit, um mit anderen Programmierern zu kommunizieren.

Lernprogramme können automatisch Stack-Diagramme für dich zeichnen. Mit Java Tutor kannst du zum Beispiel ein ganzes Programm vorwärts und rückwärts durchlaufen und bei jedem Schritt die Stack-Frames und Variablen sehen. Wenn du es noch nicht getan hast, solltest du dir die Java-Beispiele auf dieser Website ansehen.

Mathe-Methoden

Du musst nicht immer neue Methoden schreiben, um deine Arbeit zu erledigen. Zur Erinnerung: Die Java-Bibliothek enthält Tausende von Klassen, die du verwenden kannst. Die Klasse Math bietet zum Beispiel allgemeine mathematische Operationen:

double root = Math.sqrt(17.0);
double angle = 1.5;
double height = Math.sin(angle);

Die erste Zeile setzt root auf die Quadratwurzel aus 17. Die dritte Zeile findet den Sinus von 1,5 (den Wert von angle). Math ist im Paket java.lang enthalten, du musst es also nicht importieren.

Die Werte für die trigonometrischen Funktionen -sin, cos und tan- müssen im Bogenmaß angegeben werden. Um von Grad in Bogenmaß umzurechnen, teilst du durch 180 und multiplizierst mit π. Praktischerweise stellt die Klasse Math eine Konstante namens PI bereit, die eine Näherung von π enthält:

double degrees = 90;
double angle = degrees / 180.0 * Math.PI;

Beachte, dass PI in Großbuchstaben geschrieben ist. Java erkennt Pi, pi oder pie nicht. Außerdem ist PI der Name einer Konstante, nicht einer Methode, und steht daher nicht in Klammern. Das Gleiche gilt für die Konstante Math.E, die eine Annäherung an die Eulersche Zahl darstellt.

Die Umrechnung von und nach Bogenmaß ist eine gängige Operation, daher bietet die Klasse Math Methoden, die das für dich erledigen:

double radians = Math.toRadians(180.0);
double degrees = Math.toDegrees(Math.PI);

Eine weitere nützliche Methode ist round, die einen Fließkommawert auf die nächste Ganzzahl rundet und long zurückgibt. Das folgende Ergebnis ist 63 (aufgerundet von 62,8319):

long x = Math.round(Math.PI * 20.0);

Ein long ist wie ein int, aber größer. Genauer gesagt verwendet ein int 32 Bits Speicherplatz; der größte Wert, den es speichern kann, ist 231-1das sind etwa 2 Milliarden. Eine long verwendet 64 Bits, also ist der größte Wert 263-1was ungefähr 9 Quintillionen entspricht.

Nimm dir eine Minute Zeit, um die Dokumentation für diese und andere Methoden in der Klasse Math zu lesen. Der einfachste Weg, die Dokumentation für Java-Klassen zu finden, ist eine Websuche nach "Java" und dem Namen der Klasse.

Zusammensetzung

Du hast wahrscheinlich gelernt, wie man einfache Ausdrücke auswertet wie sin(π/2) und log(1/x). Zuerst wertest du den Ausdruck in den Klammern aus, der das Argument der Funktion ist. Dann kannst du die Funktion selbst auswerten, entweder von Hand oder indem du sie in einen Taschenrechner eingibst.

Dieser Prozess kann wiederholt angewendet werden, um komplexere Ausdrücke wie log(1/sin(π/2)). Zunächst bewerten wir das Argument der innersten Funktion (π/2=1.57), dann werte die Funktion selbst aus (sin(1.57)=1.0), und so weiter.

Genau wie bei mathematischen Funktionen können Java-Methoden zusammengesetzt werden, um komplexe Probleme zu lösen. Das heißt, du kannst eine Methode als Teil einer anderen verwenden. Tatsächlich kannst du jeden Ausdruck als Argument für eine Methode verwenden, solange der resultierende Wert den richtigen Typ hat:

double x = Math.cos(angle + Math.PI / 2.0);

Diese Anweisung dividiert Math.PI durch 2, addiert das Ergebnis zu angle und berechnet den Kosinus der Summe. Du kannst auch das Ergebnis einer Methode als Argument an eine andere Methode weitergeben:

double x = Math.exp(Math.log(10.0));

In Java verwendet die Methode log immer die Basis e. Diese Anweisung findet also die logarithmische Basis e von 10 und hebt e dann auf diese Potenz an. Das Ergebnis wird x zugewiesen.

Einige mathematische Methoden benötigen mehr als ein Argument. Zum Beispiel nimmt Math.pow zwei Argumente und erhöht das erste mit der Potenz des zweiten. Diese Zeile berechnet210 und weist den Wert 1024.0 der Variablen x zu:

double x = Math.pow(2.0, 10.0);

Bei der Verwendung von Math Methoden vergessen Anfänger oft das Wort Math. Wenn du zum Beispiel einfach x = pow(2.0, 10.0) schreibst, bekommst du einen Compilerfehler:

File: Test.java  [line: 5]
Error: cannot find symbol
  symbol:   method pow(double,double)
  location: class Test

Die Meldung cannot find symbol ist verwirrend, aber die letzten beiden Zeilen geben einen nützlichen Hinweis. Der Compiler sucht nach einer Methode namens pow in der Datei Test.java (der Datei für dieses Beispiel). Wenn du keinen Klassennamen angibst, wenn du dich auf eine Methode beziehst, sucht der Compiler standardmäßig in der aktuellen Klasse.

Rückgabewerte

Wenn du eine void Methode aufrufst, steht der Aufruf normalerweise in einer eigenen Zeile. Zum Beispiel:

printTime(hour + 1, 0);

Wenn du hingegen eine Methode aufrufst, die einen Wert zurückgibt, musst du etwas mit dem Rückgabewert machen. Normalerweise weisen wir ihn einer Variablen zu oder verwenden ihn als Teil eines Ausdrucks, wie hier:

double error = Math.abs(expect - actual);
double height = radius * Math.sin(angle);

Im Vergleich zu den Methoden von void unterscheiden sich die Methoden mit Wertrückgabe in zweierlei Hinsicht:

  • Sie deklarieren den Typ des Rückgabewerts (den Rückgabetyp).

  • Sie verwenden mindestens eine return Anweisung, um einen Rückgabewert zu liefern.

Hier ein Beispiel aus einem Programm namens Circle.java. Die Methode calculateArea nimmt einen double als Parameter und liefert die Fläche eines Kreises mit diesem Radius (d.h. πr2):

public static double calculateArea(double radius) {
    double result = Math.PI * radius * radius;
    return result;
}

Wie üblich, ist diese Methode public und static. Aber an der Stelle, an der wir normalerweise void sehen, sehen wir double, was bedeutet, dass der Rückgabewert dieser Methode double ist.

Die letzte Zeile ist eine neue Form der return Anweisung, die bedeutet: "Komme sofort aus dieser Methode zurück und verwende den folgenden Ausdruck als Rückgabewert." Der Ausdruck, den du angibst, kann beliebig komplex sein, also hätten wir diese Methode auch prägnanter schreiben können:

public static double calculateArea(double radius) {
    return Math.PI * radius * radius;
}

Andererseits erleichtern temporäre Variablen wie result oft das Debugging, vor allem wenn du mit einem interaktiven Debugger durch den Code schreitest (siehe "Tracing mit einem Debugger").

Abbildung 4-2 veranschaulicht, wie Datenwerte durch das Programm fließen. Wenn die Methode main calculateArea aufruft, wird der Wert 5.0 dem Parameter radius zugewiesen. calculateArea gibt dann den Wert 78.54 zurück, der der Variablen area zugewiesen wird.

Abbildung 4-2. Übergabe eines Parameters und Speichern des Rückgabewerts

Der Typ des Ausdrucks in der Anweisung return muss mit dem Rückgabetyp der Methode selbst übereinstimmen. Wenn du angibst, dass der Rückgabetyp double ist, versprichst du, dass diese Methode irgendwann einen double Wert liefert. Wenn du versuchst, return ohne Ausdruck oder return mit einem Ausdruck des falschen Typs zu verwenden, gibt der Compiler einen Fehler aus.

Inkrementelle Entwicklung

Viele Leute machen den Fehler, eine Menge Code zu schreiben, bevor sie versuchen, ihn zu kompilieren und auszuführen. Dann verbringen sie viel zu viel Zeit mit der Fehlersuche. Ein besserer Ansatz ist die so genannte inkrementelle Entwicklung. Die wichtigsten Aspekte sind folgende:

  • Beginne mit einem funktionierenden Programm und nimm kleine, schrittweise Änderungen vor. Wenn ein Fehler auftritt, weißt du jederzeit, wo du suchen musst.

  • Verwende Variablen, um Zwischenwerte zu speichern, damit du sie überprüfen kannst, entweder mit Druckanweisungen oder mit einem Debugger.

  • Wenn das Programm funktioniert, kannst du mehrere Anweisungen zu zusammengesetzten Ausdrücken zusammenfassen (aber nur, wenn das Programm dadurch nicht schwerer zu lesen ist).

Angenommen, du möchtest den Abstand zwischen zwei Punkten ermitteln, die durch die Koordinaten (x1,y1) und (x2,y2). Nach der üblichen Definition:

distance=(x2-x1)2+(y2-y1)2

Der erste Schritt ist zu überlegen, wie eine distance Methode in Java aussehen sollte. Mit anderen Worten: Was sind die Eingaben (Parameter) und was ist die Ausgabe (Rückgabewert)? Bei dieser Methode sind die Parameter die beiden Punkte, und es liegt nahe, sie durch vier double Werte darzustellen. Der Rückgabewert ist der Abstand, der auch den Typ double haben sollte.

Wir können bereits eine Gliederung für die Methode schreiben, die manchmal als Stub bezeichnet wird. Der Stub enthält die Methodendeklaration und eine return Anweisung:

public static double distance
        (double x1, double y1, double x2, double y2) {
    return 0.0;  // stub
}

Die Anweisung return ist ein Platzhalter, der nur notwendig ist, damit das Programm kompiliert werden kann. In diesem Stadium tut das Programm noch nichts Nützliches, aber es ist gut, es zu kompilieren, damit wir eventuelle Syntaxfehler finden können, bevor wir weiteren Code hinzufügen.

In der Regel ist es eine gute Idee, über Tests nachzudenken , bevor du neue Methoden entwickelst; so kannst du herausfinden, wie du sie implementieren kannst. Um die Methode zu testen, können wir sie von main aus aufrufen, indem wir die Beispielwerte verwenden:

double dist = distance(1.0, 2.0, 4.0, 6.0);

Mit diesen Werten ist der horizontale Abstand 3,0 und der vertikale Abstand 4,0. Das Ergebnis sollte also 5,0 sein, die Hypotenuse eines 3-4-5 Dreiecks. Wenn du eine Methode testest, ist es wichtig, die richtige Antwort zu kennen.

Sobald wir den Stub kompiliert haben, können wir beginnen, Code Zeile für Zeile hinzuzufügen. Nach jeder schrittweisen Änderung kompilieren wir das Programm neu und führen es aus. Wenn ein Fehler auftritt, wissen wir genau, wo wir suchen müssen: in den Zeilen, die wir gerade hinzugefügt haben.

Der nächste Schritt besteht darin, die Unterschiede zu finden: x2-x1 und y2-y1. Wir speichern diese Werte in temporären Variablen namens dx und dy, damit wir sie mit Druckanweisungen überprüfen können, bevor wir fortfahren. Sie sollten 3,0 und 4,0 sein:

public static double distance
        (double x1, double y1, double x2, double y2) {
    double dx = x2 - x1;
    double dy = y2 - y1;
    System.out.println("dx is " + dx);
    System.out.println("dy is " + dy);
    return 0.0;  // stub
}

Wir werden die Druckanweisungen entfernen, wenn die Methode fertig ist. Code wie dieser wird als Gerüst bezeichnet, weil er für den Aufbau des Programms hilfreich ist, aber nicht Teil des Endprodukts ist.

Der nächste Schritt besteht darin, dx und dy zu quadrieren. Wir könnten die Methode Math.pow verwenden, aber es ist einfacher (und effizienter), jeden Term mit sich selbst zu multiplizieren.

Dann addieren wir die Quadrate und drucken das bisherige Ergebnis aus:

public static double distance
        (double x1, double y1, double x2, double y2) {
    double dx = x2 - x1;
    double dy = y2 - y1;
    double dsquared = dx * dx + dy * dy;
    System.out.println("dsquared is " + dsquared);
    return 0.0;  // stub
}

Auch an dieser Stelle solltest du das Programm kompilieren und ausführen und den Zwischenwert überprüfen, der 25,0 sein sollte. Schließlich können wir Math.sqrt verwenden, um das Ergebnis zu berechnen und zurückzugeben:

public static double distance
        (double x1, double y1, double x2, double y2) {
    double dx = x2 - x1;
    double dy = y2 - y1;
    double dsquared = dx * dx + dy * dy;
    double result = Math.sqrt(dsquared);
    return result;
}

Wenn du mehr Erfahrung im Programmieren hast, kannst du vielleicht mehr als eine Zeile auf einmal schreiben und debuggen. Wenn du aber viel Zeit mit dem Debuggen verbringst, solltest du kleinere Schritte machen.

Vokabeln

void

Ein spezieller Rückgabetyp, der angibt, dass die Methode keinen Wert zurückgibt.

aufrufen.

Die Ausführung einer Methode veranlassen. Auch bekannt als Aufruf einer Methode.

Ablauf der Ausführung

Die Reihenfolge, in der Java Methoden und Anweisungen ausführt. Sie muss nicht unbedingt von oben nach unten in der Quelldatei sein.

Argument

Ein Wert, den du übergibst, wenn du eine Methode aufrufst. Dieser Wert muss den Typ haben, den die Methode erwartet.

Parameter

Eine Information, die eine Methode benötigt, bevor sie ausgeführt werden kann. Parameter sind Variablen: Sie enthalten Werte und haben Typen.

Parameterübergabe

Der Prozess der Zuweisung eines Argumentwertes an eine Parametervariable.

lokale Variable

Eine Variable, die innerhalb einer Methode deklariert wird. Auf lokale Variablen kann von außerhalb ihrer Methode nicht zugegriffen werden.

Stapeldiagramm

Eine grafische Darstellung der Variablen, die zu jeder Methode gehören. Die Methodenaufrufe werden von oben nach unten, im Fluss der Ausführung, gestapelt.

Rahmen

In einem Stapeldiagramm eine Darstellung der Variablen und Parameter für eine Methode mit ihren aktuellen Werten.

Umfang

Der Bereich eines Programms, in dem eine Variable verwendet werden kann.

komponieren

Einfache Ausdrücke und Aussagen zu zusammengesetzten Ausdrücken und Aussagen kombinieren.

Rückgabetyp

Der Typ des Wertes, den eine Methode zurückgibt.

Rückgabewert

Der Wert, der als Ergebnis eines Methodenaufrufs geliefert wird.

temporäre Variable

Eine kurzlebige Variable, die oft zur Fehlersuche verwendet wird.

inkrementelle Entwicklung

Ein Verfahren zur Erstellung von Programmen, bei dem ein paar Zeilen auf einmal geschrieben, kompiliert und getestet werden.

Stummel

Ein Platzhalter für eine unvollständige Methode, damit die Klasse kompiliert werden kann.

Gerüst

Code, der während der Programmentwicklung verwendet wird, aber nicht Teil der endgültigen Version ist .

Übungen

Der Code für dieses Kapitel befindet sich im Verzeichnis ch04 von ThinkJavaCode2. Unter "Verwenden der Codebeispiele" findest du Anweisungen zum Herunterladen des Repositorys. Bevor du mit den Übungen beginnst, empfehlen wir dir, die Beispiele zu kompilieren und auszuführen.

Wenn du "Command-Line Testing" noch nicht gelesen hast , wäre jetzt ein guter Zeitpunkt. Darin wird eine effiziente Methode beschrieben, um Programme zu testen, die Eingaben vom Benutzer entgegennehmen und bestimmte Ausgaben anzeigen.

Übung 4-1.

In dieser Übung geht es darum, den Code aus einer früheren Übung in eine Methode umzuwandeln, die Parameter benötigt. Beginne mit einer funktionierenden Lösung zu Übung 2-2.

  1. Schreibe eine Methode namens printAmerican, die den Tag, das Datum, den Monat und das Jahr als Parameter annimmt und sie im amerikanischen Format anzeigt.

  2. Teste deine Methode, indem du sie von main aus aufrufst und die entsprechenden Argumente übergibst. Die Ausgabe sollte in etwa so aussehen (nur das Datum könnte anders sein):

    Saturday, July 22, 2015
  3. Wenn du printAmerican getestet hast, schreibe eine weitere Methode namens printEuropean, die das Datum im europäischen Format anzeigt.

Übung 4-2.

In dieser Übung wird der Ablauf eines Programms mit mehreren Methoden überprüft. Lies den folgenden Code und beantworte die Fragen:

public static void main(String[] args) {
    zippo("rattle", 13);
}
public static void baffle(String blimp) {
    System.out.println(blimp);
    zippo("ping", -5);
}
public static void zippo(String quince, int flag) {
    if (flag < 0) {
        System.out.println(quince + " zoop");
    } else {
        System.out.println("ik");
        baffle(quince);
        System.out.println("boo-wa-ha-ha");
    }
}
  1. Schreibe die Zahl 1 neben die erste Codezeile in diesem Programm, die ausgeführt werden soll.

  2. Schreibe die Zahl 2 neben die zweite Codezeile, und so weiter bis zum Ende des Programms. Wenn eine Zeile mehr als einmal ausgeführt wird, kann es sein, dass am Ende mehr als eine Zahl neben der Zeile steht.

  3. Wie lautet der Wert des Parameters blimp, wenn baffle aufgerufen wird?

  4. Was ist die Ausgabe dieses Programms?

Übung 4-3.

Beantworte die folgenden Fragen, ohne das Programm auf einem Computer auszuführen.

  1. Zeichne ein Stapeldiagramm, das den Zustand des Programms beim ersten Aufruf von ping zeigt.

  2. Was wird von dem folgenden Programm ausgegeben? Achte genau auf die Platzierung von Leerzeichen und Zeilenumbrüchen.

public static void zoop() {
    baffle();
    System.out.print("You wugga ");
    baffle();
}
public static void main(String[] args) {
    System.out.print("No, I ");
    zoop();
    System.out.print("I ");
    baffle();
}
public static void baffle() {
    System.out.print("wug");
    ping();
}
public static void ping() {
    System.out.println(".");
}

Übung 4-4.

Wenn du eine Frage dazu hast, ob etwas legal ist und was passiert, wenn es nicht legal ist, ist es eine gute Möglichkeit, das herauszufinden, indem du den Compiler fragst. Beantworte die folgenden Fragen, indem du sie ausprobierst.

  1. Was passiert, wenn du eine Wertmethode aufrufst und nichts mit dem Ergebnis tust, d.h. wenn du es nicht einer Variablen zuweist oder es als Teil eines größeren Ausdrucks verwendest ?

  2. Was passiert, wenn du eine ungültige Methode als Teil eines Ausdrucks verwendest? Probiere zum Beispiel System.out.println("boo!") + 7; aus.

Übung 4-5.

Zeichne ein Stack-Diagramm, das den Zustand des Programms beim zweiten Aufruf von zoop zeigt. Wie lautet die vollständige Ausgabe?

public static void zoop(String fred, int bob) {
    System.out.println(fred);
    if (bob == 5) {
        ping("not ");
    } else {
        System.out.println("!");
    }
}
public static void main(String[] args) {
    int bizz = 5;
    int buzz = 2;
    zoop("just for", bizz);
    clink(2 * buzz);
}
public static void clink(int fork) {
    System.out.print("It's ");
    zoop("breakfast ", fork);
}
public static void ping(String strangStrung) {
    System.out.println("any " + strangStrung + "more ");
}

Übung 4-6.

Viele Berechnungen lassen sich mit der Multadd-Operation, die drei Operanden benötigt und a * b + c berechnet, prägnanter ausdrücken. Einige Prozessoren bieten sogar eine Hardware-Implementierung dieser Operation für Fließkommazahlen.

  1. Erstelle ein neues Programm namens Multadd.java.

  2. Schreibe eine Methode namens multadd, die drei doubles als Parameter annimmt und a * b + c zurückgibt.

  3. Schreibe eine main Methode, die multadd testet, indem du sie mit ein paar einfachen Parametern aufrufst, wie 1.0, 2.0, 3.0.

  4. Auch in main kannst du mit multadd die folgenden Werte berechnen:

    Sündeπ4+cosπ42loggen10+loggen20
  5. Schreibe eine Methode mit dem Namen expSum, die einen Double als Parameter nimmt und mit multadd zu berechnen:

    xe-x+1-e-x

    Tipp: Die Methode zur Erhöhung von e zu einer Potenz lautet Math.exp.

Im letzten Teil dieser Übung musst du eine Methode schreiben, die eine andere von dir geschriebene Methode aufruft. Immer wenn du das tust, ist es eine gute Idee, die erste Methode sorgfältig zu testen, bevor du an der zweiten arbeitest. Sonst kann es passieren, dass du zwei Methoden gleichzeitig debuggen musst, was schwierig sein kann.

Eines der Ziele dieser Übung ist es, die Mustererkennung zu trainieren: die Fähigkeit, ein bestimmtes Problem als Beispiel für eine allgemeine Kategorie von Problemen zu erkennen.

Get Think Java, 2. Auflage now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.