renvoyer un objet Void

113

Quelle est la manière correcte de renvoyer un Voidtype, quand ce n'est pas une primitive? Par exemple. J'utilise actuellement null comme ci-dessous.

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

class A implements B<Void>{

    public Void method(){
        // do something
        return null;
    }
}
Robert
la source
1
J'écris un interpréteur pour un format de fichier, en utilisant le modèle d'interprétation, mais certaines expressions n'ont pas de valeurs de retour
Robert
2
Il n'y a aucun moyen d'instancier le type Void, donc si vous devez vraiment retourner quelque chose de ce type, null est votre seule option. Cependant, vous n'avez probablement pas besoin de la valeur renvoyée pour quoi que ce soit, donc null devrait convenir.
Jorn
oui, c'était aussi ma logique - je me demandais simplement s'il y avait une manière plus sémantique
Robert
1
Je le coderais comme votre exemple. C'est une bonne approche.
David Roussel

Réponses:

134

La classe Void est une classe d'espace réservé non instable pour contenir une référence à l'objet Class représentant le mot clé Java void.

Donc, l'une des choses suivantes suffirait:

  • paramétrage avec Objectet retour new Object()ounull
  • paramétrage avec Voidet retournull
  • paramétrage avec l'un NullObjectde vos

Vous ne pouvez pas utiliser cette méthode void, et tout le reste renvoie quelque chose . Puisque ce quelque chose est ignoré, vous pouvez renvoyer n'importe quoi.

Bozho
la source
2
alors quelle est la manière génériquement correcte de réaliser un type de retour de vide?
Robert
1
Si vous voulez renvoyer null comme nul, vous devez le caster dans certains cas: (Void) null
Patrick Favre
return (Void)null;
Alex R
(Void) null peut-il être différencié de null d'une manière ou d'une autre?
Orangle le
13

Java 8 a introduit une nouvelle classe Optional<T>, qui peut être utilisée dans de tels cas. Pour l'utiliser, vous modifierez légèrement votre code comme suit:

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

class A implements B<Void>{

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

Cela vous permet de vous assurer que vous toujours obtenez une valeur de retour non nulle de votre méthode, même s'il n'y a rien à retourner. C'est particulièrement puissant lorsqu'il est utilisé en conjonction avec des outils qui détectent quand nullpeut ou ne peut pas être retourné, par exemple l'Eclipse @NonNullet les @Nullableannotations.

Erick G. Hagstrom
la source
5
Mon opinion est que cela va dans la mauvaise direction. Il est préférable de renvoyer un type beaucoup plus contraint qui transmet le sens beaucoup plus clair. Avoir quelque chose qui renvoie un Optional<Void>n'est pas nécessaire pour la même raison que vous donnez, vous obtenez toujours un Optional<Void>qui est vide et donc toutes les autres méthodes sont inutiles. C'est le contraire de la raison pour laquelle une valeur facultative doit être utilisée. Vous l'utilisez parce qu'il peut avoir ou non une valeur. De plus, le compilateur ne peut pas appliquer ce qui l' method()implémente correctement. Ce serait un échec à l' exécution: return Optional.of(null).
steinybot
3

Si vous n'avez simplement besoin de rien comme type, vous pouvez utiliser void. Cela peut être utilisé pour implémenter des fonctions ou des actions. Vous pouvez alors faire quelque chose comme ceci:

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

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

    abstract void executeInternal();
}

Ou vous pouvez omettre la classe abstraite et effectuer le retour null dans chaque action qui ne nécessite pas de valeur de retour vous-même.

Vous pouvez ensuite utiliser ces actions comme ceci:

Étant donné une méthode

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

tu peux l'appeler comme

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

ou, pour l'action d'annulation (notez que vous n'attribuez le résultat à rien)

executeAction(new VoidAction() {
    @Override
    public void executeInternal() {
        //code here
    }
});
Jorn
la source
2
en quoi est-ce différent de ce que j'ai déjà? il renvoie toujours null, comme je l'ai suggéré
Robert
Pourquoi devriez-vous retourner autre chose? Le point que j'essaie de faire est que vous n'avez pas besoin de la valeur de retour, donc peu importe ce que vous retournez. J'ai essayé de clarifier cela avec mon montage.
Jorn
1

Juste pour le plaisir, il y a bien sûr la possibilité de créer une Voidinstance en utilisant la réflexion:

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

Vous ne ferez probablement pas cela en production.

kap
la source
0

Il n'y a pas de type générique qui dira au compilateur qu'une méthode ne renvoie rien.

Je crois que la convention est d'utiliser Object lors de l'héritage en tant que paramètre de type

OU

Propagez le paramètre de type vers le haut, puis laissez les utilisateurs de votre classe instancier en utilisant Object et en affectant l'objet à une variable tapée à l'aide d'un caractère générique de type ?:

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
la source
1
est-ce la convention pour définir le type de retour sur nul avec les génériques - cela ne me semble pas très vide?
Robert
Je crois que c'est la voie à suivre. Tout utilisateur de classe A<?>ne pourra pas utiliser la valeur renvoyée de method().
Christopher Oezbek