Utilisations pour le type de référence Java Void?


163

Il existe un type de référence Java Void- V majuscule - . La seule situation que j'ai jamais vue utilisée est de paramétrer s Callable

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

Existe-t-il d'autres utilisations du Voidtype de référence Java ? Peut-on lui attribuer autre chose que null? Si oui, avez-vous des exemples?



Réponses:


116

Voidest devenue une convention pour un argument générique qui ne vous intéresse pas. Il n'y a aucune raison pour que vous utilisiez un autre type non instanciable, tel que System.

Il est également souvent utilisé dans les Mapvaleurs d' exemple (bien que les Collections.newSetFromMaputilisations en Booleantant que mappes ne doivent pas accepter de nullvaleurs) et java.security.PrivilegedAction.

J'ai écrit une entrée blog sur Voidquelques années en arrière.


qui a fait cette convention? l'état de la documentation docs.oracle.com/javase/tutorial/java/generics/types.html "Conventions de dénomination des paramètres de type Par convention, les noms de paramètres de type sont des lettres majuscules uniques."
barlop

4
@barlop C'est l'argument pas le nom du paramètre. Autrement dit, c'est le type java.lang.Void. / Josh Bloch a popularisé la convention, mais une fois que vous l'avez vue, c'est le choix évident.
Tom Hawtin - tackline

2
Cette entrée de blog est morte
mFeinstein

51

Vous pouvez créer une instance de Void en utilisant des réflexions, mais elles ne sont utiles pour rien. Void est un moyen d'indiquer qu'une méthode générique ne renvoie rien.

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

imprime quelque chose comme

I have a java.lang.Void@75636731

22
+1 pour instancier une classe qui, selon la documentation, n'est pas instanciable. J'ai fait cela aussi et je suis d'accord que les Voids instanciés sont inutiles.
Luke Woodward

1
Constructeur <Void> cv = Void.class.getDeclaredConstructor (); cv.setAccessible (vrai); Void v = cv.newInstance (); System.out.println (v); //;)
Peter Lawrey

Comme exercice, essayez de créer une nouvelle classe en utilisant des réflexions et voyez ce qui se passe.
Peter Lawrey

J'ai reçu une exception java.lang.InstantiationException de sun.reflect.InstantiationExceptionConstructorAccessorImpl. :(
Luke Woodward

7
Ceci est spécifique à la mise en œuvre et peut changer à tout moment. Il n'y a aucune garantie que la classe a un constructeur sans argument et même si elle en a un qui peut faire n'importe quoi (peut-être System.exit(0)). J'ai tendance à écrire des classes utilitaires avec un constructeur comme private Void() { throw new Error(); }. Certains peuvent préférer une énumération sans valeur.
Tom Hawtin - tackline


19

Étant donné qu'il n'y a pas de constructeurs publics , je dirais que rien d'autre ne peut lui être attribué null. Je ne l'ai utilisé que comme espace réservé pour "Je n'ai pas besoin d'utiliser ce paramètre générique", comme le montre votre exemple.

Il pourrait également être utilisé en réflexion, d'après ce que dit son Javadoc :

La classe Void est une classe d'espace réservé non instable pour contenir une référence à l'objet Class représentant le mot clé Java void.


Assez drôle pour voir Oracle / Sun le décrire de cette façon car nul est une instance de tous types. Quoi qu'il en soit, comme vous l'avez dit, la signification pure de celui-ci est "Je pourrais écrire n'importe quel type ici car cela ne m'intéresse pas, alors je vais mettre Void pour m'assurer que les gens qui lisent mon code comprennent exactement cela"
Snicolas

17

Toutes les classes d'emballage primitives ( Integer, Byte, Boolean, Double, etc.) contiennent une référence à la classe primitive correspondante dans un statique TYPEchamp, par exemple:

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

Voida été initialement créé comme un endroit pour mettre une référence au voidtype:

Void.TYPE == void.class

Cependant, vous ne gagnez vraiment rien à utiliser Void.TYPE. Lorsque vous utilisez, void.classil est beaucoup plus clair que vous faites quelque chose avec le voidtype.

En passant, la dernière fois que je l'ai essayé, BeanShell ne l'a pas reconnu void.class, vous devez donc l'utiliser Void.TYPE.


8
Il y a donc à la fois une Void.class et une void.class!
Tom Anderson

8

Lorsque vous utilisez le modèle de visiteur, il peut être plus simple d'utiliser Void au lieu d'Object lorsque vous voulez être sûr que la valeur de retour sera nulle

Exemple

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

   OUT visit(Leaf2 leaf);
}

Lorsque vous implémenterez votre visiteur, vous pouvez définir explicitement OUT pour être Void afin que vous sachiez que votre visiteur retournera toujours null, au lieu d'utiliser 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;
    }
}

5

Avant les génériques, il était créé pour l'API de réflexion, pour contenir TYPE renvoyé par Method.getReturnType () pour une méthode void, correspondant aux autres classes de type primitif.

EDIT: Du JavaDoc de Void: "La classe Void est une classe d'espace réservé non instable pour contenir une référence à l'objet Class représentant le mot clé Java void". Avant Generics, je suis conscient de toute utilité autre que la réflexion.


Je ne crois pas ça. Je n'ai pas de JVM 1.4 ou antérieure devant moi maintenant, mais je crois que Method.getReturnType () a toujours renvoyé void.class pour une méthode void.
Luke Woodward

@Pour: Je dis qu'avant les génériques, la seule utilisation dont je suis consciente est de tenir TYPE (comme dans Void.TYPE), qui était utilisé dans Method.getReturnType () de réflexion pour une méthode void.
Lawrence Dol

Il ne revient pas en quelque sorte Void. Veuillez consulter stackoverflow.com/questions/34248693/...
Alireza Fattahi

3

Comme vous ne pouvez pas instancier Void, vous pouvez utiliser l' objet Null Apache commons , donc

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

dans la première ligne, vous avez un objet, donc aNullObject != nulldétient, alors que dans la deuxième ligne il n'y a pas de référence, donc noObjectHere == nulldétient

Pour répondre à la question originale de l'affiche, il s'agit de faire la distinction entre «le rien» et «rien», qui sont des choses complètement différentes.

PS: Dites non au modèle d'objet nul


1

Void est créé pour envelopper son type de vide primitif. Chaque type primitif a son type de référence correspondant. Void est utilisé pour instancier une classe générique ou utiliser une méthode générique, Un argument générique qui ne vous intéresse pas. Et voici un exemple ...

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());
      }
    });
  } 

ici, comme vous pouvez le voir, je ne veux rien du serveur auquel je demande de créer de nouvelles inscriptions, mais public interface AsyncCallback<T> { .... }c'est une interface générique donc je fournis Void puisque les génériques n'acceptent pas les types primitifs


0

Il est également couramment utilisé sur les rappels d'achèvement Async-IO lorsque vous n'avez pas besoin d'un Attachmentobjet. Dans ce cas, vous spécifiez null à l'opération IO et implémentez CompletionHandler<Integer,Void>.


0

C'est peut-être un cas rare mais une fois, je l'ai utilisé Voiddans des classes d'aspect.

C'était un aspect qui s'exécute après les méthodes qui ont une @Logannotation, et enregistre la méthode retournée et quelques informations si le type de retour de méthode n'est pas void.

 @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
         }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.