Zastosowania typu odwołania Java Void?

163

Jest Java Void- wielkie V-- rodzaj odniesienia . Jedyna sytuacja, jaką kiedykolwiek widziałem, to parametryzacja Callables

final Callable<Void> callable = new Callable<Void>() {
            public Void call() {
                foobar();
                return null;
            }
        };

Czy są jakieś inne zastosowania Voidtypu referencyjnego Java ? Czy kiedykolwiek można mu przypisać coś innego niż null? Jeśli tak, czy masz przykłady?

Julien Chastang
źródło

Odpowiedzi:

116

Voidstało się konwencją dla ogólnego argumentu, którym nie jesteś zainteresowany. Nie ma powodu, dla którego miałbyś używać innego typu, którego nie można utworzyć instancji, takiego jak System.

Jest również często używany na przykład w Mapwartościach (chociaż Collections.newSetFromMapużywa Booleanjako map nie musi akceptować nullwartości) i java.security.PrivilegedAction.

Napisałem wpis na bloguVoid kilka lat temu.

Tom Hawtin - haczyk
źródło
kto stworzył tę konwencję? the docs state docs.oracle.com/javase/tutorial/java/generics/types.html "Konwencje nazewnictwa parametrów typu Zgodnie z konwencją, nazwy parametrów typu są pojedynczymi dużymi literami."
barlop
4
@barlop To argument, a nie nazwa parametru. To znaczy, to jest typ java.lang.Void. / Josh Bloch spopularyzował konwencję, chociaż raz ją zobaczysz, jest to oczywisty wybór.
Tom Hawtin - tackline
2
Ten wpis na blogu jest martwy
mFeinstein
51

Możesz stworzyć instancję Void za pomocą odbić, ale nie są one przydatne do niczego. Void to sposób na wskazanie, że metoda ogólna nic nie zwraca.

Constructor<Void> constructor = Void.class.getDeclaredConstructor();
constructor.setAccessible(true);
Void v = constructor.newInstance();
System.out.println("I have a " + v);

drukuje coś w rodzaju

I have a java.lang.Void@75636731
Peter Lawrey
źródło
22
+1 za utworzenie instancji klasy, o której dokumentacja mówi, że jest niemożliwa do zainstalowania. Ja też to zrobiłem i zgadzam się, że instancyjne Pustki są bezużyteczne.
Luke Woodward
1
Konstruktor <Void> cv = Void.class.getDeclaredConstructor (); cv.setAccessible (true); Void v = cv.newInstance (); System.out.println (v); //;)
Peter Lawrey
W ramach ćwiczenia spróbuj utworzyć nową klasę za pomocą odbić i zobacz, co się stanie.
Peter Lawrey,
Dostałem java.lang.InstantiationException z sun.reflect.InstantiationExceptionConstructorAccessorImpl. :(
Luke Woodward
7
Jest to specyficzne dla implementacji i może ulec zmianie w dowolnym momencie. Nie ma gwarancji, że klasa ma konstruktora bezargumentowego, a nawet jeśli ma taki, który może zrobić cokolwiek (być może System.exit(0)). Mam tendencję do pisania klas użytkowych z konstruktorem jako private Void() { throw new Error(); }. Niektórzy mogą preferować wyliczenie bez wartości.
Tom Hawtin - tackline
27

Future<Void>działa jak urok. :)

Alexander Temerev
źródło
6
Jest to bardziej powszechne (na przykład w guawie) w użyciu Future<?>, ponieważ przyszłość często będzie miała uzasadnioną wartość (nietypową Void), ale jest używana w kontekście, który nie dba o wartość.
David Phillips
1
CompletableFuture<Void>działa również jak urok.
andrybak
19

Biorąc pod uwagę, że nie ma publicznych konstruktorów , powiedziałbym, że nie można mu przypisać niczego innego niż null. Użyłem go tylko jako symbolu zastępczego dla „Nie muszę używać tego ogólnego parametru”, jak pokazuje Twój przykład.

Można go również wykorzystać do refleksji, z tego, co mówi jego Javadoc :

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.

Michael Myers
źródło
Wystarczająco zabawne, że Oracle / Sun opisują to w ten sposób, że null jest instancją wszystkich typów. W każdym razie, jak powiedziałeś, jego czyste znaczenie brzmi: „Mogę napisać tutaj dowolny typ, ponieważ nie jestem nim zainteresowany, więc umieszczę Void, aby upewnić się, że ludzie, którzy czytają mój kod, dokładnie to rozumieją”
Snicolas
17

Wszystkie pierwotne klasy osłony ( Integer, Byte, Boolean, Double, itd.) Zawierają odniesienia do odpowiedniej grupy pierwotnej w statycznym TYPEpolu, na przykład:

Integer.TYPE == int.class
Byte.TYPE == byte.class
Boolean.TYPE == boolean.class
Double.TYPE == double.class

Voidzostał początkowo utworzony jako miejsce, w którym można umieścić odniesienie do voidtypu:

Void.TYPE == void.class

