Java-Methoden und Problemzerlegung

Lerne, eigene statische Methoden in Java zu schreiben und daraus Programme aufzubauen. Definiere Methoden und rufe sie auf, übergib Informationen durch Parameter und erhalte Ergebnisse mit return zurück. Finde heraus, wo du welche Variable verwenden kannst, warum eine Methode mit Kopien ihrer Argumente arbeitet und wie der Aufrufstapel laufende Methoden nachverfolgt. Überlade Methoden und sage voraus, welche Version Java aufruft. Zerlege schließlich ein Problem in kleine Methoden, die jeweils eine Aufgabe erfüllen, entferne wiederholten Code und entwickle und teste ein Programm Methode für Methode.

AnfängerEinheit 3 von 11 in Kurs: Java-Programmierung – Klassen, Vererbung, Collections und Streams

Was du lernst

  1. Definiere statische Methoden, rufe sie aus main und gegenseitig auf und übergib ihnen die benötigten Informationen durch Parameter.
    • Definiere eine Methode und rufe sie auf
      Schreibe Methodenkopf und Methodenrumpf an die richtige Stelle, rufe die Methode über ihren Namen auf und verfolge, wie die Ausführung in die Methode und zurück springt.
    • Übergib Informationen über Parameter an eine Methode
      Deklariere Parameter mit Typ und Namen, rufe die Methode mit passenden Argumenten auf und verwende mehrere Parameter in der richtigen Reihenfolge.
  2. Schreibe Methoden, die einen Wert berechnen und mit return zurückgeben, und verwende die zurückgegebenen Werte in Variablen, Ausdrücken und Bedingungen.
    • Gib einen Wert zurück und verwende ihn
      Deklariere einen Rückgabetyp, gib ein Ergebnis mit einer return-Anweisung zurück und entscheide im aufrufenden Code, was mit dem Rückgabewert geschieht.
    • Kehre innerhalb von Verzweigungen und Schleifen aus einer Methode zurück
      Verwende return-Anweisungen in if-Anweisungen und Schleifen, stelle sicher, dass jeder Pfad einen Wert zurückgibt, und schreibe Methoden, die eine Ja-Nein-Frage beantworten.
  3. Erkenne, wo du welche Variable verwenden kannst, was eine Methode im aufrufenden Code ändern kann und was nicht und wie der Aufrufstapel laufende Methoden nachverfolgt.
    • Bestimme, wo du welche Variable verwenden kannst
      Wende die Regeln für die Gültigkeitsbereiche lokaler Variablen, Parameter und in Blöcken deklarierter Variablen an und behebe die Kompilierfehler, die durch Fehler beim Gültigkeitsbereich entstehen.
    • Verstehe, dass Argumentwerte als Kopien übergeben werden
      Sage voraus, was eine Methode im aufrufenden Code ändern kann: Die Methode arbeitet mit Kopien der Argumentwerte, sodass eine Neuzuweisung an einen Parameter die Variable des Aufrufers nicht ändert.
    • Verfolge Methodenaufrufe auf dem Aufrufstapel
      Verfolge, wie Java laufende Methoden in Stapelrahmen erfasst, vollziehe Programme nach, in denen Methoden andere Methoden aufrufen, und lies einen Stacktrace.
  4. Gib mehreren Methoden denselben Namen mit unterschiedlichen Parameterlisten und sage voraus, welche Version Java für bestimmte Argumente aufruft.
    • Schreibe überladene Methoden
      Deklariere Methoden mit demselben Namen, erkenne, welche Unterschiede eine gültige Überladung ergeben, und überlade Methoden, wenn sie dieselbe Aufgabe erfüllen.
    • Sage voraus, welche überladene Methode ausgeführt wird
      Ermittle anhand der Argumenttypen, welche Version Java auswählt, berücksichtige dabei automatische erweiternde Typumwandlungen und erkenne Aufrufe, die sich nicht kompilieren lassen.
  5. Zerlege ein Problem in kleine Methoden, die jeweils eine Aufgabe erfüllen, ersetze wiederholten Code durch parametrisierte Methoden und entwickle und teste ein Programm Methode für Methode.
    • Gib jeder Methode eine klar abgegrenzte Aufgabe
      Erkenne ein gut aufgeteiltes Programm, teile Code auf, der zu viel tut, und trenne Berechnung von Ein- und Ausgabe.
    • Ersetze wiederholten Code durch eine parametrisierte Methode
      Finde Code, der mit kleinen Unterschieden wiederholt wird, forme ihn zu einer Methode um, deren Parameter die Unterschiede aufnehmen, und prüfe, ob das Programm sich weiterhin gleich verhält.
    • Entwirf ein Programm nach dem Top-down-Prinzip und teste jede Methode einzeln
      Plane ein Programm als Folge von Methodenaufrufen, schreibe es schrittweise mit vorläufigen Stubs und teste jede Methode mit Eingaben, deren Ergebnisse du kennst.

Java-Methoden und Problemzerlegung einfach erklärt

5 Kapitel

1

Schreibe eigene Methoden und rufe sie auf

Ein Programm lässt sich leichter nachvollziehen, wenn sinnvolle Schritte Namen haben. Eine Methode gibt einer Gruppe von Anweisungen einen Namen, und ein Aufruf führt diese Anweisungen dort aus, wo sie gebraucht werden. Beginne mit einer Methode, die immer dieselbe Zeile ausgibt, und ergänze dann Parameter, damit eine Definition unterschiedliche Eingaben verarbeiten kann. Wenn du einen Methodenkopf liest und ihn mit einem Aufruf abgleichst, erkennst du, welche Informationen jeder Schritt benötigt, bevor du seinen Rumpf untersuchst.

1.1 Definiere eine Methode und rufe sie auf

Eine Methode ist ein benannter Block von Anweisungen, der eine Aufgabe erfüllt. Die Definition einer Methode stellt die Aufgabe bereit; ihr Aufruf führt sie aus.

Lies Kopf und Rumpf
public static void printLine() {
    System.out.println("----------");
}

Die erste Zeile ist der Methodenkopf. Lies seine Teile von links nach rechts:

  • public erlaubt Code in anderen Klassen, die Methode aufzurufen.
  • static ordnet die Methode der Klasse zu. Für ihren Aufruf ist kein Objekt nötig.
  • void besagt, dass die Methode keinen Wert zurückgibt.
  • printLine benennt die Aufgabe.
  • () ist die leere Parameterliste: Diese Methode benötigt keine Eingabe.

Die geschweiften Klammern umschließen den Methodenrumpf, also die Anweisungen, die bei einem Aufruf ausgeführt werden. Zwischen diesem Kopf und seiner öffnenden Klammer steht kein Semikolon.

Setze die Definition in die Klasse
public class Main {
    public static void main(String[] args) {
        System.out.println("Start");
        printLine();
        System.out.println("Middle");
        printLine();
    }

    public static void printLine() {
        System.out.println("----------");
    }
}

main und printLine sind getrennte Methoden innerhalb von Main. Die schließende Klammer von main steht vor der Definition von printLine. Eine Methode kann nicht innerhalb einer anderen Methode definiert werden; eine falsch gesetzte Klammer kann „illegal start of expression“ verursachen.

Die Definitionen können in beliebiger Reihenfolge stehen. Wenn du printLine über main verschiebst, ändert das nicht, wann die Methode ausgeführt wird. Eine Methode, die nie aufgerufen wird, wird nicht allein deshalb ausgeführt, weil ihre Definition in der Datei steht.

Verfolge einen Aufruf und die Rückkehr zum Aufrufer

Der Aufruf printLine(); besteht aus dem Namen, Klammern und einem Semikolon, weil der Aufruf als eigene Anweisung steht. Die Ausführung beginnt in main:

  1. Gib „Start“ aus.
  2. Wechsle zu printLine, gib zehn Bindestriche aus und fahre dann nach dem Aufruf fort.
  3. Gib „Middle“ aus.
  4. Wechsle erneut zu printLine und gib erneut zehn Bindestriche aus.

Die Ausgabe lautet:

Start
----------
Middle
----------

Beide Aufrufe verwenden dieselbe Definition. Änderst du die ausgegebene Zeile, ändert sie sich an beiden Stellen, die sie verwenden.

Benenne Methoden genau und rufe sie korrekt auf

Verwende ein Verb oder eine Verbgruppe in camelCase mit kleinem Anfangsbuchstaben: printReceipt, calculateAverage oder isValidCode. Java unterscheidet Groß- und Kleinschreibung: PrintLine() findet keine Methode namens printLine. Auch printLine; schlägt fehl; die Klammern gehören zum Aufruf.

Schreibe bei einer statischen Methode in einer anderen Klasse zuerst den Klassennamen. Math.max(3, 8) ergibt 8, Math.abs(-4) ergibt 4 und Math.sqrt(16.0) ergibt 4.0. Deine eigenen Methoden in derselben Klasse kannst du allein über ihren Namen aufrufen.

Diese Beispiele verwenden die klassische klassenbasierte Form mit public static void main(String[] args). Java 25 unterstützt auch kompakte Quelldateien mit void main() und ohne umgebende Klasse. Behalte beim Ausführen dieser Beispiele die klassische Form bei; ihre Hilfsmethoden werden mit static deklariert. Methoden wie System.out.println, die du aus der Java-Bibliothek aufrufst, müssen nicht selbst statisch sein.

Wichtige Erkenntnisse

  • Setze Methodendefinitionen innerhalb der Klasse und außerhalb anderer Methoden.
  • Eine Definition stellt eine Aufgabe bereit; ein Aufruf führt sie aus und setzt danach beim Aufrufer fort.
  • Schreibe bei einem Aufruf Klammern und ein Semikolon, wenn der Aufruf eine Anweisung ist.
  • Verwende einen aussagekräftigen Namen in camelCase und beachte seine genaue Groß- und Kleinschreibung.
  • Rufe eine statische Methode einer anderen Klasse mit deren Klassennamen auf, zum Beispiel Math.max(3, 8).

1.2 Übergib Informationen über Parameter an eine Methode

Ein Parameter ermöglicht es einer Methode, Werte zu verarbeiten, die sich von Aufruf zu Aufruf ändern. Ein Argument ist der Wert, der beim Aufruf der Methode für diesen Parameter übergeben wird.

Gib jeder Eingabe einen Typ und einen Namen
public static void printStars(int count) {
    for (int i = 0; i < count; i++) {
        System.out.print("*");
    }
    System.out.println();
}

int count deklariert einen Parameter. In printStars(3); wird das Argument 3 zum Anfangswert von count. Die Schleife läuft dreimal, gibt also *** aus; anschließend beendet println() die Zeile. printStars(8); verwendet denselben Rumpf mit dem Wert 8 für count.

Der Typ steht in der Definition, nicht im Aufruf. Schreibe printStars(5);, nicht printStars(int 5);.

Werte Argumente vor dem Eintritt in den Rumpf aus

Ein Argument kann ein Literal, eine Variable oder ein Ausdruck sein:

int n = 4;
printStars(n * 2);

Java wertet zuerst n * 2 aus. Es übergibt den resultierenden Wert 8, sodass der Rumpf mit dem Wert 8 für count beginnt. Der Variablenname beim Aufrufer muss nicht mit dem Parameternamen übereinstimmen.

Ordne mehrere Parameter nach Position zu

Jeder Parameter braucht seinen eigenen Typ. Eine Methode für Rechtecke kann mit diesem Kopf beginnen:

public static void printRectangle(int width, int height)

Der Aufruf printRectangle(5, 2); gibt width den Wert 5 und height den Wert 2. Vertauschst du die Argumente, erhältst du ein Rechteck mit Breite 2 und Höhe 5. Beide Aufrufe lassen sich kompilieren, weil beide Argumente int-Werte sind; nur die beabsichtigte Form zeigt dir, welche Reihenfolge richtig ist. (int width, height) im Kopf schlägt fehl, weil für height kein Typ deklariert ist.

Unterschiedliche Typen erleichtern es, manche Fehler in der Reihenfolge zu erkennen:

public static void printRepeated(String text, int times) {
    for (int i = 0; i < times; i++) {
        System.out.print(text);
    }
    System.out.println();
}

printRepeated("ab", 3); gibt „ababab“ aus. printRepeated(3, "ab"); passt nicht zu einem String gefolgt von einem int-Wert. Auch die Anzahl der Argumente muss passen: Bei printRectangle(5); erhält ein Parameter keinen Wert.

Prüfe kompatible numerische Typen

Java erweitert einen int-Wert automatisch zu einem double-Wert. Eine Methode mit den Parametern (double km, double hours) akzeptiert die Argumente (150, 2) und erhält dafür 150.0 und 2.0. Jeder int-Wert kann als double genau dargestellt werden.

Java wandelt ein double-Argument nicht implizit in einen int-Parameter um. printStars(2.9); schlägt fehl, weil bei der Umwandlung der Nachkommateil verloren ginge. Der explizite Cast in printStars((int) 2.9); ergibt 2, sodass zwei Sterne ausgegeben werden. Verwende einen Cast nur, wenn das Abschneiden dieses Teils beabsichtigt ist.

Wähle für jede Information, die die Aufgabe benötigt, einen Parameter. Da printRepeated Text und eine Anzahl erhält, lässt sich die Methode mit Tastatureingaben, einem festen Testaufruf oder aus einer anderen Methode verwenden. Ihr Rumpf muss nicht entscheiden, woher diese Werte stammen.

Wichtige Erkenntnisse

  • Ein Parameter wird im Kopf deklariert; ein Argument liefert seinen Wert beim Aufruf.
  • Java wertet Argumentausdrücke aus, bevor die aufgerufene Methode ausgeführt wird.
  • Argumente müssen nach Position, Anzahl und kompatiblem Typ zu den Parametern passen.
  • Schreibe für jeden Parameter einen Typ, aber keine Typen im Aufruf.
  • Ein int-Wert kann zu double erweitert werden; ein double-Wert benötigt einen expliziten Cast, um zu int zu werden.
  • Das Vertauschen von Argumenten desselben Typs kann sich kompilieren lassen und trotzdem das Ergebnis ändern.
