retornando um objeto vazio

113

Qual é a maneira correta de retornar um Voidtipo, quando não é um primitivo? Por exemplo. Atualmente, uso null como abaixo.

interface B<E>{ E method(); }

class A implements B<Void>{

    public Void method(){
        // do something
        return null;
    }
}
Robert
fonte
1
estou escrevendo um interpretador para um formato de arquivo, usando o padrão do interpretador, mas algumas expressões não têm valores de retorno
Robert,
2
Não há como instanciar o tipo Void, então se você realmente precisar retornar algo desse tipo, null é sua única opção. No entanto, você provavelmente não precisa do valor retornado para nada, então null deve ser suficiente.
Jorn,
sim, essa era a minha lógica também - só me perguntei se havia uma maneira mais semântica
Robert,
1
Gostaria de codificá-lo exatamente como seu exemplo. Essa é uma boa abordagem.
David Roussel,

Respostas:

134

A classe Void é uma classe de espaço reservado que não pode ser instanciada para conter uma referência ao objeto Class que representa a palavra-chave Java void.

Portanto, qualquer uma das opções a seguir seria suficiente:

  • parametrizando com Objecte retornando new Object()ounull
  • parametrizando com Voide retornandonull
  • parametrizando com um NullObjectseu

Você não pode fazer este método voide qualquer outra coisa retorna algo . Como esse algo é ignorado, você pode retornar qualquer coisa.

Bozho
fonte
2
então, qual é a maneira genericamente correta de obter um tipo de retorno de vazio?
Robert,
1
Se você quiser retornar null como void, você precisa lançá-lo em alguns casos: (Void) null
Patrick Favre
return (Void)null;
Alex R
pode (void) null ser diferenciado de null de alguma forma?
Orangle
13

Java 8 introduziu uma nova classe,, Optional<T>que pode ser usada em tais casos. Para usá-lo, você modificaria seu código ligeiramente da seguinte maneira:

interface B<E>{ Optional<E> method(); }

class A implements B<Void>{

    public Optional<Void> method(){
        // do something
        return Optional.empty();
    }
}

Isso permite que você garanta que sempre obterá um valor de retorno não nulo de seu método, mesmo quando não houver nada para retornar. Isso é especialmente poderoso quando usado em conjunto com ferramentas que detectam quando nullpode ou não pode ser retornado, por exemplo, o Eclipse @NonNulle @Nullableanotações.

Erick G. Hagstrom
fonte
5
Minha opinião é que isso vai na direção errada. É melhor retornar um tipo muito mais restrito que transmita o significado muito mais claro. Ter algo que retorna um Optional<Void>é desnecessário pelo mesmo motivo que você forneceu, você sempre obtém um Optional<Void>que está vazio e, portanto, todos os outros métodos são inúteis. Isso é o oposto do motivo pelo qual um valor opcional deve ser usado. Você o usa porque pode ou não ter um valor. Além disso, o compilador não pode impor que o method()implemente corretamente. Este seria um fracasso em tempo de execução: return Optional.of(null).
steinybot,
3

Se você simplesmente não precisa de nada como seu tipo, pode usar void. Isso pode ser usado para implementar funções ou ações. Você poderia então fazer algo assim:

interface Action<T> {
    public T execute();
}

abstract class VoidAction implements Action<Void> {
    public Void execute() {
        executeInternal();
        return null;
    }

    abstract void executeInternal();
}

Ou você pode omitir a classe abstrata e retornar null em todas as ações que não exigem um valor de retorno.

Você pode então usar essas ações como esta:

Dado um método

private static <T> T executeAction(Action<T> action) {
    return action.execute();
}

você pode chamá-lo assim

String result = executeAction(new Action<String>() {
    @Override
    public String execute() {
        //code here
        return "Return me!";
    }
});

ou, para a ação anular (observe que você não está atribuindo o resultado a nada)

executeAction(new VoidAction() {
    @Override
    public void executeInternal() {
        //code here
    }
});
Jorn
fonte
2
como isso é diferente do que eu já tenho? ele ainda retorna nulo, como sugeri
Robert,
Por que você teria que devolver mais alguma coisa? O que estou tentando mostrar é que você não precisa do valor de retorno, portanto, não importa o que você retorne. Tentei esclarecer isso com minha edição.
Jorn
1

Só por causa disso, é claro que existe a possibilidade de criar Voidinstância usando reflexão:

interface B<E>{ E method(); }

class A implements B<Void>{

    public Void method(){
        // do something

        try {
            Constructor<Void> voidConstructor = Void.class.getDeclaredConstructor();
            voidConstructor.setAccessible(true);
            return voidConstructor.newInstance();
        } catch (Exception ex) {
            // Rethrow, or return null, or whatever.
        }
    }
}

Você provavelmente não fará isso na produção.

kap
fonte
0

Não existe um tipo genérico que diga ao compilador que um método não retorna nada.

Acredito que a convenção é usar Object ao herdar como um parâmetro de tipo

OU

Propague o parâmetro de tipo e deixe os usuários de sua classe instanciarem usando Object e atribuindo o objeto a uma variável digitada usando um caractere curinga ?:

interface B<E>{ E method(); }

class A<T> implements B<T>{

    public T method(){
        // do something
        return null;
    }
}

A<?> a = new A<Object>();
Christopher Oezbek
fonte
1
esta é a convenção para definir o tipo de retorno como nulo com genéricos - não parece muito nulo para mim?
Robert,
Eu acredito que este é o caminho a percorrer. Qualquer usuário da classe A<?>não poderá fazer uso do valor retornado de method().
Christopher Oezbek,