CodeGym/Java-Blog/Germany/Das Schlüsselwort return in Java
Autor
Jesse Haniel
Lead Software Architect at Tribunal de Justiça da Paraíba

Das Schlüsselwort return in Java

Veröffentlicht in der Gruppe Germany
Wir wissen bereits, dass die Sprache Java eine objektorientierte Programmiersprache ist. Mit anderen Worten, das grundlegende Konzept, d.h. das Fundament dieser Sprache ist, dass alles ein Objekt ist. Objekte werden durch Klassen beschrieben. Klassen wiederum definieren Zustand und Verhalten. Ein Bankkonto kann z. B. einen Zustand in Form des Geldbetrags auf dem Konto haben und über Verhaltensweisen verfügen, die den Kontostand erhöhen und verringern. In Java werden Verhaltensweisen durch Methoden implementiert. Das Erlernen der Methodendefinition steht ganz am Anfang deines Java-Studiums. Zum Beispiel im offiziellen Tutorial von Oracle, unter der Überschrift „Defining Methods“. Hier gibt es zwei wichtige Dinge zu beachten:
  • Jede Methode besitzt eine Signatur. Die Signatur besteht aus dem Namen der Methode und ihren Eingabeparametern.
  • Für Methoden muss ein Rückgabetyp angegeben werden. Du deklarierst den Rückgabetyp einer Methode in ihrer Methodendeklaration.
Der Rückgabetyp ist nicht Teil der Methodensignatur. Auch dies ist eine Folge der Tatsache, dass Java eine stark typisierte Sprache ist und der Compiler möglichst im Voraus wissen will, welche Typen wo verwendet werden. Auch dies soll uns vor Fehlern bewahren. Im Grunde dient das alles einem guten Zweck. Und ich bin überzeugt, dass damit wieder eine Kultur des Umgangs mit Daten eingeübt wird. Also wird bei Methoden der Typ des Rückgabewerts angegeben. Und das Schlüsselwort return in Java wird verwendet, um die Rückgabe tatsächlich durchzuführen.

Was bewirkt return in Java (Java return)

Das Schlüsselwort return (return java) ist eine Kontrollflussanweisung, wie hier im Oracle-Tutorial beschrieben. Du kannst auch im Abschnitt „Returning a Value from a Method“ des offiziellen Tutorials nachlesen, wie man Werte zurückgibt. Der Compiler achtet sorgfältig darauf, ob er sicherstellen kann, dass der Rückgabewert einer Methode mit dem angegebenen Rückgabetyp der Methode übereinstimmt. Sehen wir uns ein Beispiel mit der Online-IDE von Tutorialspoint an. Schauen wir uns das Beispiel aller Beispiele an:
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
Wie wir sehen, wird hier die main-Methode ausgeführt, die den Einstiegspunkt des Programms darstellt. Die Codezeilen werden von oben nach unten ausgeführt. Unsere main-Methode kann keinen Wert zurückgeben. Wenn wir versuchen, dort einen Wert zurückzugeben, erhalten wir eine Fehlermeldung: „Error: Main method must return a value of type void“. Entsprechend gibt die Methode einfach etwas auf dem Bildschirm aus. Verschieben wir nun das String-Literal in eine eigene Methode zur Erzeugung der Nachricht:
public class HelloWorld {

    public static void main(String[] args) {
        System.out.println(getHelloMessage());
    }

    public static String getHelloMessage() {
        return "Hello World";
    }

}
Wir haben hier also das Schlüsselwort return verwendet, um den Rückgabewert anzugeben, den wir dann an die Methode println übergeben haben. Die Deklaration der Methode getHelloMessage zeigt an, dass die Methode einen Stringzurückgibt. Dadurch kann der Compiler prüfen, ob die Aktionen der Methode mit ihrer Deklaration übereinstimmen. Natürlich kann der in einer Methodendeklaration angegebene Rückgabetyp breiter sein als der Typ des tatsächlich im Code zurückgegebenen Wertes, d. h. entscheidend ist, dass eine Typkonvertierung möglich ist. Andernfalls erhalten wir zur Kompilierzeit einen Fehler: „Error: incompatible types“. Vielleicht stellst du dir jetzt eine Frage: Warum wird return als Kontrollflussanweisung betrachtet? Weil es den normalen Ablauf eines Programms von oben nach unten unterbrechen kann. Beispiel:
public class HelloWorld {