2

Gib Ergebnisse aus Methoden zurück

Eine Methode kann mehr als nur etwas ausgeben: Sie kann einen Wert an den aufrufenden Code zurückgeben. Dadurch lässt sich eine Berechnung in einer weiteren Berechnung, einer Bedingung oder einer späteren Auswertung verwenden. Verfolge, wie Rückgabetypen, Ausdrücke und Zuweisungen zusammenwirken, und verwende dann return-Anweisungen in Verzweigungen und Suchen. Die Position einer return-Anweisung ist entscheidend: Sie bestimmt sowohl, welche Antwort den Aufrufer erreicht, als auch, wie viel von der Methode ausgeführt wird.

2.1 Gib einen Wert zurück und verwende ihn

Ein Rückgabewert ist ein Ergebnis, das eine Methode an ihren Aufrufer zurückgibt. Sobald ein Aufruf endet, kann er als Ausdruck mit dem Typ dieses Ergebnisses verwendet werden.

Deklariere, was zurückgegeben wird
public static int sum(int a, int b) {
    return a + b;
}

int ersetzt void im Kopf, weil diese Methode eine Ganzzahl zurückgibt. Die return-Anweisung wertet a + b aus und gibt den Wert an die Aufrufstelle zurück. Für sum(4, 7) ist dieser Wert 11.

Der Aufrufer entscheidet, was als Nächstes geschieht:

int total = sum(4, 7);
System.out.println(sum(4, 7));
int doubled = sum(2, 3) * 2;

Die erste Zeile speichert 11, die zweite gibt 11 aus und die dritte speichert 10. Ein Rückgabewert kann auch in einer Bedingung verwendet werden, etwa if (sum(a, b) > 10).

Ein kompatibles int-Ergebnis kann bei der Rückgabe aus einer double-Methode erweitert werden. Ein double-Ergebnis kann ohne passende explizite Umwandlung nicht aus einer int-Methode zurückgegeben werden.

Berechne den Ausdruck vor der Umwandlung des Ergebnisses
public static double average(int a, int b) {
    return (a + b) / 2.0;
}

Für average(3, 4) ist der Zähler 7. Die Division durch das double-Literal 2.0 ergibt 3.5. Lautete der Ausdruck (a + b) / 2, würde Java zuerst zwei int-Werte dividieren und 3 erhalten. Erst danach würde es diesen Wert zum Rückgabewert 3.0 erweitern. Ein double-Rückgabetyp macht eine bereits im Rumpf ausgeführte Ganzzahldivision nicht rückgängig.

Unterscheide Rückgabe und Ausgabe
Verhalten der MethodeWas der Aufrufer erhältWas auf dem Bildschirm erscheint
return a + b; in einer int-MethodeDie SummeNichts durch diese Anweisung
System.out.println(a + b); in einer void-MethodeKein WertDie Summe

Ein void-Aufruf kann keinen Wert in einer Zuweisung oder einem anderen Aufruf liefern. Ist printSum eine void-Methode, schlägt int total = printSum(1, 2); fehl, obwohl printSum eine Zahl ausgibt. Verwende für Berechnungen eine Methode mit Rückgabewert und überlasse dem Aufrufer die Entscheidung über die Ausgabe.

Gib Text und Ja-Nein-Ergebnisse zurück

Zu den Rückgabetypen gehören auch String und boolean. Eine Begrüßungsmethode kann "Hello, " + name + "!" zurückgeben, was für das Argument "Ana" „Hello, Ana!“ ergibt. Eine Methode isEven(int n) kann n % 2 == 0 zurückgeben.

Eine Formatierungsmethode wandelt eine Zahl in wiederverwendbaren Text um:

public static String formatDuration(int minutes) {
    return minutes / 60 + " h " + minutes % 60 + " min";
}

Für 135 ergibt die Ganzzahldivision 2 volle Stunden und der Divisionsrest 15 Minuten. Das Ergebnis ist „2 h 15 min“; für 60 ist es „1 h 0 min“.

Behalte oder kombiniere das Ergebnis

Ein Aufruf wie sum(4, 7); lässt sich kompilieren, verwirft aber sein Ergebnis. Gibt square(x) einen neuen Wert zurück, verwende x = square(x);, um ihn in x zu speichern.

Ein Ergebnis kann auch unmittelbar zum Argument werden. In Math.max(sum(1, 2), 4) ergibt sum(1, 2) zuerst 3, danach ergibt Math.max(3, 4) den Wert 4. Werte den inneren Aufruf aus, bevor du sein Ergebnis im äußeren verwendest.

Wichtige Erkenntnisse

  • Der deklarierte Rückgabetyp sagt dem Aufrufer, welche Art von Ergebnis der Aufruf liefert.
  • Eine Rückgabe liefert einen Wert; eine Ausgabe zeigt einen Wert an.
  • Der Ausdruck wird berechnet, bevor sein Ergebnis in den Rückgabetyp umgewandelt wird.
  • Speichere einen Rückgabewert, wenn späterer Code ihn benötigt; ein allein stehender Aufruf verwirft ihn.
  • Ein Rückgabewert kann als Argument an eine andere Methode übergeben werden.

2.2 Kehre innerhalb von Verzweigungen und Schleifen aus einer Methode zurück

Eine return-Anweisung beendet den aktuellen Methodenaufruf sofort. Auch innerhalb einer Bedingung oder Schleife verlässt sie die ganze Methode, nicht nur diesen Block.

Gib jedem Pfad eine Antwort
public static int larger(int a, int b) {
    if (a > b) {
        return a;
    }
    return b;
}

larger(9, 4) gibt innerhalb des if-Blocks 9 zurück. Bei larger(2, 6) wird der if-Rumpf übersprungen und das abschließende return gibt 6 zurück. Gleiche Eingaben wie (5, 5) erreichen ebenfalls das abschließende return, das 5 zurückgibt. Nach dem ersten return ist kein else nötig, weil dieser Pfad die Methode bereits verlassen hat.

In einer gewöhnlichen Methode mit Rückgabewert darf kein möglicher Pfad die schließende Klammer erreichen, ohne einen Wert zu liefern. Eine Vorzeichenmethode, die nur für positive und negative Eingaben zurückkehrt, lässt null ohne Antwort:

public static String sign(int n) {
    if (n > 0) {
        return "positive";
    } else if (n < 0) {
        return "negative";
    }
    return "zero";
}

Das abschließende return vervollständigt die Methode. Zwei getrennte if-Anweisungen, von denen eine n > 0 und die andere n <= 0 prüft, benötigen weiterhin ein abschließendes return oder eine eindeutige if/else-Struktur. Javas Rückgabeprüfung leitet nicht ab, dass diese beiden Vergleiche alle Ganzzahlen abdecken. Eine Anweisung direkt nach einem unbedingten return im selben Block ist unerreichbar und wird abgelehnt.

Beende eine Suche im richtigen Moment
public static int firstMultipleOf7(int start, int end) {
    for (int i = start; i <= end; i++) {
        if (i % 7 == 0) {
            return i;
        }
    }
    return -1;
}

Für (10, 20) verwirft die Schleife 10, 11, 12 und 13 und gibt dann 14 zurück. Der Aufruf endet, ohne 15 bis 20 zu prüfen. Für (15, 20) endet die Schleife ohne Treffer, sodass das return danach -1 zurückgibt, das vereinbarte Signal „nicht gefunden“.

Ein else { return -1; } innerhalb der Schleife würde nach dem ersten erfolglosen Kandidaten abbrechen. Die Suche ab 10 würde dann einen Misserfolg melden, bevor sie 14 erreicht. Die Rückgabe für einen Misserfolg gehört hinter die Schleife, nachdem alle Kandidaten geprüft wurden.

Gib die Bedingung selbst zurück

Ein Vergleich liefert bereits einen boolean-Wert. Schreibe return n % 2 == 0; statt eines if/else, das true und false getrennt zurückgibt. Der Name einer booleschen Methode beginnt oft mit is oder has, sodass sich ein Aufruf innerhalb eines if natürlich liest.

public static boolean isLeapYear(int year) {
    return (year % 4 == 0 && year % 100 != 0)
        || year % 400 == 0;
}

Dies gibt für 2024 und 2000 den Wert true, für 1900 und 2023 aber false zurück. Verwende if (isLeapYear(y)) direkt.

Verlasse eine void-Methode vorzeitig

Eine void-Methode verwendet return; ohne Wert. Zum Beispiel kann printSquareRoot(double x) bei einer negativen Eingabe „No real square root“ ausgeben und sofort zurückkehren. Für andere Eingaben kann die Methode Math.sqrt(x) ausgeben, das für 2.25 den Wert 1.5 ergibt. return 5; schlägt in einer void-Methode fehl, weil ihr Kopf keinen Rückgabewert verspricht.

Wichtige Erkenntnisse

  • return beendet den aktuellen Aufruf sofort, auch innerhalb einer Schleife.
  • Eine Methode mit Rückgabewert darf ihre schließende Klammer nicht ohne Antwort erreichen.
  • Setze die Rückgabe für eine erfolglose Suche hinter die Schleife, damit spätere Kandidaten geprüft werden können.
  • Ein Vergleich kann direkt als boolean-Wert zurückgegeben werden.
  • Verwende return; ohne Wert, um eine void-Methode vorzeitig zu verlassen.
  • Code direkt nach einem unbedingten return im selben Block ist unerreichbar.
3

Verfolge Variablenwerte und Aufrufe im Programmablauf

Ein Methodenaufruf gibt einer Hilfsmethode keinen Zugriff auf jede Variable im Programm. Jeder Aufruf hat seine eigenen Parameter und lokalen Variablen, und Java hält diese Werte in einem eigenen Stapelrahmen. Nutze den Gültigkeitsbereich, um zu entscheiden, wo ein Name zulässig ist, die Wertübergabe, um vorherzusagen, was Zuweisungen ändern können, und den Aufrufstapel, um noch nicht abgeschlossene Aufgaben zu verfolgen. Diese drei Ideen erklären, warum zwei Variablen denselben Namen haben und dabei unterschiedliche Werte enthalten können.

3.1 Bestimme, wo du welche Variable verwenden kannst

Der Gültigkeitsbereich einer Variablen ist der Bereich des Codes, in dem ihr Name verwendet werden kann. Betrachte zuerst die geschweiften Klammern um ihre Deklaration: Ein lokaler Name gehört zu einer bestimmten Methode oder einem bestimmten Block.

Lokale Variablen des Aufrufers bleiben beim Aufrufer
public static void main(String[] args) {
    int price = 20;
    printDouble(price);
}

public static void printDouble(int price) {
    System.out.println(price * 2);
}

Das price in main und der Parameter price in printDouble sind getrennte Variablen. Das Argument liefert den Wert, den die Hilfsmethode benötigt, sodass sie 40 ausgibt.

Wenn du den Parameter entfernst und printDouble() aufrufst, kann die Hilfsmethode trotzdem nicht das lokale price von main lesen. Ihr Rumpf würde mit „cannot find symbol“ fehlschlagen. Der Aufruf einer Methode aus einer anderen verbindet ihre Gültigkeitsbereiche nicht. Verschiedene Methoden dürfen jeweils den Namen count verwenden, ohne ihre Variablen zu verbinden.

Ein verschachtelter Block schafft einen kleineren Gültigkeitsbereich

Eine lokale Variable kann von ihrer Deklaration bis zur schließenden Klammer ihres Blocks verwendet werden. Ein Parameter ist im gesamten Rumpf seiner Methode verfügbar. Ein in for (int i = 0; i < 3; i++) deklarierter Zähler gehört zu dieser Schleife; i kann danach nicht gelesen werden.

Um ein Ergebnis nach einer Schleife zu behalten, deklariere es vor der Schleife:

int sum = 0;
for (int i = 1; i <= 5; i++) {
    sum += i;
}
System.out.println(sum);

Durch die Additionen nimmt sum nacheinander die Werte 1, 3, 6, 10 und 15 an. Die abschließende Ausgabe kann sum lesen, weil der umgebende Block noch nicht beendet ist. i wird nur für die Schleife benötigt und bleibt innerhalb ihres Gültigkeitsbereichs.

Wenn du int sum = 0; in den Schleifenrumpf verschiebst, entsteht bei jedem Durchlauf ein neues sum. Jedes beginnt bei null und verschwindet am Ende dieses Durchlaufs. Es kann weder eine laufende Summe speichern noch nach der Schleife ausgegeben werden.

Prüfe Namen und Anfangswerte getrennt

Zwei lokale Variablen mit demselben Namen dürfen innerhalb einer Methode keine überlappenden Gültigkeitsbereiche haben. Eine Methode mit einem Parameter x kann keine weitere lokale Variable x deklarieren; eine Schleife, die i deklariert, kann in ihrem Rumpf kein weiteres i deklarieren. Benenne die zweite Variable um oder verwende die vorhandene.

Zwei aufeinanderfolgende Schleifen dürfen jeweils int i deklarieren. Der Gültigkeitsbereich der ersten Schleife ist vor der zweiten Deklaration beendet. Die geschweiften Klammern, nicht die ganze Datei, bestimmen diese Wiederverwendung.

Auch ein zulässiger Name braucht einen Wert, bevor er gelesen wird. int total; total++; schlägt fehl, weil ++ den alten Wert lesen muss und eine lokale Variable keinen automatischen Anfangswert erhält. Verwende int total = 0; für eine laufende Summe.

