Explain Codes LogoExplain Codes Logo

Returning a Void object

java
generics
null-object-pattern
optional
Anton ShumikhinbyAnton Shumikhin·Sep 3, 2024
TLDR
public Void myMethod() { // perform some magic... but no rabbits return null; // nailing the art of returning nothing }

A Void return type is Java's mysterious "no data," meaning null is the only acceptable return value.

Decoding Void

Void in Java is distinctive; it's an abstract unicorn. You can't create a Void object. Its main purpose? To serve as a stand-in when you're playing around with generics and need a placeholder type, but aren't actually going to return anything.

Generics and Void: a match made by programmers

Working with generics? Have a method that doesn't return a value? That's where Void enters the scene:

public <T> T genericMethod(Class<T> clazz) { if(clazz.equals(Void.class)) { // only then, returning nothing makes sense return null; } // Keep handling those pesky other types return ...; }

NullObject pattern: null who?

For those who are tired of dealing with null or Void, let's try the NullObject pattern. This pattern suggests creating a benign do-nothing object:

public interface Action { void perform(); } public class NoOpAction implements Action { @Override public void perform() { // Insert cricket sound effect 🦗 } } public Action getAction() { // Instead of null, getting the silent ninja return new NoOpAction(); }

Embrace the Optional

Facing the risk of NullPointerExceptions due to null? The Bible of Java offers Optional<T> as salvation:

public Optional<Void> safestMethod() { // do things, make coffee ☕ return Optional.empty(); // There's just wind here. }

Here, Optional<Void> is a clear sign of a value that might be absent, and it nullifies the risk of null references.

Actions, Anonymous Classes, and Safer Returns

Running side-shows with Void

Sometimes, we just care about the performance, not the applause. In such cases, where side effects matter, not the outcome, let's define an action returning Void:

public interface VoidAction { Void execute(); } public void performAsync(VoidAction action) { // let's get the show started! action.execute(); } // Call to action performAsync(() -> { // Your act goes here return null; // The sound of one hand clapping });

This strategy makes handling operations that neither shake nor stir the program easy.

Optional annotations for clarity

Optional<T> works wonders with annotations like @NonNull and @Nullable:

public Optional<@NonNull Void> zenMethod() { // Do enlightening things here if(someCondition) { return Optional.empty(); // When you have given up attachment } else { throw new SomeException("Reality did not meet expectations!"); } } public void useZenResult(Optional<@NonNull Void> result) { // Know your nulls from your empties result.ifPresentOrElse( aVoid -> { /* Here's your nothing burger */ }, () -> { /* The art of handling blank canvas */ } ); }

Quick word: don't play with Void reflection

Don't be lured into the dark arts of using reflection to create a Void object. It's a dangerous game:

// Danger Zone! ⚠️ Constructor<Void> constructor = Void.class.getDeclaredConstructor(); constructor.setAccessible(true); Void instance = constructor.newInstance(); // Do not collect $200, go straight to Jail

Such practices are fraught with security risks, go against Java's righteous path, and should be kept out of all professional codes.

Closure

Remember, as in life, practice is everything in coding. If you believe this answer got you closer to the truth of Void, upvote away! Now, code like nobody's watching! 👩‍💻 🎉