Usi per il tipo di riferimento Java Void?


163

Esiste un tipo di riferimentoVoid V maiuscolo Java . L'unica situazione che io abbia mai visto usato è parametrizzare s Callable

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

Ci sono altri usi per il Voidtipo di riferimento Java ? Può mai essere assegnato qualcosa di diverso da null? Se sì, hai degli esempi?



Risposte:


116

Voidè diventato una convenzione per un argomento generico che non ti interessa. Non vi è alcun motivo per cui dovresti usare qualsiasi altro tipo non istanziale, come System.

È anche spesso usato per esempio in Mapvalori (sebbene gli Collections.newSetFromMapusi Booleancome mappe non debbano accettare nullvalori) e java.security.PrivilegedAction.

Ho scritto una voce sul weblogVoid qualche anno fa.


chi ha fatto quella convention? the docs state docs.oracle.com/javase/tutorial/java/generics/types.html "Convenzioni di denominazione dei parametri di tipo Per convenzione, i nomi dei parametri di tipo sono lettere singole, maiuscole."
barlop

4
@barlop È l'argomento non il nome del parametro. Cioè, è il tipo java.lang.Void. / Josh Bloch ha reso popolare la convention, anche se una volta vista è la scelta più ovvia.
Tom Hawtin - tackline il

2
Quel post del blog è morto
mFeinstein il

51

Puoi creare un'istanza di Void usando le riflessioni, ma non sono utili a nulla. Void è un modo per indicare che un metodo generico non restituisce nulla.

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

stampa qualcosa di simile

I have a java.lang.Void@75636731

22
+1 per un'istanza di una classe che la documentazione afferma non è attendibile. L'ho fatto anche io e sono d'accordo che i vuoti istanziati sono inutili.
Luke Woodward,

1
Funzione di costruzione <Void> cv = Void.class.getDeclaredConstructor (); cv.setAccessible (true); Void v = cv.newInstance (); System.out.println (v); //;)
Peter Lawrey,

Come esercizio, prova a creare una nuova classe usando le riflessioni e guarda cosa succede.
Peter Lawrey,

Ho ottenuto un java.lang.InstantiationException da sun.reflect.InstantiationExceptionConstructorAccessorImpl. :(
Luke Woodward

7
Questo è specifico dell'implementazione e può cambiare in qualsiasi momento. Non c'è garanzia che la classe abbia un costruttore no-arg e anche se ne ha uno che può fare qualcosa (forse System.exit(0)). Tendo a scrivere classi di utilità con un costruttore come private Void() { throw new Error(); }. Alcuni potrebbero preferire un enum senza valore.
Tom Hawtin - affronta il


19

Dato che non ci sono costruttori pubblici , direi che non può essere assegnato altro null. L'ho usato solo come segnaposto per "Non ho bisogno di usare questo parametro generico", come mostra il tuo esempio.

Potrebbe anche essere usato in riflessione, da quello che dice il suo Javadoc :

La classe Void è una classe segnaposto non attendibile per contenere un riferimento all'oggetto Class che rappresenta il vuoto della parola chiave Java.


Abbastanza divertente da vedere Oracle / Sun descriverlo in questo modo come null è un'istanza di tutti i tipi. Comunque, come hai detto, il suo significato puro è "Potrei scrivere qualsiasi tipo qui perché non mi interessa, quindi metterò Void per assicurarmi che le persone che leggono il mio codice lo capiscano esattamente"
Snicolas

17

Tutte le classi wrapper primitive ( Integer, Byte, Boolean, Double, etc.) contengono un riferimento alla classe primitiva corrispondente statica TYPEcampo, ad esempio:

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

Voidè stato inizialmente creato come da qualche parte per mettere un riferimento al voidtipo:

Void.TYPE == void.class

Tuttavia, non guadagni davvero nulla usando Void.TYPE. Quando usi void.classè molto più chiaro che stai facendo qualcosa con il voidtipo.

A parte questo, l'ultima volta che l'ho provato, BeanShell non ha riconosciuto void.class, quindi devi usarlo Void.TYPE.


8
Quindi c'è sia un Void.class che un void.class!
Tom Anderson,

8

Quando si utilizza il modello visitatore , può essere più pulito utilizzare Void invece di Object quando si desidera essere sicuri che il valore restituito sia null

Esempio

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

   OUT visit(Leaf2 leaf);
}

Quando implementerai il tuo visitatore, puoi impostare esplicitamente OUT su Void in modo che tu sappia che il tuo visitatore restituirà sempre null, invece di usare 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

Prima dei generici, era stato creato per l'API di riflessione, per contenere TYPE restituito da Method.getReturnType () per un metodo void, corrispondente alle altre classi di tipi primitivi.

EDIT: Da JavaDoc di Void: "La classe Void è una classe segnaposto non attendibile per contenere un riferimento all'oggetto Class che rappresenta il vuoto della parola chiave Java". Prima di Generics, non sono a conoscenza di altro che della riflessione.


Non ci credo. Non ho una JVM 1.4 o precedente davanti a me ora, ma credo che Method.getReturnType () abbia sempre restituito void.class per un metodo void.
Luke Woodward,

@Pour: sto dicendo che prima dei generici, l'unico uso di cui sono a conoscenza è tenere TYPE (come in Void.TYPE), che è stato usato in Method.getReturnType () di reflection per un metodo void.
Lawrence Dol

In qualche modo non ritorna Void. Si prega di consultare stackoverflow.com/questions/34248693/...
Alireza Fattahi

3

Poiché non è possibile creare un'istanza di Void, è possibile utilizzare l' oggetto Null commons di Apache , quindi

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

nella prima riga hai un oggetto, quindi aNullObject != nulldetiene, mentre nella seconda riga non vi è alcun riferimento, quindi noObjectHere == nulldetiene

Per rispondere alla domanda originale del poster, l'uso per questo è di distinguere tra "il nulla" e "niente", che sono cose completamente diverse.

PS: Di 'di no al modello di oggetti Null


1

Void è creato per avvolgere il suo tipo di vuoto primitivo. Ogni tipo primitivo ha il suo tipo di riferimento corrispondente. Void viene utilizzato per creare un'istanza di una classe generica o l'uso di un metodo generico, Argomenti generici che non ti interessano. Ecco un esempio ...

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

qui, come puoi vedere, non voglio nulla dal server che sto chiedendo di creare una nuova registrazione, ma public interface AsyncCallback<T> { .... }è un'interfaccia generica, quindi fornisco il Vuoto poiché i generici non accettano tipi primitivi


0

Viene anche comunemente utilizzato sui callback di completamento Async-IO quando non si ha la necessità di un Attachmentoggetto. In tal caso si specifica null per l'operazione IO e l'implementazione CompletionHandler<Integer,Void>.


0

Può essere un caso raro ma una volta l'ho usato Voidnelle classi di aspetto.

Questo era un aspetto che viene eseguito dopo i metodi che hanno @Logun'annotazione e registra il metodo restituito e alcune informazioni se il tipo restituito dal metodo non è nullo.

 @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
         }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.