Halte eine lokale Variable im kleinsten Block, der sie benötigt. Benötigt eine Methode Informationen von ihrem Aufrufer, mache diese Informationen zu einem Parameter. Benötigt der Aufrufer ein Ergebnis, gib es zurück. Dann zeigen Kopf und Rumpf der Methode, woher ihre Daten stammen.

Wichtige Erkenntnisse

  • Ein lokaler Name ist von seiner Deklaration bis zum Ende seines Blocks verfügbar.
  • Eine aufgerufene Methode kann die lokalen Variablen des Aufrufers nicht über deren Namen lesen.
  • Deklariere einen Akkumulator vor einer Schleife, wenn er eine Summe behalten oder danach gelesen werden muss.
  • Gültigkeitsbereiche lokaler Namen dürfen sich innerhalb einer Methode nicht überlappen, und lokale Variablen brauchen vor ihrer Verwendung einen Wert.

3.2 Verstehe, dass Argumentwerte als Kopien übergeben werden

Java übergibt Argumente als Wert. Zu Beginn eines Aufrufs erhält jeder Parameter eine Kopie des Werts seines Arguments. Eine Zuweisung an den Parameter ändert diese lokale Variable.

Verfolge die Kopie getrennt
public static void main(String[] args) {
    int score = 10;
    addBonus(score);
    System.out.println(score);
}

public static void addBonus(int score) {
    score = score + 5;
    System.out.println(score);
}

Es gibt zwei Variablen namens score. Verfolge ihre Werte zu jedem Zeitpunkt:

Zeitpunktscore in mainscore in addBonus
Vor dem Aufruf10Noch kein Aufruf
Beim Eintritt in addBonus1010
Nach der Zuweisung in der Hilfsmethode1015
Nach der Rückkehr der Hilfsmethode10Aufruf beendet

Die Hilfsmethode gibt 15 aus, dann gibt main den Wert 10 aus. Ein gemeinsamer Name bedeutet nicht, dass die beiden Variablen denselben Speicherplatz nutzen. Eine Umbenennung des Parameters würde dieses Verhalten nicht ändern.

Gib den neuen Wert zurück und speichere ihn
public static int addBonus(int score) {
    return score + 5;
}

Schreibe bei dieser Version score = addBonus(score);. Java kopiert den alten Wert in den Parameter, berechnet 15, gibt diesen Wert zurück und weist ihn der Variablen des Aufrufers zu. Die Zuweisung beim Aufrufer ist der Schritt, der diese Variable ändert.

Ein Ergebnis kann auch an anderer Stelle gespeichert werden. Multipliziert triple(int n) sein lokales n mit 3 und gibt es zurück, bleibt bei int a = 4; int b = triple(a); der Wert von a gleich 4 und b erhält den Wert 12. Die Ausgabe von a + " " + b zeigt „4 12“.

Wende dieselbe Regel auf String-Referenzen an

Eine String-Variable enthält eine Referenz auf ein String-Objekt. Java kopiert diese Referenz in einen String-Parameter:

public static void exclaim(String text) {
    text = text + "!";
}

Verweist word beim Aufrufer auf „hi“, verweist word nach exclaim(word); weiterhin auf „hi“. Die Konkatenation erzeugt einen neuen String und die Zuweisung ändert nur, worauf der Parameter verweist. Der vorhandene Inhalt von Strings kann nicht geändert werden.

Um den neuen Text zu behalten, gib text + "!" aus einer String-Methode wie exclaimed zurück und schreibe dann word = exclaimed(word);.

Bei veränderlichen Objekten wie Listen kann eine kopierte Referenz weiterhin auf dasselbe Objekt zeigen. Eine Methode kann den Inhalt dieses Objekts über die kopierte Referenz ändern. Eine Neuzuweisung an den Parameter kann weiterhin nicht bewirken, dass die Variable des Aufrufers auf ein anderes Objekt verweist. Sowohl für kopierte Referenzen als auch für kopierte Zahlen gilt die Wertübergabe.

Du darfst einem Parameter einen neuen Wert zuweisen, aber eine separate lokale Variable wie result kann eine längere Berechnung leichter lesbar machen: Sie hält die ursprüngliche Eingabe verfügbar und zeigt zugleich, welcher Wert zurückgegeben wird.

Wichtige Erkenntnisse

  • Jeder Parameter erhält eine Kopie des Werts seines Arguments.
  • Eine Neuzuweisung an einen Parameter lässt die Variable des Aufrufers unverändert.
  • Um einen berechneten Ersatzwert zu behalten, gib ihn zurück und weise ihn beim Aufrufer zu.
  • Eine kopierte Objektreferenz kann auf dasselbe veränderliche Objekt zugreifen, aber eine Neuzuweisung an den Parameter bleibt lokal.

3.3 Verfolge Methodenaufrufe auf dem Aufrufstapel

Der Aufrufstapel erfasst Aufrufe, die begonnen haben, aber noch nicht beendet sind. Jeder Aufruf erhält einen Stapelrahmen mit seinen Parametern, lokalen Variablen und der Stelle, an der sein Aufrufer fortsetzt.

Lege einen Rahmen auf den Stapel und entferne ihn nach der Ausführung

Der Stapel folgt dem LIFO-Prinzip: Was zuletzt hineinkommt, wird zuerst entfernt. Der neueste Aufruf liegt oben und wird ausgeführt, während sein Aufrufer darunter wartet. Wenn er zurückkehrt, entfernt Java seinen Rahmen und setzt beim Aufrufer fort.

public static void main(String[] args) {
    int total = totalSeconds(2, 30);
    System.out.println(total);
}

public static int totalSeconds(int minutes, int seconds) {
    int fromMinutes = toSeconds(minutes);
    return fromMinutes + seconds;
}

public static int toSeconds(int minutes) {
    return minutes * 60;
}

Verfolge die noch nicht abgeschlossenen Aufgaben:

  1. main beginnt und ruft totalSeconds(2, 30) auf. Die Zuweisung an total muss warten.
  2. Der neue Rahmen enthält minutes = 2 und seconds = 30. Die Methode ruft toSeconds(minutes) auf und wartet auf fromMinutes.
  3. toSeconds erhält ein eigenes minutes = 2. Die Methode gibt 120 zurück und ihr Rahmen wird entfernt.
  4. totalSeconds speichert fromMinutes = 120, addiert 30 und gibt 150 zurück. Sein Rahmen wird entfernt.
  5. main speichert total = 150 und gibt 150 aus.

An der tiefsten Stelle liegen die Rahmen von unten nach oben in der Reihenfolge main, totalSeconds und toSeconds. Beide Hilfsmethoden haben einen Parameter namens minutes, aber diese Parameter liegen in verschiedenen Rahmen. Die lokalen Variablen des wartenden Aufrufers werden für die Methode darüber nicht sichtbar.

Ein späterer Aufruf erhält einen neuen Rahmen. Ein lokaler Zähler merkt sich seinen vorherigen Wert nicht, nachdem sein Aufruf beendet wurde; der Rückgabewert kann ein Ergebnis zurückübermitteln.

Lies einen Stacktrace vom Fehler nach außen

Bei einer unbehandelten Ausnahme wird ein Stacktrace ausgegeben, der zeigt, wo der Fehler auftrat und welche Aufrufe dorthin führten. Hier ist eine vollständige Datei:

public class Main {
    public static void main(String[] args) {
        report(300, 0);
    }

    public static void report(int meters, int minutes) {
        int speed = perMinute(meters, minutes);
        System.out.println(speed + " m per minute");
    }

    public static int perMinute(int meters, int minutes) {
        return meters / minutes;
    }
}

Die erste Ausgabezeile lautet Exception in thread "main" java.lang.ArithmeticException: / by zero. Die Rahmen darunter sind:

at Main.perMinute(Main.java:12)
at Main.report(Main.java:7)
at Main.main(Main.java:3)

Der oberste Rahmen weist auf die Ganzzahldivision durch null hin. Die nächsten beiden zeigen die Aufrufe, die dorthin führten. Die Zeilennummern gehören genau zu diesem Aufbau der Datei; wenn du eine Zeile hinzufügst, ändern sie sich.

Der Stapel hat begrenzten Platz. Eine Kette, die fortlaufend Aufrufe hinzufügt, ohne sie enden zu lassen, kann einen StackOverflowError verursachen. In der Stapelansicht eines Debuggers kannst du dieselbe Kette untersuchen, während das Programm an einem Haltepunkt angehalten ist, einschließlich der eigenen Variablen jedes wartenden Aufrufs.

Wichtige Erkenntnisse

  • Jeder Aufruf legt einen neuen Rahmen auf den Stapel; eine Rückkehr entfernt diesen Rahmen und setzt beim Aufrufer fort.
  • Der neueste noch nicht beendete Aufruf wird zuerst ausgeführt: Der Stapel folgt dem LIFO-Prinzip.
  • Gleichnamige lokale Variablen in verschiedenen Rahmen sind getrennte Variablen.
  • Verfolge einen Rückgabewert zurück in den wartenden Ausdruck oder die wartende Zuweisung.
  • Lies einen Stacktrace vom Fehlerrahmen oben zu den aufrufenden Methoden darunter.
  • Eine Kette, die fortlaufend Rahmen hinzufügt, kann den Stapel erschöpfen.
4

Überlade Methoden

Eine nützliche Operation kann mehrere Arten von Eingaben akzeptieren. Durch Überladen können diese Formen einen Namen teilen und jeweils eine eigene Parameterliste behalten. Prüfe zuerst, ob zwei Deklarationen wirklich unterschiedliche Signaturen haben. Verfolge dann die Wahl des Compilers bei einem Aufruf: Zähle die Argumente, bestimme ihre Typen und vergleiche die kompatiblen Versionen. Der Typ einer aufnehmenden Variablen kann einen Aufruf nicht retten, dessen Argumente keine geeignete Überladung bestimmen.

4.1 Schreibe überladene Methoden

Überladen gibt Methoden denselben Namen mit unterschiedlichen Parameterlisten. Das ist nützlich, wenn die Methoden dieselbe Aufgabe für eine unterschiedliche Anzahl oder unterschiedliche Typen von Eingaben erfüllen.

Vergleiche Signaturen

Für diese Methoden besteht eine Signatur aus dem Namen und den Parametertypen in ihrer Reihenfolge. Die Anzahl der Parameter ergibt sich aus dieser Liste.

public static int max(int a, int b) {
    if (a > b) {
        return a;
    }
    return b;
}

public static int max(int a, int b, int c) {
    return max(max(a, b), c);
}

public static double max(double a, double b) {
    if (a > b) {
        return a;
    }
    return b;
}

Die Signaturen lauten max(int, int), max(int, int, int) und max(double, double). max(3, 9) verwendet die erste und gibt 9 zurück. max(3, 9, 5) ruft die zweite auf: Der innere Aufruf mit zwei int-Werten gibt 9 zurück, dann vergleicht der äußere Aufruf mit zwei int-Werten 9 und 5 und gibt ebenfalls 9 zurück. max(2.5, 1.0) verwendet die double-Version und gibt 2.5 zurück.

Erkenne, welche Änderungen nicht zählen

Eine Änderung allein des Rückgabetyps erzeugt keine Überladung. Diese Köpfe stehen im Konflikt:

public static int area(int w, int h)
public static double area(int w, int h)

Beide haben die Signatur area(int, int). Java lehnt die doppelte Deklaration ab. Auch das Umbenennen der Parameter in width und height lässt die Signatur gleich: Aufrufer übergeben Werte nach Position, nicht nach Parameternamen.

Die Reihenfolge unterschiedlicher Typen zählt dagegen. describe(String s, int n) und describe(int n, String s) sind unterschiedliche Signaturen. Sie lassen sich zusammen kompilieren, aber ein Aufrufer muss sich eine leicht zu verwechselnde Reihenfolge merken; verwende ein solches Paar daher nur, wenn es dem Entwurf hilft.

Lass eine kürzere Überladung einen Standardwert liefern

Java bietet in Methodendeklarationen keine Standardwerte für Parameter. Eine kürzere Überladung kann eine längere mit einem festen Argument aufrufen:

public static void printLine(int length, char symbol) {
    for (int i = 0; i < length; i++) {
        System.out.print(symbol);
    }
    System.out.println();
}

public static void printLine(int length) {
    printLine(length, '-');
}

printLine(5, '*'); gibt ***** aus. printLine(4); führt die kürzere Methode aus, die die längere mit 4 und '-' aufruft und ---- ausgibt. Die Schleife steht an einer Stelle, sodass Änderungen an der Ausgabeaufgabe für beide Formen gelten.

Auch die Java-Bibliothek verwendet Überladungen. System.out.println akzeptiert über verschiedene Versionen einen int-, double-, char-, boolean- oder String-Wert. Math.abs und Math.max bieten Versionen für int, long, float und double an.

Gib dem gemeinsamen Namen eine einzige Bedeutung. Das Ausgeben eines Belegs und das Ausgeben eines Etiketts sind unterschiedliche Aufgaben; klare Namen wie printReceipt und printLabel sagen dem Aufrufer, welche Aufgabe ausgeführt wird.

Wichtige Erkenntnisse

  • Überladungen haben denselben Namen und unterscheiden sich in Anzahl, Typen oder Reihenfolge der Parametertypen.
  • Rückgabetypen und Parameternamen unterscheiden Signaturen nicht.
  • Eine kürzere Überladung kann eine längere mit einem festen Standardargument aufrufen.
  • Verwende einen überladenen Namen für eine Aufgabe mit unterschiedlichen Eingabeformen.

4.2 Sage voraus, welche überladene Methode ausgeführt wird

Der Compiler wählt eine Überladung anhand der Anzahl und der Typen der Argumente. Ermittle diese Wahl, bevor du betrachtest, wie der Rückgabewert verwendet wird.

Beginne mit exakten Typübereinstimmungen

