Void Type in Java

Overview

Als Java ontwikkelaars, zijn we misschien wel eens het Void type tegengekomen en hebben we ons afgevraagd wat het doel ervan was.

In deze korte handleiding leren we over deze eigenaardige klasse en zien we wanneer en hoe we hem kunnen gebruiken en hoe we het gebruik ervan kunnen vermijden wanneer dat mogelijk is.

Wat is het Void Type

Sinds JDK 1.1, voorziet Java ons van het Void type. Het doel ervan is eenvoudigweg om het void return type als een klasse te representeren en een Class<Void> publieke waarde te bevatten. Het is niet instantiable omdat de enige constructor prive is.

Daarom is de enige waarde die we aan een Void variabele kunnen toekennen, null. Het lijkt misschien een beetje nutteloos, maar we zullen nu zien wanneer en hoe we dit type kunnen gebruiken.

Gebruiken

Er zijn enkele situaties waarin het gebruik van het Void type interessant kan zijn.

3.1. Reflectie

In de eerste plaats kunnen we het gebruiken bij reflectie. Inderdaad, het return type van elke void methode zal overeenkomen met de Void.TYPE variabele die de eerder genoemde Class<Void> waarde bevat.

Laten we ons een eenvoudige Calculator klasse voorstellen:

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

Enkele methodes retourneren een geheel getal, andere retourneren niets. Laten we nu zeggen dat we, door reflectie, alle methodes moeten ophalen die geen resultaat teruggeven. We zullen dit bereiken door de Void.TYPE variabele te gebruiken:

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

Zoals we kunnen zien, zijn alleen de clear() en print() methodes opgehaald.

3.2. Generics

Een ander gebruik van het Void type is met generieke klassen. Stel dat we een methode aanroepen die een parameter Callable nodig heeft:

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

Maar, de Callable die we willen doorgeven hoeft niets terug te geven. Daarom kunnen we een Callable<Void> doorgeven:

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

We hadden ook een willekeurig type kunnen gebruiken (b.v. Callable<Integer>) en null of helemaal geen type terug kunnen geven (Callable), maar door Void te gebruiken geven we onze bedoelingen duidelijk aan.

We kunnen deze methode ook toepassen op lambdas. In feite had onze Callable ook als een lambda geschreven kunnen worden. Laten we ons een methode voorstellen die een Function vereist, maar we willen een Function gebruiken die niets teruggeeft. Dan hoeven we alleen maar Void te retourneren:

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

Hoe vermijd je het gebruik ervan?

Nu, we hebben een aantal toepassingen van het Void type gezien. Echter, zelfs als het eerste gebruik helemaal prima is, willen we misschien het gebruik van Void in generics vermijden indien mogelijk. Inderdaad, het tegenkomen van een return type dat de afwezigheid van een resultaat representeert en alleen null kan bevatten kan omslachtig zijn.

We zullen nu zien hoe we deze situaties kunnen vermijden. Laten we eerst eens kijken naar onze methode met de parameter Callable. Om het gebruik van een Callable<Void> te vermijden, kunnen we een andere methode aanbieden die in plaats daarvan een Runnable-parameter neemt:

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

Dus, we kunnen het een Runnable doorgeven die geen waarde teruggeeft en zo ons ontdoen van de nutteloze return null:

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

Maar wat dan, als de Defer klasse niet van ons is om te wijzigen? Dan kunnen we ofwel vasthouden aan de Callable<Void> optie of een andere klasse maken die een Runnable neemt en de aanroep naar de Defer klasse uitstelt:

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

Door dat te doen, kapselen we het omslachtige deel voor eens en voor altijd in onze eigen methode in, zodat toekomstige ontwikkelaars een eenvoudiger API kunnen gebruiken.

Hetzelfde kan natuurlijk worden bereikt voor de Function. In ons voorbeeld retourneert de Function niets, zodat we een andere methode kunnen maken die in plaats daarvan een Consumer neemt:

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

En wat als onze functie geen parameter neemt? We kunnen ofwel een Runnable gebruiken of onze eigen functionele interface maken (als dat duidelijker lijkt):

public interface Action { void execute();}

Dan overloaden we de defer() methode weer:

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

Conclusie

In dit korte artikel hebben we de Java Void klasse behandeld. We hebben gezien wat het doel ervan is en hoe je het moet gebruiken. We leerden ook enkele alternatieven voor het gebruik ervan.

Zoals gebruikelijk is de volledige code van dit artikel te vinden op onze GitHub.

Ga aan de slag met Spring 5 en Spring Boot 2, via de Leer Spring cursus:

>> CHECK OUT THE COURSE

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.