Rückgabe eines Void-Objekts

113

Was ist der richtige Weg, um einen VoidTyp zurückzugeben, wenn er kein Grundelement ist? Z.B. Ich benutze derzeit null wie unten.

interface B<E>{ E method(); }

class A implements B<Void>{

    public Void method(){
        // do something
        return null;
    }
}
Robert
quelle
1
Ich schreibe einen Interpreter für ein Dateiformat unter Verwendung des Interpreter-Musters, aber einige Ausdrücke haben keine Rückgabewerte
Robert
2
Es gibt keine Möglichkeit, den Void-Typ zu instanziieren. Wenn Sie also wirklich etwas von diesem Typ zurückgeben müssen, ist null Ihre einzige Option. Wahrscheinlich benötigen Sie den zurückgegebenen Wert jedoch für nichts, daher sollte null in Ordnung sein.
Jorn
Ja, das war auch meine Logik - ich habe mich nur gefragt, ob es einen semantischeren Weg gibt
Robert
1
Ich würde es genau wie Ihr Beispiel codieren. Das ist ein guter Ansatz.
David Roussel

Antworten:

134

Die Void-Klasse ist eine nicht instabilisierbare Platzhalterklasse, die einen Verweis auf das Class-Objekt enthält, das das Java-Schlüsselwort void darstellt.

Folgendes würde also ausreichen:

  • parametrieren mit Objectund zurückgeben new Object()odernull
  • Parametrieren mit Voidund Zurückgebennull
  • Parametrieren mit einem NullObjectvon Ihnen

Sie können diese Methode nicht ausführen void, und alles andere gibt etwas zurück . Da dieses Etwas ignoriert wird, können Sie alles zurückgeben.

Bozho
quelle
2
Was ist dann der allgemein korrekte Weg, um einen Rückgabetyp von Leere zu erreichen?
Robert
1
Wenn Sie null als ungültig zurückgeben möchten, müssen Sie es in einigen Fällen umwandeln: (Void) null
Patrick Favre
return (Void)null;
Alex R
Kann (Void) null in irgendeiner Weise von null unterschieden werden?
Orangle
13

Java 8 hat eine neue Klasse eingeführt, Optional<T>die in solchen Fällen verwendet werden kann. Um es zu verwenden, würden Sie Ihren Code wie folgt leicht ändern:

interface B<E>{ Optional<E> method(); }

class A implements B<Void>{

    public Optional<Void> method(){
        // do something
        return Optional.empty();
    }
}

Auf diese Weise können Sie sicherstellen, dass Ihre Methode immer einen Rückgabewert ungleich Null erhält, auch wenn nichts zurückgegeben werden muss. Dies ist besonders leistungsfähig, wenn es in Verbindung mit Tools verwendet wird, die erkennen, wann zurückgegeben werden nullkann oder nicht, z. B. Eclipse @NonNullund @NullableAnmerkungen.

Erick G. Hagstrom
quelle
5
Meiner Meinung nach geht das in die falsche Richtung. Es ist besser, einen viel eingeschränkteren Typ zurückzugeben, der die Bedeutung viel klarer vermittelt. Etwas zu haben, das ein zurückgibt, Optional<Void>ist aus dem gleichen Grund, den Sie angeben, nicht erforderlich. Sie erhalten immer ein Optional<Void>, das leer ist, und daher sind alle anderen Methoden sinnlos. Dies ist das Gegenteil davon, warum ein optionaler Wert verwendet werden sollte. Sie verwenden es, weil es einen Wert haben kann oder nicht. Außerdem kann der Compiler nicht erzwingen, dass method()er korrekt implementiert wird. Dies würde zur Laufzeit fehlschlagen : return Optional.of(null).
Steinybot
3

Wenn Sie einfach nichts als Typ benötigen, können Sie void verwenden. Dies kann zum Implementieren von Funktionen oder Aktionen verwendet werden. Sie könnten dann so etwas tun:

interface Action<T> {
    public T execute();
}

abstract class VoidAction implements Action<Void> {
    public Void execute() {
        executeInternal();
        return null;
    }

    abstract void executeInternal();
}

Oder Sie können die abstrakte Klasse weglassen und die Rückgabe null in jeder Aktion ausführen, für die selbst kein Rückgabewert erforderlich ist.

Sie können diese Aktionen dann folgendermaßen verwenden:

Eine Methode gegeben

private static <T> T executeAction(Action<T> action) {
    return action.execute();
}

man kann es so nennen

String result = executeAction(new Action<String>() {
    @Override
    public String execute() {
        //code here
        return "Return me!";
    }
});

oder für die void-Aktion (beachten Sie, dass Sie das Ergebnis nichts zuweisen)

executeAction(new VoidAction() {
    @Override
    public void executeInternal() {
        //code here
    }
});
Jorn
quelle
2
Wie unterscheidet sich das von dem, was ich bereits habe? es gibt immer noch nur null zurück, wie ich vorgeschlagen habe
Robert
Warum müssten Sie etwas anderes zurückgeben? Der Punkt, den ich versuche, ist, dass Sie den Rückgabewert nicht benötigen, also spielt es keine Rolle, was Sie zurückgeben. Ich habe versucht, das mit meiner Bearbeitung zu klären.
Jorn
1

Nur deswegen gibt es natürlich die Möglichkeit, eine VoidInstanz mithilfe von Reflexion zu erstellen :

interface B<E>{ E method(); }

class A implements B<Void>{

    public Void method(){
        // do something

        try {
            Constructor<Void> voidConstructor = Void.class.getDeclaredConstructor();
            voidConstructor.setAccessible(true);
            return voidConstructor.newInstance();
        } catch (Exception ex) {
            // Rethrow, or return null, or whatever.
        }
    }
}

Das werden Sie in der Produktion wahrscheinlich nicht tun.

kap
quelle
0

Es gibt keinen generischen Typ, der dem Compiler mitteilt, dass eine Methode nichts zurückgibt.

Ich glaube, die Konvention besteht darin, Object beim Erben als Typparameter zu verwenden

ODER

Verbreiten Sie den Typparameter nach oben und lassen Sie die Benutzer Ihrer Klasse mithilfe von Object instanziieren und das Objekt einer Variablen zuweisen, die mit einem Typ-Platzhalter eingegeben wurde ?:

interface B<E>{ E method(); }

class A<T> implements B<T>{

    public T method(){
        // do something
        return null;
    }
}

A<?> a = new A<Object>();
Christopher Oezbek
quelle
1
Ist dies die Konvention, um den Rückgabetyp mit Generika auf ungültig zu setzen - es sieht für mich nicht sehr ungültig aus?
Robert
Ich glaube, das ist der richtige Weg. Jeder Benutzer der Klasse A<?>kann den zurückgegebenen Wert von nicht verwenden method().
Christopher Oezbek