Angenommen, eine Klasse definiert show(int x) und show(double x). show(5) verwendet die int-Version, weil das Literal 5 ein int-Wert ist. show(5.0) verwendet die double-Version. Ein als 5.0 geschriebener ganzzahliger Wert ist weiterhin ein double-Ausdruck.

Vergleiche bei einem Aufruf mit mehreren Argumenten den Typ an jeder Position. Ein Kandidat mit der falschen Anzahl von Argumenten kann nicht passen.

Erlaube bei Bedarf eine erweiternde Typumwandlung

Existiert nur show(double x), ist show(5) gültig: Der int-Wert wird zu 5.0 erweitert. Zu den möglichen erweiternden Umwandlungen primitiver Typen gehören:

byte → short → int → long → float → double
char → int → long → float → double

Bei show(long x) und show(double x) wählt ein int-Argument long. Das ist der spezifischere kompatible Parametertyp: Ein long-Wert kann zu double erweitert werden, ein double-Wert aber nicht zurück zu long.

Eine erweiternde Typumwandlung ist eine zulässige numerische Umwandlung; sie garantiert nicht, dass bei jeder solchen Umwandlung alle Stellen erhalten bleiben. Insbesondere kann bei der Umwandlung eines ausreichend großen long-Werts in double sein Wert gerundet werden. Die in den vorherigen Beispielen verwendete Umwandlung von int zu double erhält alle int-Werte exakt.

Ein char-Wert hat ebenfalls einen numerischen Wert. Bei letter(int code) und letter(String text) ruft letter('A') die int-Version mit 65 auf. Ein Zeichen wird nicht in einen String umgewandelt, damit es zu einem Parameter passt. Doppelte Anführungszeichen in "A" würden stattdessen ein String-Argument erzeugen.

Schließe implizite einengende Typumwandlungen aus

Gibt es nur show(int x), schlägt show(5.0) fehl. Java wandelt ein double-Argument nicht einengend um, nur weil sein Wert zufällig ganzzahlig ist. show((int) 5.0) übergibt nach einem expliziten Cast einen int-Wert.

Ebenso können Versionen von max für zwei und drei int-Werte max(1) nicht akzeptieren. Kein Kandidat hat die erforderliche Anzahl von Parametern, daher meldet der Compiler „no suitable method found“. Vergleiche die Kandidatenliste mit den übergebenen Argumenten.

Trenne die Auswahl der Überladung von der Ergebnisumwandlung

Betrachte int twice(int n) und double twice(double x). In double d = twice(3); wählt das Argument die int-Überladung. Dieser Aufruf gibt 6 zurück, dann erweitert die Zuweisung den Wert zu 6.0. Die Zielvariable d wählt nicht die double-Überladung.

Erkenne einen mehrdeutigen Aufruf
public static void combine(int a, double b) { }
public static void combine(double a, int b) { }

combine(1, 2) passt zur ersten Version nach Erweiterung des zweiten Arguments und zur zweiten nach Erweiterung des ersten. Keine der beiden Signaturen ist über beide Positionen hinweg spezifischer. Java meldet „reference to combine is ambiguous“; es wählt nicht die zuerst geschriebene Definition.

combine(1, 2.0) passt nur zu (int, double), weil die andere Signatur eine einengende Umwandlung von 2.0 benötigen würde. Ein eindeutiger Argumenttyp oder eine bessere Auswahl an Überladungen beseitigt die Mehrdeutigkeit.

Wichtige Erkenntnisse

  • Wähle eine Überladung zur Kompilierzeit anhand der Anzahl und der Typen der Argumente.
  • Eine exakte Typübereinstimmung hat Vorrang; eine erweiternde Typumwandlung kann eine andere Version kompatibel machen.
  • Java wandelt numerische Methodenargumente nicht implizit einengend um.
  • Die Variable, die das Ergebnis aufnimmt, wählt die Überladung nicht aus.
  • Mehrdeutigkeit bedeutet, dass mehrere Versionen passen und keine über den ganzen Aufruf hinweg spezifischer ist.
5

Zerlege ein Programm in Methoden

Die Methoden eines Programms sollten seinen Plan erkennen lassen. Gib jeder Methode eine sinnvolle Aufgabe, übergib ihr die benötigten Werte und verwende ihr Ergebnis im nächsten Schritt. Wiederholter Code deutet oft auf eine fehlende Methode hin; eine lange Methode zeigt oft, dass mehrere Aufgaben vermischt sind. Plane zuerst die Methodenköpfe, entwickle kleine Teile mit bekannten Ergebnissen und verbinde sie nach und nach. So lassen sich sowohl der Datenfluss als auch die Stelle eines neuen Fehlers leichter erkennen.

5.1 Gib jeder Methode eine klar abgegrenzte Aufgabe

Problemzerlegung bedeutet, ein Problem in kleinere Aufgaben zu teilen und jede Aufgabe in einer eigenen Methode zu lösen. Wähle Aufgaben, deren Namen helfen, den Plan des Programms zu verstehen.

Trenne Berechnung und Ein- und Ausgabe

Ein Programm für eine Radtour benötigt eine Geschwindigkeitsberechnung und einen Bericht. Beide verwenden dieselben Daten, haben aber unterschiedliche Aufgaben:

public static double kilometersPerHour(double km, double hours) {
    return km / hours;
}

public static void printRideReport(double speed) {
    System.out.println("Speed: " + speed + " km/h");
}

Für eine Fahrt von 150 km in 2 Stunden gibt die Berechnung 75.0 zurück. Die Berichtsmethode erhält diesen Wert und zeigt ihn an. Ein Aufrufer verbindet die Schritte:

double speed = kilometersPerHour(150, 2);
printRideReport(speed);

Die Berechnung liest keine Tastatureingaben und gibt keinen Bericht aus. Ein anderes Programm kann sie verwenden, um Fahrten zu vergleichen oder Geschwindigkeiten zu speichern, ohne ihren Rumpf zu ändern. Um sie zu testen, rufe sie mit bekannten Eingaben auf und vergleiche die zurückgegebene Zahl mit der erwarteten.

Erkenne eine Methode mit zu vielen Aufgaben

Ein Name wie readAndCheckAndPrint deutet auf mehrere Tätigkeiten hin. Weitere Hinweise sind durch Kommentare gekennzeichnete Abschnitte, ein Rumpf, der länger als eine Bildschirmseite ist, und Gruppen von Variablen, die unabhängigen Zwecken dienen. Das sind Gründe, die Methode zu untersuchen, keine starren Grenzen für ihre Zeilenanzahl.

Teile an einer sinnvollen Stelle. Eingabecode kann einen Wert einlesen, eine boolesche Hilfsmethode kann ihn prüfen, eine Berechnung kann ein Ergebnis zurückgeben und eine Berichtsmethode kann es anzeigen. Dann liest sich main wie eine kurze Beschreibung, wie diese Aufgaben zusammenhängen.

Auf eine Aufgabe konzentrierte Methoden lassen sich einzeln leichter lesen, wiederverwenden und testen. Ändert sich das Format eines Berichts, bearbeite die Berichtsmethode. Ist eine Berechnung falsch, teste sie, ohne eine ganze Folge von Eingaben eintippen zu müssen.

Lass den Kopf den Datenfluss erklären

In kilometersPerHour(double km, double hours) nennt der Name das Ergebnis, die Parameternamen nennen die Größen und der Rückgabetyp double nennt die Art des Ergebnisses. Ein kurzer Javadoc-Kommentar kann die Bedeutung der Eingaben und des Ergebnisses ergänzen:

/**
 * Calculates a ride's average speed.
 * @param km distance in kilometers
 * @param hours elapsed time in hours, greater than zero
 * @return speed in kilometers per hour
 */

Setze diesen Kommentar direkt über den Methodenkopf. Ein nützlicher Kommentar ergänzt Informationen wie Einheiten oder eine Anforderung an die Eingabe; er muss nicht jede Zeile des Rumpfs beschreiben.

Eine Hilfsmethode, die nur ihre eigene Klasse benötigt, kann private static sein. private verhindert, dass andere Klassen sie aufrufen, während Code in derselben Klasse sie weiterhin verwenden kann. public static stellt die Hilfsmethode anderen Klassen zur Verfügung.

Auch wenn du jede offensichtliche Anweisung in eine eigene umhüllende Methode auslagerst, kann das den Plan verschleiern. Behalte eine Methode, wenn ihr Name für einen sinnvollen Schritt oder eine wiederverwendbare Berechnung steht. Eine Kette von Hilfsmethoden, die denselben Aufruf nur weiterreichen, schafft mehr Stellen zum Untersuchen, ohne mehr über die Aufgabe zu erklären.

Wichtige Erkenntnisse

  • Zerlege ein Programm in sinnvolle Aufgaben mit klaren Namen.
  • Berechnungsmethoden nehmen Parameter entgegen und geben Ergebnisse zurück; Berichtsmethoden zeigen sie an.
  • Hilfsmethoden mit klarer Aufgabe lassen sich einzeln wiederverwenden und testen.
  • Ein Methodenkopf und ein kurzer Javadoc-Kommentar können Eingaben, Einheiten und Ergebnis angeben.
  • Verwende private static für Hilfsmethoden, die nur ihre eigene Klasse aufrufen soll.
  • Teile dort auf, wo ein Name die Aufgabe verdeutlicht, nicht bei jeder einzelnen Anweisung.

5.2 Ersetze wiederholten Code durch eine parametrisierte Methode

Codeduplizierung wiederholt dieselbe Aufgabe an mehreren Stellen. Wenn sich nur die Eingabewerte unterscheiden, kann eine parametrisierte Methode die gemeinsame Arbeit zusammenhalten.

Finde die gemeinsame Berechnung

Angenommen, ein Programm summiert von 1 bis 10 und dann von 1 bis 50:

int total1 = 0;
for (int i = 1; i <= 10; i++) {
    total1 += i;
}
System.out.println("Sum 1 to 10: " + total1);
int total2 = 0;
for (int i = 1; i <= 50; i++) {
    total2 += i;
}
System.out.println("Sum 1 to 50: " + total2);

Beide Schleifen beginnen bei 1, addieren zu einer Summe und enden bei einer oberen Grenze. Nur diese Grenze ändert sich. Ein Parameter n kann sie an eine gemeinsame Berechnung übergeben.

Extrahiere die Methode
public static int sumUpTo(int n) {
    int total = 0;
    for (int i = 1; i <= n; i++) {
        total += i;
    }
    return total;
}

n ist die veränderliche Eingabe. total und i sind Arbeitsvariablen, die in die Hilfsmethode gehören. Der Aufrufer benötigt die fertige Summe, also gibt die Hilfsmethode einen int-Wert zurück.

Ersetze beide wiederholten Abschnitte:

System.out.println("Sum 1 to 10: " + sumUpTo(10));
System.out.println("Sum 1 to 50: " + sumUpTo(50));

sumUpTo(10) gibt 55 zurück und sumUpTo(50) gibt 1275 zurück. Die ausgegebenen Zeilen lauten wie zuvor „Sum 1 to 10: 55“ und „Sum 1 to 50: 1275“. Die Beschreibungen bleiben beim Aufrufer; die Schleife führt nur die Berechnung aus.

Prüfe die Extraktion in einer festen Reihenfolge
  1. Markiere die Anweisungen, die die wiederholte Aufgabe erfüllen.
  2. Bestimme jeden Wert, der sich zwischen den Kopien unterscheidet.
  3. Mache diese Werte zu Parametern mit passenden Typen und gib jedes außerhalb benötigte Ergebnis zurück.
  4. Ersetze jede Kopie durch einen Aufruf mit ihren ursprünglichen Eingaben.
  5. Führe das Programm vorher und nachher mit denselben Eingaben aus und vergleiche das Verhalten.

Die Struktur von Code zu ändern und dabei sein Verhalten zu erhalten, heißt Refactoring. Bleibt eine ursprüngliche Kopie zurück, muss eine spätere Korrektur weiterhin an zwei Stellen vorgenommen werden. Verschiebst du eine Ausgabe in eine Schleife oder änderst einen Schleifenendpunkt, ändert sich das Verhalten, auch wenn der Code nun kürzer ist.

Haben zwei Unterschiede verschiedene Typen, verwende passende Parameter. Soll unterschiedlicher Text unterschiedlich oft wiederholt werden, bietet sich printRepeated(String text, int times) an; das Wort ist ein String und die Anzahl ein int-Wert.

Ähnlich aussehender Code erfüllt nicht immer dieselbe Aufgabe. Ein boolescher Parameter, der eine Methode zwischen unabhängigen Berechnungen umschaltet, kann ihre Aufrufe schwer verständlich machen. Gib unterschiedlichen Aufgaben unterschiedliche Namen. Extrahiere die wiederholte Operation nur, wenn sie beim Ändern ihrer Eingaben eine klare Bedeutung behält.

Wichtige Erkenntnisse

  • Bestimme die gemeinsame Aufgabe und mache ihre veränderlichen Eingaben zu Parametern.
  • Halte Arbeitsvariablen lokal und gib jedes Ergebnis zurück, das der Aufrufer benötigt.
  • Überarbeite jede Kopie und vergleiche das Verhalten mit denselben Eingaben.
  • Führe Kopien derselben Aufgabe zusammen, nicht unabhängige Aufgaben, die nur ähnlich aussehen.

5.3 Entwirf ein Programm nach dem Top-down-Prinzip und teste jede Methode einzeln

Der Top-down-Entwurf beginnt mit der gesamten Aufgabe und verfeinert sie zu kleineren Methodenaufrufen. Entscheide, was jeder Aufruf benötigt und zurückgibt, bevor du alle Einzelheiten ausarbeitest.

Plane die Schritte und Köpfe