Jednak tak naprawdę nic nie zyskujesz, używając Void.TYPE. Kiedy używasz void.class, jest znacznie wyraźniejsze, że robisz coś z voidtypem.

Na marginesie, kiedy ostatnio go próbowałem, BeanShell nie rozpoznał void.class, więc musisz Void.TYPEtam użyć .

Luke Woodward
źródło
8
Mamy więc zarówno Void.class, jak i void.class!
Tom Anderson,
8

Kiedy używasz wzorca gościa , bardziej przejrzystym może być użycie Void zamiast Object, gdy chcesz mieć pewność, że zwracana wartość będzie zerowa

Przykład

public interface LeavesVisitor<OUT>
{
   OUT visit(Leaf1 leaf);

   OUT visit(Leaf2 leaf);
}

Kiedy zaimplementujesz swojego gościa, możesz jawnie ustawić OUT jako Void, abyś wiedział, że twój gość zawsze zwróci wartość null, zamiast używać Object

public class MyVoidVisitor implements LeavesVisitor<Void>
{
    Void visit(Leaf1 leaf){
        //...do what you want on your leaf
        return null;
    }

    Void visit(Leaf2 leaf){
        //...do what you want on your leaf
        return null;
    }
}
Ronan Quillevere
źródło
5

Przed typami generycznymi został utworzony dla interfejsu API odbicia, aby przechowywać TYPE zwracany przez Method.getReturnType () dla metody void, odpowiadającej innym klasom typów pierwotnych.

EDYCJA: Z JavaDoc of Void: „Klasa Void jest nieinstanowalną klasą zastępczą, która zawiera odniesienie do obiektu Class reprezentującego słowo kluczowe Java void”. Przed pojawieniem się Generics nie zdaję sobie sprawy z niczego innego niż refleksja.

Lawrence Dol
źródło
Nie wierzę w to. Nie mam teraz maszyny JVM w wersji 1.4 lub wcześniejszej, ale uważam, że metoda Method.getReturnType () zawsze zwracała void.class dla metody void.
Luke Woodward
@Pour: Mówię, że przed typami generycznymi jedynym zastosowaniem, o którym wiem, jest trzymanie TYPE (jak w Void.TYPE), który został użyty w Method.getReturnType () refleksji dla metody void.
Lawrence Dol,
Jakoś nie wraca Void. Zobacz stackoverflow.com/questions/34248693/…
Alireza Fattahi,
3

Ponieważ nie możesz utworzyć instancji Void, możesz użyć obiektu Apache commons Null , więc

Null aNullObject = ObjectUtils.Null;
Null noObjectHere = null;

w pierwszej linii masz obiekt, więc aNullObject != nulltrzyma się, podczas gdy w drugiej linii nie ma odniesienia, więc noObjectHere == nulltrzyma

Odpowiadając na pierwotne pytanie autora, celem tego jest odróżnienie „nic” od „niczego”, które są zupełnie różnymi rzeczami.

PS: Powiedz nie wzorowi obiektu o wartości Null

Mar Bar
źródło
1

Pustka jest tworzona, aby owinąć jej prymitywny typ pustki. Każdy typ pierwotny ma odpowiadający mu typ referencyjny. Void służy do tworzenia instancji klasy ogólnej lub użycia metody ogólnej, argumentów ogólnych, którymi nie jesteś zainteresowany. A oto przykład ...

public void onNewRegistration() {
    newRegistrationService.createNewUser(view.getUsername(), view.getPassword(),
            view.getInitialAmount(), view.getCurrency(), new AsyncCallback<Void>() {
      @Override
      public void onFailure(Throwable caught) {

      }

      @Override
      public void onSuccess(Void result) {
        eventBus.fireEvent(new NewRegistrationSuccessEvent());
      }
    });
  } 

tutaj, jak widzisz, nie chcę niczego od serwera, o który proszę, aby utworzyć nowe rejestracje, ale public interface AsyncCallback<T> { .... }jest to interfejs ogólny, więc udostępniam Void, ponieważ typy generyczne nie akceptują typów pierwotnych

Adelin
źródło
0

Jest również często używany w wywołaniach zwrotnych uzupełniania Async-IO, gdy nie potrzebujesz Attachmentobiektu. W takim przypadku określasz wartość null w operacji IO i implementujesz CompletionHandler<Integer,Void>.

eckes
źródło
0

Może to być rzadki przypadek, ale kiedyś użyłem Voidw klasach aspektów.

Był to aspekt, który działa po metodach, które mają @Logadnotację i rejestruje zwróconą metodę oraz pewne informacje, jeśli typ zwracanej metody nie jest nieważny.

 @AfterReturning(value = "@annotation(log)", 
       returning = "returnValue", 
       argNames = "joinPoint, log, returnValue"
      )
    public void afterReturning(final JoinPoint joinPoint, final Log log,
            final Object returnValue) {

            Class<?> returnType = ((MethodSignature) joinPoint.getSignature())
            .getReturnType();
           if (Void.class.isAssignableFrom (returnType)) ) {
            //Do some log
         }
}
Alireza Fattahi
źródło