¿Usos para el tipo de referencia de Java Void?

163

Hay un tipo de referencia Java Void- mayúscula V-- . La única situación que he visto que se usa es para parametrizar s Callable

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

¿Hay otros usos para el Voidtipo de referencia de Java ? ¿Se le puede asignar alguna otra cosa que no sea null? En caso afirmativo, ¿tienes ejemplos?

Julien Chastang
fuente

Respuestas:

116

Voidse ha convertido en una convención para un argumento genérico en el que no está interesado. No hay ninguna razón por la que deba usar ningún otro tipo no instanciable, como System.

También se usa a menudo en, por ejemplo, Mapvalores (aunque los Collections.newSetFromMapusos Booleancomo mapas no tienen que aceptar nullvalores) y java.security.PrivilegedAction.

Me escribió una entrada de blog en Voidunos pocos años atrás.

Tom Hawtin - tackline
fuente
¿Quién hizo esa convención? los documentos indican docs.oracle.com/javase/tutorial/java/generics/types.html "Convenciones de nomenclatura de parámetros de tipo Por convención, los nombres de parámetros de tipo son letras mayúsculas individuales".
barlop
44
@barlop Es el argumento, no el nombre del parámetro. Es decir, es el tipo java.lang.Void. / Josh Bloch popularizó la convención, aunque una vez que la haya visto, es la opción obvia.
Tom Hawtin - tackline
2
Esa entrada del blog está muerta
mFeinstein
51

Puede crear una instancia de Void usando reflejos, pero no son útiles para nada. Void es una forma de indicar que un método genérico no devuelve nada.

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

imprime algo como

I have a java.lang.Void@75636731
Peter Lawrey
fuente
22
+1 para crear instancias de una clase que la documentación dice que es desinstalable. También he hecho esto y estoy de acuerdo en que los vacíos instanciados son inútiles.
Luke Woodward
1
Constructor <Void> cv = Void.class.getDeclaredConstructor (); cv.setAccessible (verdadero); Nulo v = cv.newInstance (); System.out.println (v); //;)
Peter Lawrey
Como ejercicio, intente crear una nueva Clase usando reflexiones y vea qué sucede.
Peter Lawrey el
Obtuve una java.lang.InstantiationException de sun.reflect.InstantiationExceptionConstructorAccessorImpl. :(
Luke Woodward
77
Esto es específico de la implementación y puede cambiar en cualquier momento. No hay garantía de que la clase tenga un constructor sin argumentos e incluso si tiene uno que pueda hacer algo (tal vez System.exit(0)). Tiendo a escribir clases de utilidad con un constructor como private Void() { throw new Error(); }. Algunos pueden preferir una enumeración sin valor.
Tom Hawtin - tackline
27

Future<Void>Funciona como encanto. :)

Alexander Temerev
fuente
66
Es más común (por ejemplo, en Guava) usarlo Future<?>, ya que el futuro a menudo tendrá un valor legítimo (de no Voidtipo) pero se usa en un contexto que no le importa el valor.
David Phillips
1
CompletableFuture<Void>funciona como un encanto también.
andrybak
19

Dado que no hay constructores públicos , diría que no se le puede asignar otra cosa que no sea null. Solo lo he usado como marcador de posición para "No necesito usar este parámetro genérico", como muestra su ejemplo.

También podría usarse en la reflexión, por lo que dice su Javadoc :

La clase Void es una clase de marcador de posición desinstalable para contener una referencia al objeto Class que representa la palabra clave Java void.

Michael Myers
fuente
Lo suficientemente divertido como para ver a Oracle / Sun describirlo de esa manera, ya que nulo es una instancia de todo tipo. De todos modos, como dijiste, el significado puro es "podría escribir cualquier tipo aquí ya que no me interesa, así que pondré Void para asegurarme de que las personas que leen mi código entiendan exactamente eso"
Snicolas
17

Todas las clases de envoltura primitivas ( Integer, Byte, Boolean, Double, etc.) contienen una referencia a la clase primitiva correspondiente en una estática TYPEcampo, por ejemplo:

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

Voidinicialmente se creó como un lugar para poner una referencia al voidtipo:

Void.TYPE == void.class

Sin embargo, realmente no ganas nada con el uso Void.TYPE. Cuando usas void.classes mucho más claro que estás haciendo algo con el voidtipo.

Como comentario aparte, la última vez que lo probé, BeanShell no lo reconoció void.class, por lo que debes usarlo Void.TYPEallí.

Luke Woodward
fuente
8
¡Entonces hay una Void.class y una void.class!
Tom Anderson
8

Cuando usa el patrón de visitante , puede ser más limpio usar Void en lugar de Object cuando desea asegurarse de que el valor de retorno sea nulo

Ejemplo

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

   OUT visit(Leaf2 leaf);
}

Cuando implemente a su visitante, puede establecer explícitamente que OUT sea vacío para que sepa que su visitante siempre devolverá nulo, en lugar de usar 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
fuente
5

Antes de los genéricos, se creó para la API de reflexión, para contener TYPE devuelto por Method.getReturnType () para un método vacío, correspondiente a las otras clases de tipos primitivos.

EDITAR: Del JavaDoc de Void: "La clase Void es una clase de marcador de posición que no se puede desinstalar para contener una referencia al objeto Class que representa la palabra clave Java void". Antes de los genéricos, no soy consciente de otro uso que no sea la reflexión.

Lawrence Dol
fuente
No lo creo No tengo una JVM 1.4 o anterior frente a mí ahora, pero creo que Method.getReturnType () siempre ha devuelto void.class para un método void.
Luke Woodward el
@Pour: estoy diciendo que antes de los genéricos, el único uso que conozco es mantener TYPE (como en Void.TYPE), que se usó en el Method.getReturnType () de reflexión para un método vacío.
Lawrence Dol
De alguna manera no vuelve Void. Consulte stackoverflow.com/questions/34248693/…
Alireza Fattahi el
3

Como no puede crear una instancia de Void, puede usar el objeto nulo Apache commons , por lo que

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

en la primera línea, tiene un objeto, por lo que se aNullObject != nullmantiene, mientras que en la segunda línea no hay referencia, por lo que se noObjectHere == nullmantiene

Para responder a la pregunta original del cartel, el uso para esto es diferenciar entre "la nada" y "nada", que son cosas completamente diferentes.

PD: Di no al patrón de objeto nulo

Mar Bar
fuente
1

Void es create para envolver su tipo de vacío primitivo. Cada tipo primitivo tiene su tipo de referencia correspondiente. Void se usa para crear una instancia de una clase genérica o el uso de un método genérico, un argumento genérico que no le interesa. Y aquí hay un ejemplo ...

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

aquí, como puede ver, no quiero nada del servidor al que le pido que cree nuevos registros, pero public interface AsyncCallback<T> { .... }es una interfaz genérica, por lo que proporciono Void ya que los genéricos no aceptan tipos primitivos

Adelin
fuente
0

También se usa comúnmente en devoluciones de llamada de finalización de Async-IO cuando no tiene la necesidad de un Attachmentobjeto. En ese caso, especifique nulo para la operación e implementación de IO CompletionHandler<Integer,Void>.

Eckes
fuente
0

Puede ser un caso raro, pero una vez, lo usé Voiden clases de aspecto.

Este era un aspecto que se ejecuta después de los métodos que tienen una @Loganotación, y registra el método devuelto y alguna información si el tipo de retorno del método no es nulo.

 @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
fuente