    public static void main(String[] args) {
        if (args.length == 0) {
            return;
        }
        for (String arg : args) {
            System.out.println(arg);
        }
    }

}
Wie du in diesem Beispiel siehst, unterbrechen wir die main-Methode im Java-Programm, wenn sie ohne Argumente aufgerufen wird. Du darfst nicht vergessen, dass Code nach einer return-Anweisung nicht mehr zugänglich ist. Unser intelligenter Compiler bemerkt dies und verhindert, dass du ein solches Programm ausführst. Zum Beispiel lässt sich dieser Code nicht kompilieren:
public static void main(String[] args) {
        System.out.println("1");
        return;
// we use output method after return statement, which is incorrect
        System.out.println("2");
 }
Es gibt einen schmutzigen Trick, um dies zu umgehen. Zum Beispiel zu Debugging-Zwecken oder aus einem anderen Grund. Der obige Code kann ausgeführt werden, indem die return-Anweisung in einen if-Block eingeschlossen wird:
if (2==2) {
    return;
}
Das Schlüsselwort return in Java - 1

return-Anweisung bei Fehlerbehandlung

Es gibt noch einen coolen Trick – wir können return in Verbindung mit der Fehlerbehandlung verwenden. Ich möchte gleich vorwegnehmen, dass die Verwendung einer return-Anweisung in einem Catch-Block wirklich sehr schlechter Stil ist, weshalb du das vermeiden solltest. Aber wir brauchen ein Beispiel, richtig? Hier ist es:
public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Value: " + getIntValue());
    }

    public static int getIntValue() {
        int value = 1;
        try {
            System.out.println("Something terrible happens");
            throw new Exception();
        } catch (Exception e) {
            System.out.println("Cached value: " + value);
            return value;
        } finally {
            value++;
            System.out.println("New value: " + value);
        }
    }

}
Auf den ersten Blick scheint es, dass 2 zurückgegeben werden sollte, da finally immer ausgeführt wird. Aber nein, der Rückgabewert wird 1 sein, und die Änderung der Variablen im finally-Block wird ignoriert. Nehmen wir außerdem an, dass value ein Objekt enthält und wir sagen value = null im finally-Block. Dann würde dieses Objekt, nicht null, im catch-Block zurückgegeben werden. Aber eine return-Anweisung würde im finally-Block korrekt funktionieren. Natürlich werden dir deine Kollegen für kleine Überraschungen mit return-Anweisungen nicht gerade dankbar sein. Wie auch das Zurückgeben von zwei Werten (return two values).

void.class

Und finally. Es gibt dieses seltsame Konstrukt, das man schreiben kann: void.class. Hmm. Warum und was bedeutet das? Es gibt tatsächlich verschiedene Frameworks und knifflige Fälle, bei denen die Java Reflection API sehr nützlich sein kann. Du kannst zum Beispiel prüfen, welchen Typ eine Methode zurückgibt:
import java.lang.reflect.Method;

public class HelloWorld {

    public void getVoidValue() {
    }

    public static void main(String[] args) {
        for (Method method : HelloWorld.class.getDeclaredMethods()) {
            System.out.println(method.getReturnType() == void.class);
        }
    }
}
Das kann in Testframeworks nützlich sein, wo du den eigentlichen Code in Methoden ersetzen musst. Dazu musst du aber verstehen, wie sich eine Methode verhält (d. h. welchen Typ sie zurückgibt). Es gibt noch eine zweite Möglichkeit, die main-Methode im obigen Code zu implementieren:
public static void main(String[] args) {
        for (Method method : HelloWorld.class.getDeclaredMethods()) {
            System.out.println(method.getReturnType() == Void.TYPE);
        }
 }
Auf Stack Overflow findest du eine interessante Diskussion über den Unterschied zwischen den beiden: Was ist der Unterschied zwischen java.lang.Void und void?
Kommentare
  • Beliebt
  • Neu
  • Alt
Du musst angemeldet sein, um einen Kommentar schreiben zu können
Auf dieser Seite gibt es noch keine Kommentare