Ein Programm für die wöchentliche Bewegung liest 7 Tagesdauern ein, addiert sie und gibt einen Bericht aus. Seine Hilfsmethoden lassen sich so planen:

  • readMinutes(Scanner scanner, int day) gibt die gültige Minutenzahl eines Tages zurück.
  • isValidMinutes(int minutes) beantwortet, ob die Eingabe zwischen 0 und 1440 liegt.
  • formatDuration(int minutes) gibt Text mit vollen Stunden und verbleibenden Minuten zurück.
  • averagePerDay(int total, int days) gibt einen Durchschnitt als double-Wert zurück.
  • printSummary(int totalMinutes, int days) gibt den Bericht aus.

Derselbe Scanner wird an jeden Eingabeaufruf übergeben. Eine Hilfsmethode wie isValidMinutes muss selbst keine Eingabe lesen.

Verwende beim Entwickeln Stubs

Ein Stub hat seinen endgültigen Kopf, aber einen vorläufigen minimalen Rumpf, etwa return 0;. Er ermöglicht das Kompilieren des Programms, bevor eine Hilfsmethode implementiert ist. Ersetze einen Stub, kompiliere und prüfe diese Methode, bevor du den nächsten ersetzt. Ein kompilierbarer Stub ist weiterhin unvollendete Arbeit; seine feste Antwort kann keine echte Berechnung überprüfen.

Hier ist das vollständige Programm:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int total = 0;
        for (int day = 1; day <= 7; day++) {
            total += readMinutes(scanner, day);
        }
        printSummary(total, 7);
    }

    public static int readMinutes(Scanner scanner, int day) {
        System.out.println("Minutes for day " + day + ":");
        int minutes = scanner.nextInt();
        while (!isValidMinutes(minutes)) {
            System.out.println("Enter minutes from 0 to 1440:");
            minutes = scanner.nextInt();
        }
        return minutes;
    }

    public static boolean isValidMinutes(int minutes) {
        return minutes >= 0 && minutes <= 1440;
    }

    public static String formatDuration(int minutes) {
        return minutes / 60 + " h " + minutes % 60 + " min";
    }

    public static double averagePerDay(int total, int days) {
        return (double) total / days;
    }

    public static void printSummary(int totalMinutes, int days) {
        System.out.println("Total: " + formatDuration(totalMinutes));
        System.out.println("Daily average: "
            + averagePerDay(totalMinutes, days) + " min");
        if (totalMinutes >= 150) {
            System.out.println("Weekly goal reached");
        }
    }
}

Bei ganzzahligen Eingaben wiederholt readMinutes seine Wertebereichsprüfung, bis die Zahl gültig ist. Bei den täglichen Eingaben 30, 45, 0, 60, 90, 45 und 45 beträgt die Summe 315. Die Formatierung ergibt „5 h 15 min“, der Durchschnitt beträgt 45.0 Minuten und das Programm meldet, dass sein Wochenziel von 150 Minuten erreicht ist.

Prüfe kleine Methoden und ihre Grenzwerte

Rufe jede Berechnung mit bekannten Ergebnissen auf. formatDuration(0) sollte „0 h 0 min“ ergeben, 59 ergibt „0 h 59 min“, 60 ergibt „1 h 0 min“ und 135 ergibt „2 h 15 min“. Die Eingaben knapp unter und bei 60 prüfen den Wechsel von Minuten zu einer vollen Stunde.

Teste für isValidMinutes die Werte -1, 0, 1440 und 1441. Die erwarteten Ergebnisse sind false, true, true und false. Wenn du erwartete und tatsächliche Werte nebeneinander ausgibst, wird ein Fehler sichtbar. JUnit automatisiert diese Art von Prüfung.

Die Bottom-up-Entwicklung beginnt damit, kleine Hilfsmethoden zu schreiben und zu testen, und verbindet sie dann zu größeren Schritten. Du kannst nach dem Top-down-Prinzip planen und nach dem Bottom-up-Prinzip entwickeln: Lege zuerst den Datenfluss fest, beweise dann, dass die kleinen Berechnungen funktionieren, und prüfe anschließend das verbundene Programm.

Wichtige Erkenntnisse

  • Der Top-down-Entwurf macht aus einer Gesamtaufgabe Aufrufe und verfeinert dann jede Aufgabe.
  • Lege Eingaben und Rückgabetyp jeder Hilfsmethode vor ihrem Rumpf fest.
  • Ein Stub behält einen geplanten Kopf bei, während sein Rumpf noch vorläufig ist.
  • Teste bekannte Ergebnisse und Werte an und um Grenzwerte.
  • Entwickle und prüfe jeweils eine Methode und teste dann das verbundene Programm.
  • Die Bottom-up-Entwicklung erstellt kleine Hilfsmethoden, bevor sie diese kombiniert.

Java-Methoden und Problemzerlegung: Beispiele

5 Interaktive Lektionen

1

Entwickle eine wiederverwendbare Methode zur Linienausgabe

11 Schritte
Definiere eine Hilfsmethode, verfolge ihre Aufrufe und ergänze Parameter für veränderliche Eingaben.
  1. 1
    EinführungMache aus einer wiederholten Aktion einen Aufruf

    Ein Bericht benötigt an mehreren Stellen eine kurze Trennlinie. Wenn diese Aktion einen Methodennamen erhält, kann der Bericht eine Trennlinie anfordern, ohne die Ausgabeanweisungen zu wiederholen. Diese benannte Aktion ist eine Methode, und eine Definition dient jedem Aufruf.

    Beginne mit einer festen Trennlinie. Lass dann den Aufrufer ihre Breite und ihr Zeichen über Parameter wählen. Verfolge Definition, Aufruf und übergebene Werte als drei verschiedene Teile der Aufgabe.

  2. 2
    ErklärungLies einen Methodenkopf
    public static void printDivider() {
        System.out.println("====");
    }
    

    printDivider ist der Name. public erlaubt Aufrufe aus anderen Klassen; static bedeutet, dass kein Objekt benötigt wird. void besagt, dass kein Wert zurückkommt, und () besagt, dass keine Eingabe erforderlich ist.

    Die Anweisung innerhalb der geschweiften Klammern ist der Rumpf. Nur weil diese Definition existiert, wird nichts ausgegeben.

  3. 3
    TippSetze die Hilfsmethode neben main

    In einer klassischen Klasse sind main und printDivider getrennte Methoden innerhalb derselben Klassenklammern. Schließe den Rumpf von main, bevor du mit dem Kopf der Hilfsmethode beginnst.

    Eine Hilfsmethode kann über oder unter main stehen; ihre Position legt nicht fest, wann sie ausgeführt wird. Eine Definition innerhalb von main wird abgelehnt. Prüfe zuerst die Klammern, wenn ein Methodenkopf „illegal start of expression“ verursacht.

  4. 4
    BeispielVerfolge den ersten Aufruf

    Angenommen, main enthält:

    System.out.println("Items");
    printDivider();
    System.out.println("End");
    

    Die Ausführung gibt zuerst „Items“ aus. Der Aufruf führt zu printDivider, das „====“ ausgibt. Wenn die Hilfsmethode endet, fährt main bei seiner nächsten Anweisung fort und gibt „End“ aus.

    Der Rumpf der Hilfsmethode wird zwischen den beiden Anweisungen des Aufrufers ausgeführt, genau dort, wo der Aufruf steht.

  5. 5
    HerausforderungSetze eine zweite Trennlinie

    main ruft printDivider(); auf, gibt "A" aus und ruft erneut printDivider(); auf. Welche drei Zeilen erscheinen?

    ---reveal---

    Die Zeilen lauten „====“, „A“ und „====“. Jeder Aufruf führt denselben Rumpf der Hilfsmethode aus, gibt einmal etwas aus und kehrt zu seiner eigenen Stelle in main zurück.

    printDivider; wäre kein Aufruf. Auch ohne Argumente sind die Klammern erforderlich.

  6. 6
    ErklärungMache die Breite zur Eingabe

    Ersetze den festen Rumpf durch eine Schleife:

    public static void printDivider(int length) {
        for (int i = 0; i < length; i++) {
            System.out.print("=");
        }
        System.out.println();
    }
    

    length ist ein im Kopf deklarierter Parameter. In printDivider(6); wird das Argument 6 zu seinem Anfangswert. Sechs Schleifendurchläufe geben sechs Zeichen aus, bevor die Zeile endet.

  7. 7
    BeispielWerte einen Ausdruck vor dem Aufruf aus
    int sections = 3;
    printDivider(sections + 2);
    

    Werte zuerst sections + 2 aus und erhalte 5. Führe dann die Hilfsmethode mit ihrem Parameter length = 5 aus. Ihre Schleife gibt „=====“ aus.

    sections und length müssen nicht denselben Namen haben. Ein Parameter erhält den ausgewerteten Argumentwert; der Aufrufer schreibt den Typ nicht in den Aufruf.

  8. 8
    BeispielErgänze eine zweite veränderliche Eingabe

    Um auch das Zeichen zu wählen, verwende:

    public static void printDivider(int length, char symbol) {
        for (int i = 0; i < length; i++) {
            System.out.print(symbol);
        }
        System.out.println();
    }
    

    Der Aufruf printDivider(3, '+'); übergibt 3 an length und '+' an symbol und gibt „+++“ aus. Jeder Parameter benötigt im Kopf seinen eigenen Typ.

  9. 9
    TippPrüfe Anzahl, Reihenfolge und Typ

    Ein Aufruf muss für jeden Parameter einen kompatiblen Wert liefern. Bei printDivider(3); fehlt nun das Zeichen, während printDivider("3", '+'); Text übergibt, wo ein int-Wert benötigt wird.

    Java kann einen int-Wert für einen double-Parameter zu double erweitern. Es kann 3.7 nicht implizit einengend umwandeln, damit der Wert zu diesem int-Parameter passt. Der explizite Cast (int) 3.7 liefert 3, indem er den Nachkommateil abschneidet.

  10. 10
    HerausforderungSage einen parametrisierten Aufruf voraus

    Welche Zeile gibt dies mit der Hilfsmethode mit zwei Parametern aus?

    int width = 4;
    printDivider(width - 1, '#');
    

    ---reveal---

    Es wird „###“ ausgegeben. Der Ausdruck wird zu 3 ausgewertet, dann erhält der erste Parameter diese Anzahl und der zweite '#'. Die Schleife läuft dreimal.

    Der Aufruf ist eine Anweisung und endet daher mit einem Semikolon. Seine Argumentausdrücke enthalten Werte, keine Parameterdeklarationen.

  11. 11
    ZusammenfassungLies die Aktion und ihre Eingaben

    Eine Definition gibt einer Aufgabe einen Kopf und einen Rumpf; ein Aufruf führt sie aus und setzt dann beim Aufrufer fort. Halte Definitionen innerhalb der Klasse und außerhalb anderer Methoden.

    Parameter beschreiben die benötigten Eingaben. Aufrufe liefern ausgewertete Argumente in der passenden Reihenfolge, in der richtigen Anzahl und mit kompatiblen Typen.

2

Gib Antworten zurück und beende Suchen

13 Schritte
Verwende Rückgabewerte beim Aufrufer und verfolge dann vorzeitige Rückgaben und vollständige Rückgabepfade.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungGib ein Ergebnis an den Aufrufer zurück
  2. 2
    ErklärungLass einen Aufruf für einen Wert stehen
  3. 3
    KernaussageEine Ausgabe liefert keinen Wert für eine Zuweisung
  4. 4
    BeispielBehalte den Nachkommateil
  5. 5
    HerausforderungVerwende das Ergebnis in einem anderen Ausdruck
  6. 6
    BeispielGib formatierten Text zurück
  7. 7
    ErklärungEin return beendet diesen Aufruf
  8. 8
    TippPrüfe den Pfad, der den if-Block auslässt
  9. 9
    BeispielSchreibe eine Suche mit einem Ergebnis für Misserfolg
  10. 10
    BeispielVerfolge die Suche bis zu ihrem Ende
  11. 11
    HerausforderungFinde einen vorzeitig gemeldeten Misserfolg
  12. 12
    HerausforderungVerbinde ein Suchergebnis mit einer Bedingung
  13. 13
    ZusammenfassungVerfolge Antwort und Abbruchstelle
3

Halte die Variablen jedes Aufrufs getrennt

15 Schritte
Verfolge Gültigkeitsbereiche, kopierte Werte und wartende Stapelrahmen in einem kleinen Programm.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungOrdne jede Variable ihrem Aufruf zu
  2. 2
    ErklärungEine Hilfsmethode sieht ihre eigenen lokalen Variablen
  3. 3
    BeispielHalte eine Summe außerhalb der Schleife
  4. 4
    HerausforderungUnterscheide Gültigkeitsbereich und Initialisierung
  5. 5
    BeispielKopiere eine Zahl in einen Parameter
  6. 6
    BeispielWeise den zurückgegebenen Ersatzwert zu
  7. 7
    HerausforderungSage einen zweiten Aufruf voraus
  8. 8
    VerbindungFür kopierte Referenzen gilt dieselbe Regel
  9. 9
    BeispielBeginne eine äußere Berechnung
  10. 10
    BeispielHalte den Aufrufer an und lege einen weiteren Rahmen auf den Stapel
  11. 11
    BeispielÜbertrage Ergebnisse auf dem Stapel nach unten
  12. 12
    TippLies einen Fehler aus dem obersten Rahmen
  13. 13
    HerausforderungFinde die wartende Aufgabe
  14. 14
    HerausforderungVerbinde Kopien mit Ergebnissen auf dem Stapel
  15. 15
    ZusammenfassungHalte Namen, Werte und Rahmen auseinander
4

Wähle die richtige überladene Methode

