zwracanie obiektu Void

113

Jaki jest prawidłowy sposób zwracania Voidtypu, jeśli nie jest to typ pierwotny? Na przykład. Obecnie używam null, jak poniżej.

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

class A implements B<Void>{

    public Void method(){
        // do something
        return null;
    }
}
Robert
źródło
1
piszę interpreter dla formatu pliku, używając wzorca interpretera, ale niektóre wyrażenia nie mają wartości zwracanych
Robert
2
Nie ma sposobu na utworzenie instancji typu Void, więc jeśli naprawdę musisz zwrócić coś tego typu, jedyną opcją jest null. Jednak prawdopodobnie nie potrzebujesz zwracanej wartości do niczego, więc wartość null powinna wystarczyć.
Jorn,
tak, to też była moja logika - po prostu zastanawiałem się, czy istnieje bardziej semantyczny sposób
Robert
1
Zakodowałbym to tak, jak twój przykład. To dobre podejście.
David Roussel,

Odpowiedzi:

134

Klasa Void jest nieinstanowalną klasą zastępczą, która zawiera odwołanie do obiektu Class reprezentującego słowo kluczowe void w języku Java.

Wystarczyłoby więc jedno z poniższych:

  • parametryzacja za pomocą Objecti zwracanie new Object()lubnull
  • parametryzacja Voidzi zwracanienull
  • parametryzacja z NullObjectTwoim

Nie możesz zrobić tej metody void, a cokolwiek innego coś zwraca . Ponieważ to coś jest ignorowane, możesz zwrócić wszystko.

Bozho
źródło
2
Jaki jest zatem ogólnie poprawny sposób uzyskania zwrotnego typu pustki?
Robert,
1
Jeśli chcesz zwrócić null jako void, musisz go rzucić w niektórych przypadkach: (Void) null
Patrick Favre
return (Void)null;
Alex R
czy (Void) null można w jakikolwiek sposób odróżnić od wartości null?
Orangle
13

Java 8 wprowadziła nową klasę Optional<T>, która może być używana w takich przypadkach. Aby z niego skorzystać, zmodyfikuj nieco swój kod w następujący sposób:

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

class A implements B<Void>{

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

Pozwala to upewnić się, że z metody zawsze zostanie zwrócona wartość niezerowa, nawet jeśli nie ma nic do zwrócenia. Jest to szczególnie przydatne w połączeniu z narzędziami, które wykrywają, kiedy nullmożna lub nie można zwrócić, np. Eclipse @NonNulli @Nullableadnotacje.

Erick G. Hagstrom
źródło
5
Uważam, że zmierza to w złym kierunku. Lepiej jest zwrócić znacznie bardziej ograniczony typ, który lepiej przekazuje znaczenie. Posiadanie czegoś, co zwraca an, Optional<Void>jest niepotrzebne z tego samego powodu, który podajesz, zawsze otrzymujesz Optional<Void>pustą, więc wszystkie inne metody są bezcelowe. Jest to przeciwieństwo tego, dlaczego należy używać wartości opcjonalnej. Używasz go, ponieważ może mieć wartość lub nie. Kompilator nie może również wymusić, że method()implementuje go poprawnie. To byłoby nie w czasie wykonywania: return Optional.of(null).
steinybot
3

Jeśli po prostu nie potrzebujesz niczego jako swojego typu, możesz użyć void. Można to wykorzystać do implementacji funkcji lub akcji. Możesz wtedy zrobić coś takiego:

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

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

    abstract void executeInternal();
}

Możesz też pominąć klasę abstrakcyjną i samodzielnie zwrócić wartość null w każdej akcji, która nie wymaga zwracania wartości.

Następnie możesz użyć tych akcji w następujący sposób:

Biorąc pod uwagę metodę

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

możesz to nazwać jak

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

lub, dla akcji void (pamiętaj, że nie przypisujesz wyniku do niczego)

executeAction(new VoidAction() {
    @Override
    public void executeInternal() {
        //code here
    }
});
Jorn
źródło
2
czym to się różni od tego, co już mam? nadal zwraca po prostu zero, tak jak zasugerowałem
Robert
Dlaczego miałbyś zwrócić cokolwiek innego? Chodzi mi o to, że nie potrzebujesz wartości zwracanej, więc nie ma znaczenia, co zwrócisz. Próbowałem to wyjaśnić w mojej edycji.
Jorn,
1

W tym celu istnieje oczywiście możliwość stworzenia Voidinstancji za pomocą refleksji:

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.
        }
    }
}

Prawdopodobnie nie zrobisz tego w produkcji.

kap
źródło
0

Nie ma typu ogólnego, który powie kompilatorowi, że metoda nic nie zwraca.

Uważam, że konwencja polega na używaniu Object podczas dziedziczenia jako parametru typu

LUB

Propaguj parametr typu w górę, a następnie pozwól użytkownikom Twojej klasy na tworzenie instancji przy użyciu Object i przypisywanie obiektu do zmiennej wpisanej przy użyciu symbolu wieloznacznego typu ?:

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
źródło
1
czy to jest konwencja ustawiania typu zwracanego na void w przypadku typów ogólnych - nie wygląda to dla mnie zbyt nieważne?
Robert,
Wierzę, że to jest droga. Żaden użytkownik class A<?>nie będzie mógł w żaden sposób wykorzystać zwróconej wartości method().
Christopher Oezbek,