devolver un objeto vacío

113

¿Cuál es la forma correcta de devolver un Voidtipo, cuando no es un primitivo? P.ej. Actualmente uso null como se muestra a continuación.

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

class A implements B<Void>{

    public Void method(){
        // do something
        return null;
    }
}
Robert
fuente
1
Estoy escribiendo un intérprete para un formato de archivo, usando el patrón de intérprete, pero algunas expresiones no tienen valores de retorno
Robert
2
No hay forma de crear una instancia del tipo Void, por lo que si realmente tiene que devolver algo de ese tipo, null es su única opción. Sin embargo, probablemente no necesite el valor devuelto para nada, por lo que nulo debería estar bien.
Jorn
sí, esa era mi lógica también, solo me preguntaba si había una forma más semántica
Robert
1
Lo codificaría como tu ejemplo. Ese es un buen enfoque.
David Roussel

Respuestas:

134

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

Entonces, cualquiera de los siguientes sería suficiente:

  • parametrizar con Objecty devolver new Object()onull
  • parametrizar con Voidy regresarnull
  • parametrizar con uno NullObjecttuyo

No puede hacer este método voidy cualquier otra cosa devuelve algo . Dado que ese algo se ignora, puede devolver cualquier cosa.

Bozho
fuente
2
entonces, ¿cuál es la forma genéricamente correcta de lograr un tipo de retorno de vacío?
Robert
1
Si desea devolver null como vacío, debe lanzarlo en algunos casos: (Void) null
Patrick Favre
return (Void)null;
Alex R
¿Se puede (nulo) nulo diferenciarse de nulo de alguna manera?
Orangle
13

Java 8 ha introducido una nueva clase, Optional<T> , que se puede utilizar en tales casos. Para usarlo, modificaría ligeramente su código de la siguiente manera:

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

class A implements B<Void>{

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

Esto le permite asegurarse de obtener siempre un valor de retorno no nulo de su método, incluso cuando no hay nada que devolver. Eso es especialmente poderoso cuando se usa junto con herramientas que detectan cuándo se nullpuede o no se puede devolver, por ejemplo, el Eclipse @NonNully las @Nullableanotaciones.

Erick G. Hagstrom
fuente
5
Mi opinión es que esto va en la dirección equivocada. Es mejor devolver un tipo mucho más restringido que transmita el significado mucho más claro. Tener algo que devuelve un Optional<Void>es innecesario por la misma razón que usted da, siempre obtiene un Optional<Void>que está vacío y, por lo tanto, todos los demás métodos son inútiles. Esto es lo contrario de por qué debería usarse un valor opcional. Lo usa porque puede o no tener un valor. Además, el compilador no puede exigir que lo method()implemente correctamente. Esto sería un fracaso en tiempo de ejecución: return Optional.of(null).
steinybot
3

Si simplemente no necesita nada como su tipo, puede usar void. Esto se puede utilizar para implementar funciones o acciones. Entonces podrías hacer algo como esto:

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

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

    abstract void executeInternal();
}

O puede omitir la clase abstracta y hacer el retorno nulo en cada acción que no requiera un valor de retorno usted mismo.

Luego puede usar esas acciones como esta:

Dado un método

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

puedes llamarlo como

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

o, para la acción nula (tenga en cuenta que no está asignando el resultado a nada)

executeAction(new VoidAction() {
    @Override
    public void executeInternal() {
        //code here
    }
});
Jorn
fuente
2
¿En qué se diferencia esto de lo que ya tengo? todavía devuelve nulo, como sugerí
Robert
¿Por qué tendrías que devolver algo más? El punto que estoy tratando de hacer es que no necesita el valor de retorno, por lo que no importa lo que devuelva. Traté de aclarar eso con mi edición.
Jorn
1

Por el simple hecho de hacerlo, existe, por supuesto, la posibilidad de crear una Voidinstancia mediante la reflexión:

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.
        }
    }
}

Probablemente no haga eso en producción.

kap
fuente
0

No existe un tipo genérico que le diga al compilador que un método no devuelve nada.

Creo que la convención es usar Object cuando se hereda como parámetro de tipo

O

Propague el parámetro de tipo y luego permita que los usuarios de su clase creen una instancia usando Object y asignen el objeto a una variable escrita usando un tipo de comodín ?:

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
fuente
1
¿Es esta la convención para configurar el tipo de retorno como anulado con genéricos? ¿No me parece muy vacío?
Robert
Creo que este es el camino a seguir. Ningún usuario de la clase A<?>podrá hacer uso del valor devuelto de method().
Christopher Oezbek