12 Schritte
Vergleiche Signaturen, verwende eine längere Überladung wieder und bestimme anhand der Argumenttypen die passenden Aufrufe.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungEine Aufgabe, mehrere Eingabeformen
  2. 2
    ErklärungBestimme eine Signatur
  3. 3
    KernaussageEin Rückgabetyp kann keine Überladung erzeugen
  4. 4
    BeispielDelegiere an die vollständige Version
  5. 5
    HerausforderungPrüfe eine vorgeschlagene dritte Deklaration
  6. 6
    ErklärungWähle eine exakte numerische Typübereinstimmung
  7. 7
    BeispielVerwende erweiternde ohne einengende Typumwandlung
  8. 8
    BeispielTrenne den Aufruf von seiner Zuweisung
  9. 9
    BeispielVergleiche jede Argumentposition
  10. 10
    TippNutze die Kandidatenliste zur Untersuchung eines Aufrufs
  11. 11
    HerausforderungWähle eine Version und verwende dann ihr Ergebnis
  12. 12
    ZusammenfassungPrüfe Definitionen vor Aufrufen
5

Erstelle einen kleinen Bericht aus getesteten Hilfsmethoden

16 Schritte
Trenne Aufgaben, extrahiere wiederholten Code und plane ein vollständiges Programm um getestete Methoden.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungTeile einen Bericht in kleine Aufgaben auf
  2. 2
    ErklärungBenenne die Aufgabe, bevor du den Rumpf schreibst
  3. 3
    BeispielMache die Berechnung wiederverwendbar
  4. 4
    BeispielGib der Ausgabe eine eigene Methode
  5. 5
    HerausforderungVerwende eine Berechnung ohne Bericht wieder
  6. 6
    ErklärungFinde, was sich im wiederholten Code ändert
  7. 7
    BeispielWähle den extrahierten Methodenkopf
  8. 8
    BeispielSetze die gemeinsame Schleife an eine Stelle
  9. 9
    HerausforderungErhalte die letzte Wiederholung
  10. 10
    ErklärungPlane das Programm von oben
  11. 11
    TippVerwende einen Stub nur während der Entwicklung
  12. 12
    BeispielÜbergib denselben Eingabeleser
  13. 13
    BeispielPrüfe die Berechnung vor dem Verbinden
  14. 14
    BeispielPrüfe eine Eingabefolge im verbundenen Programm
  15. 15
    HerausforderungFinde einen Fehler beim Verbinden
  16. 16
    ZusammenfassungEntwickle sinnvolle Teile und verbinde sie

Java-Methoden und Problemzerlegung: Übungsaufgaben

40 Übungsfragen in 4 Sets

Set 1: Aufrufe, Werte und kleine Programmschritte10 Übungsfragen

Frage 1 von 10

Eine klassische Java-Klasse hat eine main-Methode und benötigt eine neue Methode printMenu. Wohin gehört die neue Definition?
  1. In main, nach der letzten Anweisung.
  2. In die Klasse, außerhalb aller anderen Methoden.
  3. Außerhalb der Klasse, nach ihrer schließenden Klammer.
  4. In die Methode, die sie aufrufen muss.
Antwort zeigenAntwort ausblenden
Antwort: B
Eine Methodendefinition gehört in die Klasse und außerhalb jeder anderen Methode. Der Aufruf einer Hilfsmethode aus main macht ihre Definition nicht zu einem Teil von main; dort würde eine verschachtelte Methodendefinition entstehen, die Java ablehnt.

Frage 2 von 10

Welche Zeile gibt dieser Aufruf aus?

public static void showPair(int rows, int columns) {
    System.out.println(rows + ":" + columns);
}
int width = 7;
showPair(3, width - 2);
  1. 5:3
  2. 3:7
  3. 7:3
  4. 3:5
Antwort zeigenAntwort ausblenden
Antwort: D
Das erste Argument liefert rows = 3. Der Ausdruck width - 2 wird vor dem Aufruf ausgewertet, sodass der zweite Parameter 5 erhält und die Ausgabe „3:5“ lautet. Der Name width beim Aufrufer ändert die Zuordnung der Argumente nach Position nicht.

Frage 3 von 10

Welchen Wert gibt halfTotal(8, 5) zurück?

public static double halfTotal(int a, int b) {
    return (a + b) / 2;
}
  1. 6.0
  2. 6.5
  3. 13.0
  4. 7.0
Antwort zeigenAntwort ausblenden
Antwort: A
Die Addition ergibt den int-Wert 13, und die Division durch den int-Wert 2 ergibt 6. Dieses Ergebnis wird zum zurückgegebenen double-Wert 6.0 erweitert. Ein Rückgabetyp double sorgt nicht dafür, dass die frühere Division mit Dezimalzahlen rechnet; um 6.5 zu erhalten, wäre ein Divisor 2.0 nötig.

Frage 4 von 10

Warum lässt sich diese Methode nicht kompilieren?

public static String label(int n) {
    if (n >= 0) {
        return "ready";
    }
}
  1. Der Rückgabewert muss zuerst ausgegeben werden.
  2. Der Vergleich darf nicht in einer Methode stehen.
  3. Negative Eingaben erreichen das Ende ohne Wert.
  4. String-Methoden dürfen nicht innerhalb eines if zurückkehren.
Antwort zeigenAntwort ausblenden
Antwort: C
Eine negative Eingabe überspringt den if-Rumpf und erreicht die schließende Klammer ohne String-Ergebnis. Eine Methode mit diesem Rückgabetyp benötigt auch für diesen Pfad ein return. Die Rückkehr innerhalb eines if ist gültig; die fehlende Antwort außerhalb dieses Zweigs verursacht den Fehler.

Frage 5 von 10

Eine Schleife soll die Ganzzahlen 2 bis 4 addieren und danach die Summe ausgeben. Welche Deklaration soll den Kommentar ersetzen?

// declaration here
for (int i = 2; i <= 4; i++) {
    total += i;
}
System.out.println(total);
  1. int total;
  2. int total = 0;
  3. int total = 2;
  4. int total = i;
Antwort zeigenAntwort ausblenden
Antwort: B
Initialisiere total vor der Schleife mit 0, damit alle drei Additionen dieselbe Variable aktualisieren und sie für die abschließende Ausgabe sichtbar bleibt. Die alleinige Deklaration int total; weist keinen Anfangswert zu, sodass total += i eine nicht initialisierte lokale Variable lesen würde.

Frage 6 von 10

Welche zwei Zahlen werden in welcher Reihenfolge ausgegeben?

public static void lower(int level) {
    level -= 3;
    System.out.println(level);
}
int level = 14;
lower(level);
System.out.println(level);
  1. 11, dann 14
  2. 11, dann 11
  3. 14, dann 11
  4. 14, dann 14
Antwort zeigenAntwort ausblenden
Antwort: A
Die Hilfsmethode erhält ein eigenes, mit 14 initialisiertes level, verringert diese Kopie auf 11 und gibt sie aus. Das level des Aufrufers bleibt 14 und wird als Nächstes ausgegeben. Derselbe Name in beiden Methoden führt nicht dazu, dass eine Zuweisung an den Parameter die Variable des Aufrufers aktualisiert.

Frage 7 von 10

Eine Klasse deklariert bereits public static int scale(int value). Welcher zusätzliche Kopf würde mit ihrer Signatur in Konflikt stehen?
  1. public static int scale(int value, int factor)
  2. public static double scale(double value)
  3. public static long scale(long value)
  4. public static double scale(int amount)
Antwort zeigenAntwort ausblenden
Antwort: D
Der zusätzliche Kopf mit einem int-Parameter hat weiterhin die Signatur scale(int). Sein double-Rückgabetyp und der geänderte Parametername unterscheiden ihn nicht von der vorhandenen Methode. Eine Änderung des Parametertyps oder ein zusätzlicher Parameter würde eine andere Signatur erzeugen.

Frage 8 von 10

Eine Klasse hat show(int n) und show(double n). Welche Methode wird für show(12.0) ausgeführt?
  1. show(int), mit 12
  2. Beide, mit 12.0
  3. show(double), mit 12.0
  4. Keine; der Aufruf ist mehrdeutig
Antwort zeigenAntwort ausblenden
Antwort: C
Das Literal 12.0 hat den Typ double, sodass die double-Überladung exakt passt. Sein ganzzahliger Wert macht den Ausdruck nicht zu einem int-Wert. Die int-Überladung würde eine einengende Typumwandlung benötigen, die Java für dieses Argument nicht implizit durchführt.

Frage 9 von 10

Ein Routenprogramm soll eine Durchschnittsgeschwindigkeit berechnen und einen Bericht anzeigen. Welche Aufteilung macht die Geschwindigkeitsberechnung in einem Programm zum Vergleichen von Routen wiederverwendbar?
  1. Geschwindigkeit berechnen und zurückgeben; in einer eigenen Methode ausgeben.
  2. Geschwindigkeit berechnen und ausgeben; keinen Wert aus der Methode zurückgeben.
  3. Geschwindigkeit einlesen und ausgeben; bei jedem Aufrufer erneut berechnen.
  4. Geschwindigkeit berechnen und ausgeben; die Überschrift des Berichts zurückgeben.
Antwort zeigenAntwort ausblenden
Antwort: A
Eine Methode, die Strecke und Zeit erhält und die Geschwindigkeit zurückgibt, kann sowohl einem Bericht als auch einem Vergleich dienen. Halte die Anzeige in einer anderen Methode. Eine void-Berechnungsmethode, die ihre Antwort nur ausgibt, hinterlässt dem Vergleichscode kein verwendbares numerisches Ergebnis.

Frage 10 von 10

Ein Programm soll Aufgabendauern von 0 bis einschließlich 90 Minuten akzeptieren und ihren Durchschnitt ausgeben. Zurzeit verwendet es diese Hilfsmethoden. Welche zwei Aufrufe mit Eingabewerten können beide unabhängigen Fehler aufdecken?

public static boolean valid(int m) {
    return m > 0 && m <= 90;
}
public static double mean(int total, int count) {
    return total / count;
}
  1. valid(45) und mean(8, 2)
  2. valid(0) und mean(7, 2)
  3. valid(91) und mean(8, 2)
  4. valid(90) und mean(7, 2)
Antwort zeigenAntwort ausblenden
Antwort: B
valid(0) gibt fälschlich false zurück, obwohl null erlaubt ist. mean(7, 2) gibt 3.0 statt 3.5 zurück, weil vor der erweiternden Typumwandlung eine Ganzzahldivision stattfindet. Der Test mit valid(90) und diesem Mittelwert entdeckt nur den Divisionsfehler, da der obere Endpunkt bereits funktioniert.
Set 2: Verfolge Hilfsmethoden und korrigiere Methodengrenzen10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

In welcher Reihenfolge werden die Zeilen ausgegeben?

public static void frame() {
    System.out.println("Open");
    mark();
    System.out.println("Close");
}
public static void mark() {
    System.out.println("Mark");
}

main ruft frame(); auf und gibt dann "Done" aus.

  1. „Open“, „Close“, „Mark“, „Done“
  2. „Mark“, „Open“, „Close“, „Done“
  3. „Open“, „Mark“, „Done“, „Close“
  4. „Open“, „Mark“, „Close“, „Done“
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Eine Methode hat den Kopf public static void repeat(int count). Welcher Wert erreicht count bei repeat((int) 3.9 + 2);?
  1. 3
  2. 5
  3. 6
  4. 5.9
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Welcher Wert wird result zugewiesen?

public static int addTwo(int n) {
    return n + 2;
}
public static int product(int a, int b) {
    return a * b;
}
int result = product(addTwo(4), addTwo(addTwo(1)));
  1. 24
  2. 42
  3. 30
  4. 18
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Die Methode soll den ersten geraden Wert in einem Bereich einschließlich seiner Grenzen zurückgeben oder -1, falls keiner existiert. Für (9, 12) gibt sie fälschlich -1 zurück. Welche Änderung korrigiert die Suche?

public static int firstEven(int start, int end) {
    for (int n = start; n <= end; n++) {
        if (n % 2 == 0) {
            return n;
        } else {
            return -1;
        }
    }
    return -1;
}
  1. Entferne den else-Zweig und behalte das abschließende return.
  2. Ersetze das return im else-Zweig durch return n + 1;.
  3. Verschiebe das abschließende return in der Schleife hinter das if/else.
  4. Ändere die if-Bedingung zu n % 2 != 0.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Eine Hilfsmethode benötigt die Zahl, die in der lokalen Variablen pages von main steht. Wie sollen die Daten zur Hilfsmethode gelangen?
  1. Deklariere ein weiteres, nicht initialisiertes pages in der Hilfsmethode.
  2. Verschiebe die Hilfsmethode in der Klasse unter main.
  3. Setze den Aufruf der Hilfsmethode nur in den Gültigkeitsbereich von pages.
  4. Ergänze einen Parameter und übergib pages als Argument.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Welcher Wert wird von outer(4) an main zurückgegeben?

public static int outer(int n) {
    int saved = n;
    int changed = inner(n + 1);
    return saved + changed;
}
public static int inner(int n) {
    n *= 2;
    return n - 1;
}
  1. 14
  2. 13
  3. 19
  4. 9
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine Methode printBorder(int length, char symbol) mit zwei Argumenten enthält bereits die Ausgabeschleife. Wie soll printBorder(int length) ein vorgegebenes '#' bereitstellen, ohne die Schleife zu duplizieren?
  1. Rufe printBorder(length, '#'); in ihrem Rumpf auf.
  2. Ergänze char symbol = '#' als Standardparameter im Kopf.
  3. Rufe printBorder('#', length); in ihrem Rumpf auf.
  4. Rufe printBorder(length); in ihrem Rumpf auf.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Diese Überladungen stehen in derselben Klasse. Welcher Wert wird in answer gespeichert?

