Usos para o tipo de referência do Java Void?

163

Existe um tipo de referência Java Void- V maiúsculo . A única situação que eu já vi usada é parametrizar s Callable

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

Existem outros usos para o Voidtipo de referência Java ? Pode ser atribuído algo além de null? Se sim, você tem exemplos?

Julien Chastang
fonte

Respostas:

116

Voidtornou-se uma convenção para um argumento genérico no qual você não está interessado. Não há motivo para usar qualquer outro tipo não instável, como System.

Também é frequentemente usado em por exemplo Mapvalores (embora os Collections.newSetFromMapusos Booleancomo mapas não precisem aceitar nullvalores) e java.security.PrivilegedAction.

Eu escrevi um post do blog em Voidalguns anos atrás.

Tom Hawtin - linha de orientação
fonte
quem fez essa convenção? docs state docs.oracle.com/javase/tutorial/java/generics/types.html "Convenções de nomenclatura de parâmetro de tipo Por convenção, os nomes de parâmetro de tipo são letras maiúsculas e únicas".
barlop
4
@ barlop É o argumento, não o nome do parâmetro. Ou seja, é o tipo java.lang.Void. / Josh Bloch popularizou a convenção, embora uma vez que você a tenha visto, seja a escolha óbvia.
Tom Hawtin - defina
2
Essa entrada do blog está morta
mFeinstein 17/10
51

Você pode criar uma instância do Void usando reflexos, mas eles não são úteis para nada. Vazio é uma maneira de indicar que um método genérico não retorna 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
fonte
22
+1 para instanciar uma classe que a documentação diz ser instável. Também fiz isso e concordo que os vazios instanciados são inúteis.
22420 Luke Woodward
1
Construtor <Void> cv = Void.class.getDeclaredConstructor (); cv.setAccessible (true); Vazio v = cv.newInstance (); System.out.println (v); //;)
Peter Lawrey 14/03/2009
Como exercício, tente criar uma nova classe usando reflexões e veja o que acontece.
31540 Peter Lawrey
Eu recebi um java.lang.InstantiationException de sun.reflect.InstantiationExceptionConstructorAccessorImpl. :(
Luke Woodward
7
Isso é específico da implementação e pode mudar a qualquer momento. Não há garantia de que a classe tenha um construtor sem argumento e mesmo que tenha um que possa fazer alguma coisa (talvez System.exit(0)). Eu costumo escrever classes de utilidade com um construtor como private Void() { throw new Error(); }. Alguns podem preferir uma enumeração sem valor.
Tom Hawtin - defina
27

Future<Void>funciona como charme. :)

Alexander Temerev
fonte
6
É mais comum (por exemplo, no Guava) usar Future<?>, pois o futuro geralmente terá um valor legítimo (não- Voidtipo), mas é usado em um contexto que não se importa com o valor.
David Phillips
1
CompletableFuture<Void>funciona como um encanto também.
andrybak
19

Dado que não há construtores públicos , eu diria que não pode ser atribuído nada além de null. Eu apenas o usei como espaço reservado para "Não preciso usar esse parâmetro genérico", como mostra seu exemplo.

Também poderia ser usado na reflexão, pelo que diz o Javadoc :

A classe Void é uma classe de espaço reservado instável para manter uma referência ao objeto Class que representa a palavra-chave Java void.

Michael Myers
fonte
Engraçado o suficiente para ver o Oracle / Sun descrevê-lo dessa maneira, pois null é uma instância de todos os tipos. De qualquer forma, como você disse, o significado puro é "Eu poderia escrever qualquer tipo aqui, pois não estou interessado nela, então colocarei o Void para garantir que as pessoas que leem meu código entendam exatamente isso"
Snicolas
17

Todos os classe empacotadora ( Integer, Byte, Boolean, Double, etc.) conter uma referência para a classe correspondente primitiva em um estático TYPEcampo, por exemplo:

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

Voidfoi criado inicialmente como um local para colocar uma referência ao voidtipo:

Void.TYPE == void.class

No entanto, você realmente não ganha nada usando Void.TYPE. Quando você usa void.class, é muito mais claro que você está fazendo algo com o voidtipo.

Como um aparte, a última vez que tentei, o BeanShell não reconheceu void.class, então você precisa usá Void.TYPE-lo.

Luke Woodward
fonte
8
Portanto, há uma classe Void.class e uma void.class!
Tom Anderson
8

Quando você usa o padrão de visitante , pode ser mais limpo usar Void, em vez de Object, quando quiser ter certeza de que o valor de retorno será nulo.

Exemplo

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

   OUT visit(Leaf2 leaf);
}

Quando você implementa seu visitante, pode explicitamente definir OUT como nulo, para que saiba que seu visitante sempre retornará nulo, em vez de usar Objeto

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
fonte
5

Antes dos genéricos, ele era criado para a API de reflexão, para manter TYPE retornado por Method.getReturnType () para um método nulo, correspondente às outras classes de tipos primitivos.

EDIT: No JavaDoc do Void: "A classe Void é uma classe de espaço reservado instável para manter uma referência ao objeto Class que representa a palavra-chave Java void". Antes da Genéricos, não tenho outra utilidade além da reflexão.

Lawrence Dol
fonte
Eu não acredito nisso. Não tenho uma JVM 1.4 ou anterior agora, mas acredito que Method.getReturnType () sempre retornou void.class para um método void.
22420 Luke Woodward
@Pour: estou dizendo que, antes dos genéricos, o único uso que tenho conhecimento é manter TYPE (como no Void.TYPE), que foi usado no Method.getReturnType () da reflexão para um método nulo.
Lawrence Dol
De alguma forma, não retorna Void. Veja stackoverflow.com/questions/34248693/…
Alireza Fattahi
3

Como você não pode instanciar o Void, você pode usar o objeto nulo do Apache commons , então

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

na primeira linha, você tem um objeto, então aNullObject != nullmantém, enquanto na segunda linha não há referência, então noObjectHere == nullmantém

Para responder à pergunta original do pôster, o uso para isso é diferenciar entre "o nada" e "nada", que são coisas completamente diferentes.

PS: Diga não ao padrão de objeto nulo

Mar Bar
fonte
1

Vazio é criar para quebrar seu tipo de vazio primitivo. Todo tipo primitivo tem seu tipo de referência correspondente. O void é usado para instanciar uma classe genérica ou o uso de um método genérico. Argumentos genéricos nos quais você não está interessado. E aqui está um exemplo ...

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

aqui, como você pode ver, não quero nada do servidor que estou pedindo para criar um novo registro, mas public interface AsyncCallback<T> { .... }é uma interface genérica, então forneço o Void, pois os genéricos não aceitam tipos primitivos

Adelin
fonte
0

Também é comumente usado em retornos de chamada de conclusão de Async-IO quando você não precisa de um Attachmentobjeto. Nesse caso, você especifique nulo para a operação IO e implementar CompletionHandler<Integer,Void>.

eckes
fonte
0

Pode ser um caso raro, mas uma vez eu usei Voidnas classes de aspecto.

Esse era um aspecto que é executado após os métodos que possuem uma @Loganotação e registra o método retornado e algumas informações se o tipo de retorno do método não for 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
fonte