Type Void en Java

Aperçu

En tant que développeurs Java, nous avons peut-être rencontré le type Void à une occasion et nous nous sommes demandés quel était son but.

Dans ce rapide tutoriel, nous allons apprendre à connaître cette classe particulière et voir quand et comment l’utiliser ainsi que comment l’éviter lorsque c’est possible.

Qu’est-ce que le type Void

Depuis le JDK 1.1, Java nous fournit le type Void. Son but est simplement de représenter le type de retour void comme une classe et de contenir une valeur publique Class<Void>. Il n’est pas instanciable car son seul constructeur est privé.

Par conséquent, la seule valeur que nous pouvons attribuer à une variable Void est null. Cela peut sembler un peu inutile, mais nous allons maintenant voir quand et comment utiliser ce type.

Utilisations

Il y a quelques situations où l’utilisation du type Void peut être intéressante.

3.1. Reflection

Premièrement, nous pourrions l’utiliser lors de la réflexion. En effet, le type de retour de toute méthode void correspondra à la variable Void.TYPE qui contient la valeur Class<Void> mentionnée plus tôt.

Imaginons une simple classe Calculatrice:

public class Calculator { private int result = 0; public int add(int number) { return result += number; } public int sub(int number) { return result -= number; } public void clear() { result = 0; } public void print() { System.out.println(result); }}

Certaines méthodes retournent un entier, d’autres ne retournent rien. Maintenant, disons que nous devons récupérer, par réflexion, toutes les méthodes qui ne retournent aucun résultat. Nous y parviendrons en utilisant la variable Void.TYPE :

@Testvoid givenCalculator_whenGettingVoidMethodsByReflection_thenOnlyClearAndPrint() { Method calculatorMethods = Calculator.class.getDeclaredMethods(); List<Method> calculatorVoidMethods = Arrays.stream(calculatorMethods) .filter(method -> method.getReturnType().equals(Void.TYPE)) .collect(Collectors.toList()); assertThat(calculatorVoidMethods) .allMatch(method -> Arrays.asList("clear", "print").contains(method.getName()));}

Comme nous pouvons le constater, seules les méthodes clear() et print() ont été récupérées.

3.2. Génériques

Une autre utilisation du type Void est avec les classes génériques. Supposons que nous appelons une méthode qui nécessite un paramètre Callable :

public class Defer { public static <V> V defer(Callable<V> callable) throws Exception { return callable.call(); }}

Mais, le Callable que nous voulons passer ne doit rien retourner. Par conséquent, nous pouvons passer un Callable<Void>:

@Testvoid givenVoidCallable_whenDiffer_thenReturnNull() throws Exception { Callable<Void> callable = new Callable<Void>() { @Override public Void call() { System.out.println("Hello!"); return null; } }; assertThat(Defer.defer(callable)).isNull();}

Nous aurions pu soit utiliser un type aléatoire (par exemple Callable<Integer>) et retourner null ou aucun type du tout (Callable), mais utiliser Void énonce clairement nos intentions.

Nous pouvons également appliquer cette méthode aux lambdas. En fait, notre Callable aurait pu être écrit comme un lambda. Imaginons une méthode nécessitant une Function, mais nous voulons utiliser une Function qui ne renvoie rien. Il suffit alors de lui faire retourner Void:

public static <T, R> R defer(Function<T, R> function, T arg) { return function.apply(arg);}
@Testvoid givenVoidFunction_whenDiffer_thenReturnNull() { Function<String, Void> function = s -> { System.out.println("Hello " + s + "!"); return null; }; assertThat(Defer.defer(function, "World")).isNull();}

Comment éviter de l’utiliser?

Maintenant, nous avons vu quelques utilisations du type Void. Cependant, même si le premier usage est totalement correct, nous pourrions vouloir éviter d’utiliser Void dans les génériques si possible. En effet, rencontrer un type de retour qui représente l’absence de résultat et qui ne peut contenir que null peut être encombrant.

Nous allons maintenant voir comment éviter ces situations. Tout d’abord, considérons notre méthode avec le paramètre Callable. Afin d’éviter d’utiliser un Callable<Void>, nous pourrions proposer une autre méthode prenant un paramètre Runnable à la place:

public static void defer(Runnable runnable) { runnable.run();}

Donc, nous pouvons lui passer un Runnable qui ne renvoie aucune valeur et ainsi nous débarrasser de l’inutile return null:

Runnable runnable = new Runnable() { @Override public void run() { System.out.println("Hello!"); }};Defer.defer(runnable);

Mais alors, que faire si la classe Defer ne nous appartient pas pour la modifier ? Alors nous pouvons soit nous en tenir à l’option Callable<Void>, soit créer une autre classe prenant un Runnable et reportant l’appel à la classe Defer:

public class MyOwnDefer { public static void defer(Runnable runnable) throws Exception { Defer.defer(new Callable<Void>() { @Override public Void call() { runnable.run(); return null; } }); }}

En faisant cela, nous encapsulons la partie encombrante une fois pour toutes dans notre propre méthode, permettant aux futurs développeurs d’utiliser une API plus simple.

Bien sûr, la même chose peut être réalisée pour Function. Dans notre exemple, la fonction ne renvoie rien, donc nous pouvons fournir une autre méthode prenant un Consumer à la place :

public static <T> void defer(Consumer<T> consumer, T arg) { consumer.accept(arg);}

Alors, que faire si notre fonction ne prend aucun paramètre ? Nous pouvons soit utiliser un Runnable, soit créer notre propre interface fonctionnelle (si cela semble plus clair):

public interface Action { void execute();}

Puis, nous surchargeons à nouveau la méthode defer():

public static void defer(Action action) { action.execute();}
Action action = () -> System.out.println("Hello!");Defer.defer(action);

Conclusion

Dans ce court article, nous avons couvert la classe Java Void. Nous avons vu quel était son but et comment l’utiliser. Nous avons également appris quelques alternatives à son utilisation.

Comme d’habitude, le code complet de cet article peut être trouvé sur notre GitHub.

Débutez avec Spring 5 et Spring Boot 2, grâce au cours Learn Spring:

>> VÉRIFIER LE COURS

.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.