public static int adjust(int n) { return n + 1; }
public static double adjust(double n) { return n + 0.5; }
double answer = adjust(6);
  1. 6.5
  2. 6.0
  3. 7.5
  4. 7.0
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Zwei Codeblöcke berechnen Rechteckflächen, einer mit 8 * 3 und einer mit 11 * 4. Beide Ergebnisse werden für spätere Vergleiche benötigt. Welcher Kopf einer Hilfsmethode passt zur Extraktion dieser gemeinsamen Berechnung?
  1. public static void area(int width, int height)
  2. public static int area(int width)
  3. public static int area(int width, int height)
  4. public static int area()
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Was macht public static int countItems(int limit) { return 0; } zu einem nützlichen vorläufigen Stub?
  1. Er beweist, dass alle Stückzahlen korrekt sind.
  2. Er macht Tests der fertigen Methode überflüssig.
  3. Er lässt Aufrufe kompilieren, bevor der echte Rumpf fertig ist.
  4. Er liefert Java einen Standardwert für den Parameter.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 3: Verbinde Argumente, Rückgabepfade und Entwurf10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Ein Programmierer schreibt dies innerhalb einer Klasse. Warum wird die Definition der Hilfsmethode abgelehnt?

public static void main(String[] args) {
    public static void printTitle() {
        System.out.println("Schedule");
    }
}
  1. Eine Hilfsmethode muss über main stehen.
  2. Eine ausgebende Hilfsmethode muss einen String zurückgeben.
  3. Die Hilfsmethode ist innerhalb einer anderen Methode definiert.
  4. Der Name der Hilfsmethode muss groß beginnen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Die Methode gibt die Anzahl vollständiger Gruppen zurück. Was gibt groups(5, 18) zurück?

public static int groups(int groupSize, int items) {
    return items / groupSize;
}
  1. 3
  2. 0
  3. 3.6
  4. 4
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Eine Kalenderhilfsmethode ist wie unten geschrieben. Welches Ergebnispaar geben zuerst leap(2100) und dann leap(2400) zurück?

public static boolean leap(int year) {
    return (year % 4 == 0 && year % 100 != 0)
        || year % 400 == 0;
}
  1. true, dann true
  2. false, dann true
  3. false, dann false
  4. true, dann false
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Welchen Text gibt der Aufrufer aus?

public static void tag(String name) {
    name = name + "-checked";
}
String label = "parcel";
tag(label);
System.out.println(label);
  1. „parcel-checked“
  2. „checked“
  3. „parcelparcel“
  4. „parcel“
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Ein Fehlerbericht beginnt mit ArithmeticException: / by zero und diesen Rahmen. Wo trat die fehlgeschlagene Division auf?

at Main.unitCount(Main.java:23)
at Main.printLoad(Main.java:15)
at Main.main(Main.java:5)
  1. In main, in Zeile 5.
  2. In printLoad, in Zeile 15.
  3. In unitCount, in Zeile 23.
  4. Nach der Rückkehr von unitCount zu Zeile 15.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Eine Klasse deklariert public static void describe(String name, int count). Welcher Kopf fügt durch Änderung der Reihenfolge der Parametertypen eine gültige Überladung hinzu?
  1. public static int describe(String name, int count)
  2. public static void describe(int count, String name)
  3. public static void describe(String title, int number)
  4. private static void describe(String name, int count)
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Welche Zeile wird durch diesen Aufruf ausgegeben? Das Zeichen 'B' hat den numerischen Wert 66.

public static int code(int n) { return n + 1; }
public static String code(String s) { return s + "!"; }
double result = code('B');
System.out.println(result);
  1. 67.0
  2. 66.0
  3. „B!“
  4. 67
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Eine Hilfsmethode soll nur durch Code innerhalb derselben Klasse aufrufbar sein. Welchen Zugriffsmodifikator soll ihr statischer Kopf verwenden?
  1. public
  2. static
  3. void
  4. private
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Das ursprüngliche Programm gibt die Summen 20 und 30 in dieser Reihenfolge aus. Nach der Extraktion verwendet es diese Hilfsmethode. Wie sollen die beiden Aufrufe geschrieben werden, damit diese Summen erhalten bleiben?

public static int sumMultiples(int factor, int count) {
    int total = 0;
    for (int i = 1; i <= count; i++) {
        total += factor * i;
    }
    return total;
}

Die ursprüngliche erste Schleife addierte 2, 4, 6 und 8. Die zweite addierte 5, 10 und 15.

  1. sumMultiples(2, 4) dann sumMultiples(5, 3)
  2. sumMultiples(4, 2) dann sumMultiples(3, 5)
  3. sumMultiples(2, 8) dann sumMultiples(5, 15)
  4. sumMultiples(2, 3) dann sumMultiples(5, 2)
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein Programm liest fünf tägliche Anzahlen ein, addiert sie und gibt einen Durchschnitt aus. Die geplanten Köpfe der Hilfsmethoden stehen unten. Welche Verbindung in main ermöglicht es dem Berichtsschritt, alle benötigten Daten zu erhalten?

public static int readCount(Scanner scanner, int day)
public static double average(int total, int days)
public static void printReport(int total, int days)

Der Scanner wurde bereits erstellt.

  1. Überschreibe ein count in der Schleife; rufe printReport(count, 5) auf.
  2. Summiere die fünf zurückgegebenen Anzahlen; rufe printReport(total, 5) auf.
  3. Gib jede zurückgegebene Anzahl aus; rufe danach printReport(0, 5) auf.
  4. Addiere die Tagesnummern in der Schleife; rufe printReport(total, 5) auf.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 4: Untersuche vollständige Methodeninteraktionen10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Welche Zeile wird ausgegeben?

public static int next(int n) { return n + 1; }
public static double half(int n) { return n / 2.0; }
int n = 5;
next(n);
double result = half(next(n)) + n;
System.out.println(result);
  1. 9.5
  2. 7.5
  3. 3.0
  4. 8.0
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Welchen Wert gibt locate(5) zurück?

public static int locate(int limit) {
    int total = 0;
    for (int n = 1; n <= limit; n++) {
        total += n;
        if (total > 8) {
            return n;
        }
    }
    return -1;
}
  1. 4
  2. 5
  3. 10
  4. 15
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Der Code soll die Gewichte addieren und ihre Summe nach der Schleife ausgeben. Zurzeit lässt er sich nicht kompilieren. Welche Änderung behebt das Problem mit dem Gültigkeitsbereich und erhält zugleich eine laufende Summe?

for (int box = 1; box <= 3; box++) {
    int total = 0;
    total += box * 2;
}
System.out.println(total);
  1. Verschiebe nur println(total) in die Schleife.
  2. Deklariere int total; vor der Schleife und entferne die innere Deklaration.
  3. Verschiebe int total = 0; vor die Schleife und entferne die innere Deklaration.
  4. Deklariere int total = 0; nach der Schleife vor der Ausgabe.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Welches Wertepaar wird als a:b ausgegeben?

public static int shift(int n) {
    n += 4;
    return n;
}
int a = 2;
int b = shift(a);
a = shift(b);
System.out.println(a + ":" + b);
  1. 6:10
  2. 10:6
  3. 10:10
  4. 6:6
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Welche Werte haben an der markierten Stelle die beiden lokalen Variablen namens saved, zuerst im äußeren und dann im inneren Rahmen?

public static int outer(int n) {
    int saved = n + 2;
    return inner(saved) + saved;
}
public static int inner(int n) {
    int saved = n * 3;
    // program pauses here
    return saved;
}

main hat outer(5) aufgerufen.

  1. 7 und 21
  2. 21 und 21
  3. 5 und 15
  4. 7 und 7
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Programm startet fortlaufend weitere Aufrufe, ohne die bestehenden Aufrufe enden zu lassen. Welcher Fehler kann auftreten, wenn kein Platz mehr auf dem Stapel ist?
  1. ArithmeticException
  2. „missing return statement“
  3. „cannot find symbol“
  4. StackOverflowError
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Die folgenden Methoden sind in einer Klasse deklariert. Was geschieht bei double result = merge(4, 9);?

public static int merge(int a, double b) { return a; }
public static double merge(double a, int b) { return b; }
public static double merge(double a, double b) { return a + b; }
  1. Die double-Zielvariable wählt (double, int) und speichert 9.0.
  2. Der Aufruf ist zwischen den beiden Versionen mit gemischten Typen mehrdeutig.
  3. Das erste int-Argument wählt (int, double) und speichert 4.0.
  4. Die Version nur mit double wird gewählt und speichert 13.0.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Eine Sensorberechnung ist nützlich, aber ihre aktuelle Methode gibt auch eine lange Statusmeldung aus. Ein zweiter Aufrufer benötigt die Zahl ohne diese Meldung. Welcher Entwurf lässt beide Aufrufer eine Berechnungsmethode gemeinsam verwenden und ihre eigene Ausgabe wählen?
  1. Füge eine zweite Kopie der Berechnung ohne Ausgabe hinzu.
  2. Benenne die vorhandene Methode um, sodass sie beide Aktionen beschreibt.
  3. Gib die Zahl zurück und verschiebe die Ausgabe zum berichtenden Aufrufer.
  4. Mache die kombinierte Methode public, damit beide Aufrufer sie nutzen können.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Zwei Blöcke geben eine Beschriftung und danach eine Zeile pro Element aus. Der erste gibt "Crate" mit den Elementnummern 1 bis 2 aus; der zweite gibt "Bag" mit den Elementnummern 1 bis 4 aus. Welcher extrahierte Rumpf erhält dieses Format für printItems(String label, int count)?
  1. Gib label in einer Schleife ab 0 aus, solange i < count; gib keine Zahlen aus.
  2. Gib label einmal aus; durchlaufe ab 1 die Schleife, solange i < count, und gib i aus.
  3. Gib label einmal aus; durchlaufe ab 0 die Schleife, solange i <= count, und gib i aus.
  4. Gib label einmal aus; durchlaufe ab 1 die Schleife, solange i <= count, und gib i aus.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Eine Hilfsmethode soll einen Tagesdurchschnitt als Dezimalzahl zurückgeben:

public static double dailyAverage(int total, int days) {
    return total / days;
}

Warum deckt die Prüfung nur mit (24, 6) ihren Rechenfehler nicht auf?

  1. Die Division geht auf, sodass beim Abschneiden kein Nachkommateil verloren geht.
  2. Die Methode erweitert beide int-Operanden vor der Division.
  3. Diese Eingabe prüft einen Quotienten mit einem Nachkommateil ungleich null.
  4. Das Ergebnis wird danach auf die nächste ganze Zahl gerundet.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe

Schlüsselbegriffe

51 Schlüsselbegriffe, jeweils mit Definition

A

Akkumulator
Ein Akkumulator ist eine Variable, die ein laufendes Ergebnis speichert, während eine Schleife aufeinanderfolgende Werte zu diesem Ergebnis zusammenfasst.
Deklariere sum vor einer Schleife, damit jeder Durchlauf zu der aus dem vorherigen Durchlauf erhaltenen Summe addiert.
Argument
Ein Argument ist ein in einem Methodenaufruf übergebener Ausdruck, dessen ausgewerteter Wert an einen passenden Parameter übergeben wird.
In printRepeated("go", 4) liefern die Argumente den Text und die Anzahl der Wiederholungen.
Aufrufstapel
Der Aufrufstapel erfasst nicht abgeschlossene Methodenaufrufe, wobei der neueste Aufruf oben ausgeführt wird, während seine Aufrufer darunter warten.
Wenn main eine Hilfsmethode aufruft, die eine weitere Hilfsmethode aufruft, können drei Rahmen gleichzeitig auf dem Stapel liegen.

B

Block
Ein Block ist eine von geschweiften Klammern umschlossene Gruppe von Anweisungen, die einen Methodenrumpf, einen Schleifenrumpf oder einen bedingten Zweig bilden kann.
Wird ein Zähler innerhalb eines if-Blocks deklariert, bleibt dieser lokale Name innerhalb der schließenden Klammer des Blocks.
Boolesche Methode
Eine boolesche Methode gibt true oder false zurück, oft als Antwort auf eine Frage, die der Aufrufer direkt als Bedingung verwendet.
Ein Aufruf wie isEven(count) kann direkt innerhalb der Klammern einer if-Anweisung stehen.
Bottom-up-Entwicklung
Die Bottom-up-Entwicklung erstellt und testet zuerst kleine Methoden und kombiniert sie dann zu den größeren Schritten des Programms.
Teste eine Gültigkeitsprüfung und eine Formatierungsmethode getrennt, bevor du sie in einem vollständigen Berichtsprogramm verwendest.

C

Codeduplizierung
Codeduplizierung wiederholt dieselben oder nahezu dieselben Anweisungen, sodass bei einer Änderung der gemeinsamen Aufgabe mehrere Stellen aktualisiert werden müssen.
Zwei Summenschleifen mit unterschiedlichen oberen Grenzen lassen sich oft durch eine Hilfsmethode und zwei Aufrufe ersetzen.

D

Delegierende Methodenüberladung
Eine delegierende Methodenüberladung ruft eine andere Version derselben Operation auf und übergibt dabei oft einen festen Wert für ein ausgelassenes Argument.
Eine Methode zur Linienausgabe mit einem Argument kann die Version mit zwei Argumenten mit einem festen Bindestrich aufrufen.

E

