Parameter & Rückgabewerte
Tiefer Einblick in Parameter und Rückgabewerte in Java: Pass-by-Value, varargs, mehrere Rückgabewerte und Best Practices.
Parameter & Rueckgabewerte
Im letzten Kapitel hast du die Grundlagen von Methoden gelernt. Jetzt tauchen wir tiefer ein: Wie funktionieren Parameter wirklich? Was passiert bei der Uebergabe? Und wie gibst du mehrere Werte zurueck?
Parameter im Detail
Parameter sind die Eingabewerte einer Methode. Sie werden beim Aufruf uebergeben:
// "name" und "alter" sind Parameter (formale Parameter)
static void begruesse(String name, int alter) {
System.out.printf("Hallo %s, du bist %d Jahre alt!%n", name, alter);
}
public static void main(String[] args) {
// "Max" und 25 sind Argumente (tatsaechliche Werte)
begruesse("Max", 25);
begruesse("Anna", 30);
}
Unterschied: Parameter vs. Argument
| Begriff | Bedeutung | Beispiel |
|---|---|---|
| Parameter | Variable in der Methodendefinition | String name |
| Argument | Wert beim Methodenaufruf | "Max" |
Pass-by-Value in Java
Java arbeitet immer mit Pass-by-Value. Das bedeutet: Die Methode bekommt eine Kopie des Werts.
Bei primitiven Typen
static void verdopple(int zahl) {
zahl = zahl * 2;
System.out.println("In der Methode: " + zahl); // 20
}
public static void main(String[] args) {
int x = 10;
verdopple(x);
System.out.println("Nach dem Aufruf: " + x); // 10 -- unveraendert!
}
Die Methode aendert nur ihre lokale Kopie — das Original bleibt gleich.
Bei Referenztypen
Bei Objekten wird die Referenz kopiert, nicht das Objekt selbst. Beide Referenzen zeigen auf dasselbe Objekt:
static void fuegeHinzu(List<String> liste, String element) {
liste.add(element); // Aendert das ORIGINALE Objekt!
}
public static void main(String[] args) {
var namen = new ArrayList<>(List.of("Max"));
fuegeHinzu(namen, "Anna");
System.out.println(namen); // [Max, Anna] -- veraendert!
}
Aber: Die Referenz selbst neu zuweisen hat keinen Effekt:
static void ersetze(List<String> liste) {
liste = new ArrayList<>(); // Aendert nur die lokale Kopie der Referenz!
liste.add("Neu");
}
public static void main(String[] args) {
var namen = new ArrayList<>(List.of("Max"));
ersetze(namen);
System.out.println(namen); // [Max] -- unveraendert!
}
Visualisierung
Primitive:
main: x = [10] --> verdopple: zahl = [10] (Kopie)
Referenz:
main: namen = [Ref] ──┐
├──> [Max, Anna] (gleiches Objekt!)
fuegeHinzu: liste = [Ref] ──┘
Mehrere Parameter
Du kannst beliebig viele Parameter verwenden:
static double berechnePreis(String produkt, double einzelpreis, int menge, double rabatt) {
var gesamt = einzelpreis * menge;
var rabattBetrag = gesamt * rabatt;
System.out.printf("%s: %.2f EUR (Rabatt: %.2f EUR)%n", produkt, gesamt - rabattBetrag, rabattBetrag);
return gesamt - rabattBetrag;
}
public static void main(String[] args) {
var preis = berechnePreis("Laptop", 999.99, 2, 0.10);
System.out.printf("Endpreis: %.2f EUR%n", preis);
}
Best Practice: Wenn eine Methode mehr als 3-4 Parameter hat, ueberlege, ob du sie in ein Objekt zusammenfassen kannst:
// Statt vieler Parameter:
// static void erstelleBenutzer(String name, String email, int alter, String stadt, String beruf)
// Besser: Record verwenden
record BenutzerDaten(String name, String email, int alter, String stadt, String beruf) {}
static void erstelleBenutzer(BenutzerDaten daten) {
System.out.println("Erstelle Benutzer: " + daten.name());
}
Varargs (Variable Argumente)
Mit ... kannst du eine variable Anzahl von Argumenten uebergeben:
static int summe(int... zahlen) {
var ergebnis = 0;
for (var zahl : zahlen) {
ergebnis += zahl;
}
return ergebnis;
}
public static void main(String[] args) {
System.out.println(summe(1, 2, 3)); // 6
System.out.println(summe(10, 20)); // 30
System.out.println(summe(1, 2, 3, 4, 5)); // 15
System.out.println(summe()); // 0
}
Regeln fuer Varargs:
- Varargs muss der letzte Parameter sein
- Es darf nur einen Varargs-Parameter pro Methode geben
- Intern wird Varargs als Array behandelt
// OK: Varargs als letzter Parameter
static String formatiere(String prefix, String... namen) {
return prefix + String.join(", ", namen);
}
// FEHLER: Varargs nicht am Ende
// static void falsch(String... namen, int alter) { }
Rueckgabewerte
Primitive Typen zurueckgeben
static int quadrat(int x) {
return x * x;
}
static boolean istPositiv(double zahl) {
return zahl > 0;
}
static char anfangsbuchstabe(String text) {
return text.charAt(0);
}
Objekte zurueckgeben
static String formatiereName(String vorname, String nachname) {
return nachname + ", " + vorname;
}
static List<Integer> geradeZahlen(int bis) {
var ergebnis = new ArrayList<Integer>();
for (int i = 2; i <= bis; i += 2) {
ergebnis.add(i);
}
return ergebnis;
}
Mehrere Werte zurueckgeben
Java kann nur einen Wert zurueckgeben. Fuer mehrere Werte gibt es mehrere Strategien:
Option 1: Record verwenden (empfohlen)
record MinMax(int min, int max) {}
static MinMax findeMinMax(int[] zahlen) {
var min = Integer.MAX_VALUE;
var max = Integer.MIN_VALUE;
for (var zahl : zahlen) {
if (zahl < min) min = zahl;
if (zahl > max) max = zahl;
}
return new MinMax(min, max);
}
public static void main(String[] args) {
var ergebnis = findeMinMax(new int[]{3, 7, 1, 9, 4});
System.out.println("Min: " + ergebnis.min()); // 1
System.out.println("Max: " + ergebnis.max()); // 9
}
Option 2: Array zurueckgeben
static int[] teile(int a, int b) {
return new int[]{a / b, a % b}; // [Quotient, Rest]
}
var ergebnis = teile(17, 5);
System.out.println("Quotient: " + ergebnis[0]); // 3
System.out.println("Rest: " + ergebnis[1]); // 2
Option 3: Map zurueckgeben
static Map<String, Object> analysiereText(String text) {
return Map.of(
"laenge", text.length(),
"woerter", text.split("\\s+").length,
"grossbuchstaben", text.chars().filter(Character::isUpperCase).count()
);
}
Methoden-Signatur
Die Signatur einer Methode besteht aus dem Namen und den Parametertypen:
// Verschiedene Signaturen:
static int addiere(int a, int b) { ... } // addiere(int, int)
static double addiere(double a, double b) { ... } // addiere(double, double)
static int addiere(int a, int b, int c) { ... } // addiere(int, int, int)
Der Rueckgabetyp ist NICHT Teil der Signatur:
// FEHLER: Gleiche Signatur!
// static int verdopple(int x) { return x * 2; }
// static double verdopple(int x) { return x * 2.0; } // Kompilierfehler!
Rekursion
Eine Methode kann sich selbst aufrufen — das nennt man Rekursion:
static int fakultaet(int n) {
if (n <= 1) return 1; // Basisfall
return n * fakultaet(n - 1); // Rekursiver Aufruf
}
System.out.println(fakultaet(5)); // 120 (5 * 4 * 3 * 2 * 1)
static int fibonacci(int n) {
if (n <= 0) return 0;
if (n == 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
for (int i = 0; i < 10; i++) {
System.out.print(fibonacci(i) + " ");
}
// 0 1 1 2 3 5 8 13 21 34
Achtung: Rekursion braucht immer einen Basisfall, sonst gibt es einen StackOverflowError!
Uebungen
Uebung 1: Mathematik-Bibliothek
Schreibe Methoden fuer: min(int a, int b), max(int a, int b), abs(int x), potenz(int basis, int exponent).
Uebung 2: Array-Helfer
Schreibe Methoden: durchschnitt(double... zahlen), enthaelt(int[] array, int wert), umkehren(int[] array).
Uebung 3: Text-Analyse
Schreibe eine Methode analysiere(String text), die einen Record mit Wortanzahl, Zeichenanzahl und laengstem Wort zurueckgibt.
Uebung 4: Rekursives Palindrom
Schreibe eine rekursive Methode istPalindrom(String text), die prueft, ob ein Text ein Palindrom ist.
Was kommt als Naechstes?
In der naechsten Lektion lernst du Methoden-Ueberladung (Overloading) — wie du mehrere Methoden mit dem gleichen Namen, aber verschiedenen Parametern erstellen kannst.
Zusammenfassung
- Java verwendet Pass-by-Value: Primitive werden kopiert, Referenzen werden kopiert (aber zeigen auf dasselbe Objekt)
- Varargs (
int... zahlen) erlauben eine variable Anzahl von Argumenten - Fuer mehrere Rueckgabewerte nutze Records oder Arrays
- Die Signatur besteht aus Name + Parametertypen (nicht Rueckgabetyp)
- Rekursion ist eine Methode, die sich selbst aufruft (braucht Basisfall!)
- Halte die Parameteranzahl klein (max. 3-4) — sonst nutze Records
Pro-Tipp: Records (seit Java 16) sind die eleganteste Loesung, um mehrere Werte aus einer Methode zurueckzugeben. Statt unuebersichtliche Arrays oder Maps zu nutzen, definiere einfach record Ergebnis(int wert, String text) {} — und du hast einen sauberen, typsicheren Container mit automatischen Gettern, equals() und toString()!