Kotlin - Void vs. Unit vs. Nothing: Best Practices in 2025
\n\nHello, colleagues! If you've ever written in Kotlin and wondered: "Why is it Unit here, and not void? And what kind of beast is Nothing?" — you've come to the right place. This topic is a real hit on Stack Overflow with thousands of views, and for good reason. The confusion between Void, Unit, and Nothing can throw even an experienced developer off track. In 2025, when Kotlin confidently occupies a niche in backend (Ktor, Spring) and Android, understanding these types is not just a whim, but a necessity for writing clean, safe, and expressive code.
In this article, we won't just list definitions. We'll break them down with real examples, show where each one is appropriate, and where it's a mortal sin. Let's go!
\n\nQuick Overview: What is What?
\n\nLet's get things straight right away. These three types solve different problems, even though they might seem similar at first glance.
\n\n- \n
Void— is a relic from Java. In Kotlin, it exists only for compatibility. Never use it in pure Kotlin code. \n Unit— means "I return nothing, but I am still a type." An analogue ofvoidin Java, but better. Used in 99% of cases when a function does not return a meaningful result. \n Nothing— means "the function will never complete normally." It will either throw an exception or go into an infinite loop. This is a powerful tool for controlling execution flow. \n
Sounds simple? Let's dig deeper.
\n\nVoid — A Stranger Among Its Own
\n\nIf you're writing in pure Kotlin, forget about Void like a bad dream. It's a class from Java (java.lang.Void), which is a wrapper for the void keyword. It exists in Kotlin solely for interoperability with Java code.
An example of when Void might appear in your project:
import java.lang.Void\n\n// Never do this in pure Kotlin!\nfun doSomething(): Void? {\n println("Doing something...")\n return null // Must return null, otherwise compilation error\n}\n\nSee that return null? That's the main downside. Void cannot be instantiated (it has a private constructor), but it can be null. This creates confusion and unnecessary code.
Best Practice 2025: Use Void only if you are overriding a method from a Java library that requires Void as a generic parameter. For example, in Callable<Void>. In all other cases — use Unit.
Unit — The King of Empty Functions
\n\nUnit is the true Kotlin way to say: "The function executed, but I don't care about the result." Unlike void, Unit is a full-fledged type with a single value — Unit.
This gives cool possibilities:
\n\n- \n
- Generics. You can use
Unitin generic functions. \n - Higher-order functions. You can pass a function returning
Unitas an argument. \n - Extensions. You can write extension functions that return
Unit. \n
A standard example — lambda expressions:
\n\nfun executeAction(action: () -> Unit) {\n println("Preparing for action...")\n action() // Call the passed function\n println("Action completed.")\n}\n\nfun main() {\n // Lambda that returns nothing but produces a side effect\n executeAction {\n println("Hello from lambda!")\n }\n}\n\nHere