Einengende Typumwandlung
Eine einengende Typumwandlung wandelt einen numerischen Wert in einen eingeschränkteren Typ um und kann dabei Informationen verlieren; bei Methodenaufrufen erfolgt sie nicht implizit.
Die Übergabe von 9.0 an einen int-Parameter schlägt ohne Cast fehl, obwohl der Wert keinen Nachkommateil hat.
Erweiternde Typumwandlung
Eine erweiternde Typumwandlung wandelt einen Wert in einen zulässigen größeren Typ um, sodass ein int-Argument zu einem double-Parameter passen kann.
Wird 12 an einen double-Parameter übergeben, erhält dieser 12.0, ohne dass ein expliziter Cast nötig ist.
Exakte Typübereinstimmung
Eine exakte Typübereinstimmung liegt vor, wenn die Argumenttypen bereits ohne Umwandlung zu den Parametertypen einer Methode passen.
Bei show(int) und show(double) stimmt show(9) exakt mit der int-Version überein.
Explizite Typumwandlung (Cast)
Eine explizite Typumwandlung wird mit einem Zieltyp in Klammern vor dem umzuwandelnden Ausdruck geschrieben.
Der Ausdruck (int) 4.9 liefert einem int-Parameter den Wert 4, indem er den Nachkommateil abschneidet.

G

Grenzwertfall
Ein Grenzwertfall prüft eine Eingabe an oder neben einem Grenzwert, an dem sich das erwartete Verhalten einer Methode ändert, und hilft so, Fehler an Endpunkten aufzudecken.
Prüfe für einen gültigen Bereich von 0 bis 1440 die Werte -1, 0, 1440 und 1441 als getrennte Eingaben.
Gültigkeitsbereich
Der Gültigkeitsbereich einer Variablen ist der Bereich des Programmtexts, in dem ihr Name zulässigerweise verwendet werden kann, um auf diese Variable zu verweisen.
Ein im Kopf einer for-Schleife deklarierter Zähler ist in dieser Schleife im Gültigkeitsbereich, kann aber danach nicht gelesen werden.

H

Hilfsmethode
Eine Hilfsmethode erfüllt eine kleinere Aufgabe, die von einer anderen Methode benötigt wird, und macht die größere Operation dadurch leichter lesbar und einfacher zu entwickeln.
Eine Berichtsmethode kann eine Formatierungsmethode für Dauern aufrufen, statt die Formatierung selbst auszuführen.

I

Initialisierung
Die Initialisierung gibt einer Variablen ihren Anfangswert, bevor späterer Code sie liest oder aktualisiert; lokale Variablen haben keinen automatischen Anfangswert.
Die Anweisung int total = 0; vor einer Summenschleife gibt der ersten Addition eine vorhandene Summe zur Aktualisierung.
Inkrementelle Entwicklung
Die inkrementelle Entwicklung ergänzt und prüft jeweils einen kleinen Teil funktionsfähigen Codes, sodass die Ursache eines neuen Fehlers leichter zu finden ist.
Implementiere eine Hilfsmethode, kompiliere sie, teste bekannte Ergebnisse und verbinde sie dann mit dem nächsten Teil.

J

Javadoc
Javadoc ist Dokumentation in einem /** ... */-Kommentar über einer Deklaration, mit Tags zur Beschreibung von Parametern und Ergebnissen.
Verwende @param minutes, um eine Eingabe zu erklären, und @return, um den erzeugten formatierten Text zu beschreiben.

L

LIFO-Prinzip
Das LIFO-Prinzip bezeichnet die Stapelreihenfolge, bei der der neueste nicht abgeschlossene Aufruf beendet wird, bevor sein wartender Aufrufer fortsetzt.
Eine innere Hilfsmethode kehrt zurück, bevor die äußere Hilfsmethode die Verwendung dieses Rückgabewerts beenden kann.
Lokale Variable
Eine lokale Variable wird innerhalb einer Methode oder eines Blocks deklariert und gehört zur Ausführung dieses Bereichs, nicht zum gesamten Programm.
Das lokale total einer Hilfsmethode ist von einer ebenfalls total genannten lokalen Variablen einer anderen Methode getrennt.

M

Mehrdeutiger Aufruf
Ein mehrdeutiger Aufruf passt zu mehreren Überladungen, ohne dass eine einzige am spezifischsten ist, sodass der Compiler keine auswählen kann.
Die Paare (int, double) und (double, int) machen einen Aufruf mit zwei int-Argumenten mehrdeutig.
Methode
Eine Methode ist ein benannter Block von Anweisungen, der eine Aufgabe erfüllt und immer dann ausgeführt wird, wenn die Programmausführung einen Aufruf dieser Methode erreicht.
Eine Methode printHeader() kann an mehreren Stellen eines Programms dieselbe Berichtsüberschrift ausgeben.
Methodenaufruf
Ein Methodenaufruf ist ein Ausdruck, der eine Methode benennt und ihre Argumente in Klammern übergibt, um ihren Rumpf auszuführen.
Die Anweisung printHeader(); führt die Methode zur Ausgabe der Überschrift an dieser Stelle beim Aufrufer aus.
Methodenextraktion
Die Methodenextraktion verschiebt einen zusammengehörigen Codeabschnitt in eine Hilfsmethode und macht veränderliche Eingaben zu Parametern sowie benötigte Ergebnisse zu Rückgabewerten.
Wird eine Summenschleife in sumUpTo(int n) extrahiert, bleibt der Aufrufer für seinen eigenen Berichtstext verantwortlich.
Methodenkopf
Ein Methodenkopf deklariert den Namen, die Modifikatoren, den Rückgabetyp und die Parameter einer Methode, bevor der Rumpf beginnt.
Der Kopf public static void greet() beschreibt eine aufrufbare Aktion ohne Eingabe und Rückgabewert.
Methodenrumpf
Ein Methodenrumpf ist der von geschweiften Klammern umschlossene Block, der die beim Aufruf der Methode ausgeführten Anweisungen enthält.
Der Aufruf führt in den Rumpf, dessen Anweisungen ausgeführt werden; danach wird beim wartenden Aufrufer fortgesetzt.
Methodensignatur
Eine Methodensignatur besteht bei diesen Methoden aus dem Namen und den Parametertypen in ihrer Reihenfolge; Rückgabetypen und Parameternamen unterscheiden sie nicht.
Das Umbenennen von width in w lässt area(int, int) unverändert und kann keine neue Überladung erzeugen.

P

Parameter
Ein Parameter ist eine mit einem Typ in einem Methodenkopf deklarierte Variable, die zu Beginn eines bestimmten Aufrufs einen Wert erhält.
In printRepeated(String text, int times) sind text und times die beiden deklarierten Parameter.
Parameterliste
Eine Parameterliste ist die geordnete Folge von Eingabevariablen mit Typ zwischen den Klammern eines Methodenkopfs.
Die Liste (int width, int height) erfordert zwei Argumente, die zuerst width und dann height zugeordnet werden.
Private Methode
Eine private Methode kann nur von Code in ihrer eigenen Klasse aufgerufen werden, sodass eine interne Hilfsmethode anderen Klassen nicht zur Verfügung steht.
Wird eine Berechnung als private static deklariert, kann ihre eigene Klasse sie verwenden, ohne einen externen Aufruf anzubieten.
Problemzerlegung
Die Problemzerlegung teilt das Problem eines Programms in kleinere sinnvolle Aufgaben auf, die jeweils als Methode mit klarer Aufgabe implementiert werden können.
Ein Bericht über eine Radtour kann das Einholen von Eingaben, die Berechnung einer Geschwindigkeit und die Anzeige des Ergebnisses trennen.

R

Refactoring
Refactoring ändert die Struktur von Code und erhält dabei sein Verhalten, etwa indem wiederholte Berechnungen durch Aufrufe ersetzt werden.
Vergleiche vor und nach der Extraktion dieselben Eingaben, um zu prüfen, ob sowohl Ergebnisse als auch Ausgabe gleich bleiben.
Referenz
Eine Referenz ist ein Wert, der auf ein Objekt verweist; durch Kopieren dieses Werts können zwei Variablen auf dasselbe Objekt verweisen.
Die Übergabe eines Strings kopiert seine Referenz in den Parameter, ohne die Zuweisungen an die beiden Variablen zu verbinden.
return-Anweisung
Eine return-Anweisung beendet den aktuellen Methodenaufruf und gibt bei einer Methode mit Rückgabewert einen Wert zurück, bei einer void-Methode keinen.
Die Anweisung return minutes * 60; beendet die Berechnung und liefert die Anzahl der Sekunden.
Rückgabetyp
Ein Rückgabetyp gibt den Typ des Werts an, den eine Methode ihrem Aufrufer liefert; void deklariert, dass sie keinen Wert liefert.
Eine als double average(int a, int b) deklarierte Methode verspricht ihrem Aufrufer ein double-Ergebnis.
Rückgabewert
Ein Rückgabewert ist das Ergebnis, das eine Methode an die Aufrufstelle zurückgibt, wo es gespeichert oder in einem anderen Ausdruck verwendet werden kann.
Nach int total = sum(6, 8); ist die zurückgegebene 14 in der Variablen total des Aufrufers gespeichert.

S

Sentinelwert
Ein Sentinelwert ist ein besonders vereinbartes Ergebnis, das einen Zustand signalisiert, etwa dass eine Suche keinen passenden Kandidaten gefunden hat.
Die Rückgabe von -1 nach einer Suche kann „nicht gefunden“ signalisieren, wenn -1 kein gültiger Treffer sein kann.
Stacktrace
Ein Stacktrace ist eine ausgegebene Liste aktiver Aufrufrahmen bei einem Fehler, die Methodennamen und Stellen in der Aufrufkette zeigt.
Der erste Rahmen zeigt die Fehlerstelle, und die Zeilen darunter zeigen, welche Methoden dorthin aufgerufen haben.
Stapelrahmen
Ein Stapelrahmen enthält die Parameter und lokalen Variablen eines Aufrufs sowie Informationen darüber, wo sein Aufrufer danach fortsetzen muss.
Zwei Aufrufe können jeweils einen Parameter namens minutes haben, weil die Parameter in getrennten Rahmen liegen.
Stapelüberlauf
Ein Stapelüberlauf tritt auf, wenn eine Kette von Methodenaufrufen mehr Stapelspeicher benötigt, als verfügbar ist, und führt zu StackOverflowError.
Aufrufe, die fortlaufend Rahmen hinzufügen, ohne sie enden zu lassen, können den Stapel schließlich erschöpfen.
Statische Methode
Eine statische Methode gehört zu einer Klasse und kann aufgerufen werden, ohne ein Objekt dieser Klasse zu erzeugen.
Der statische Aufruf Math.abs(-6) verwendet den Klassennamen Math und gibt den positiven Wert 6 zurück.
Stub
Ein Stub ist eine vorläufige Methode mit ihrem geplanten Kopf und einem minimalen Rumpf, die das Kompilieren des noch unvollständigen umgebenden Codes ermöglicht.
Ein vorläufiges return 0; kann als Platzhalter dienen, während die eigentliche Berechnung implementiert und geprüft wird.

T

Top-down-Entwurf
Der Top-down-Entwurf beginnt mit dem gesamten Problem und zerlegt dessen Schritte wiederholt in kleinere benannte Aufgaben oder Methodenaufrufe.
Plane in main die Aufrufe für Eingabe, Berechnung und Bericht, bevor du die Rümpfe ihrer Hilfsmethoden ausarbeitest.

U

Unerreichbare Anweisung
Eine unerreichbare Anweisung ist Code, von dem Java feststellt, dass er nicht ausgeführt werden kann, etwa eine Anweisung direkt nach return im selben Block.
Eine Ausgabe direkt nach einem unbedingten return im selben Block wird vom Compiler abgelehnt.
Unveränderlicher String
Ein unveränderlicher String ist ein String, dessen Inhalt sich nach seiner Erzeugung nicht ändern kann; Textoperationen können einen anderen String erzeugen.
Die Konkatenation von "!" und die Zuweisung des Ergebnisses an einen String-Parameter lassen die Referenz des Aufrufers unverändert.

Ü

Überladen
Überladen definiert Methoden mit demselben Namen und unterschiedlichen Parameterlisten, sodass eine Operation unterschiedliche Eingabeformen akzeptiert.
Zwei Methoden namens max können zwei und drei int-Werte akzeptieren und dabei eine Bedeutung für den Namen beibehalten.
Überladungsauflösung
Die Überladungsauflösung ist der Vorgang, bei dem der Compiler anhand der Anzahl und der Typen der Argumente eines Aufrufs eine passende Methodenversion auswählt.
Ein int-Argument wählt eine exakt passende int-Überladung vor einer Version, die eine Umwandlung benötigen würde.

V

Verschachtelter Aufruf
Ein verschachtelter Aufruf ist ein Methodenaufruf innerhalb eines anderen Aufrufs. Das Ergebnis des inneren Aufrufs muss vor der Ausführung der äußeren Methode ermittelt werden.
In Math.max(sum(2, 6), 5) wird das Ergebnis 8 zum ersten Argument von Math.max.
void
Das Java-Schlüsselwort void deklariert, dass eine Methode keinen Wert zurückgibt, selbst wenn ihr Rumpf Aktionen wie eine Ausgabe ausführt.
Ein void-Aufruf von printTotal kann nicht die rechte Seite einer int-Zuweisung füllen, nur weil er eine Zahl ausgibt.
Vorzeitige Rückkehr
Eine vorzeitige Rückkehr beendet eine Methode vor dem Ende ihres Rumpfs, häufig nachdem ein Treffer gefunden oder eine Eingabebedingung behandelt wurde.
Eine Suche endet, sobald return candidate; ausgeführt wird, selbst wenn die Schleife noch weitere Kandidaten hat.

W

Wertübergabe (Pass-by-Value)
Wertübergabe bedeutet, dass jeder Parameter eine Kopie des Werts seines Arguments erhält, sodass eine Neuzuweisung an den Parameter die Variable des Aufrufers unverändert lässt.
Eine Hilfsmethode kann ihren int-Parameter erhöhen, während der ursprüngliche int-Wert des Aufrufers unverändert bleibt.

Über diese Einheit

Von StudeliFehler melden

Erstelle deine eigenen Lernmaterialien

Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.

Jetzt starten