with ChatGPT 시리즈는 ChatGPT의 내용과 개인의 생각을 토대로 학습해 보는 컨텐츠입니다.
코틀린에는 Unit과 Nothing이라는 두 가지 특수한 반환 타입이 존재합니다.
- Unit은 Java의 void와 유사하지만, 타입으로 존재하며 함수형 프로그래밍에 더 적합한 구조를 가집니다.
- Nothing은 "정상적으로 종료되지 않는 함수"를 표현하며, 예외 처리나 흐름 제어에서 중요한 역할을 합니다.
이번 글에서는 두 타입의 차이, 그리고 실무에서 어떻게 활용되는지를 구체적으로 살펴보겠습니다.
🔹 1. Kotlin의 Unit은 무엇인가요?
✅ Unit의 기본 개념
Kotlin에서 Unit은 Java의 void와 유사하게, 반환값이 없는 함수에서 사용되는 타입입니다. 하지만 void와는 달리, Unit은 타입 시스템에서 하나의 객체로 존재합니다.
fun logMessage(message: String): Unit {
println(message)
}
이렇게 작성한 함수는 다음과 같이 Unit 생략도 가능합니다.
fun logMessage(message: String) {
println(message)
}
- Unit은 사실상 Unit.INSTANCE라는 단일 객체를 반환합니다.
- 따라서 Kotlin에서는 반환값이 없는 함수도 타입이 있다고 볼 수 있으며, 이를 활용해 고차 함수나 람다에서 일관된 타입을 유지할 수 있습니다.
🔹 2. Kotlin의 Nothing은 무엇인가요?
✅ Nothing의 기본 개념
Nothing은 정상적으로 값을 반환하지 않는 함수의 반환 타입입니다. 즉, 예외를 던지거나 무한 루프를 돌거나, 절대 실행이 끝나지 않는 함수에 사용됩니다.
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
이 함수는 절대로 값을 반환하지 않기 때문에 Nothing을 반환 타입으로 가질 수 있습니다.
✅ Nothing은 왜 필요한가요?
Nothing은 코드가 더 이상 진행되지 않음을 컴파일러에게 명확하게 알리는 역할을 합니다.
이는 표현식 내에서 타입 일관성을 유지할 때 매우 유용합니다.
예를 들어:
fun getColorCode(color: String): String {
return when (color) {
"red" -> "#FF0000"
"blue" -> "#0000FF"
else -> throw IllegalArgumentException("Invalid color: $color")
}
}
여기서 else 분기에서 throw를 사용하고 있는데, 이 throw 표현식의 타입은 Nothing입니다.
따라서 이 when 표현식 전체가 String 타입으로 추론될 수 있는 것입니다.
즉, Nothing은 "여기서 더 이상 코드가 실행되지 않는다"는 것을 명확하게 표현하며,
표현식 (when, if 등) 내부에서 타입 추론을 가능하게 해 주는 중요한 역할을 합니다.
🔹 3. 실무에서는 언제 사용하나요?
✅ Unit을 사용하는 대표적인 경우
1. 일반적인 반환 없는 함수
fun log(message: String) {
println(message)
}
2. 고차 함수에서 반환 값 없는 람다를 인자로 넘길 때
fun runAction(action: () -> Unit) {
action()
}
runAction { println("Hello") }
3. HTTP 요청에서 바디가 없는 POST 요청을 보낼 때
실무에서 Webhook이나 이벤트 전송 등 바디가 필요 없는 요청을 보낼 일이 종종 있습니다.
이럴 때 Kotlin에서는 Unit을 명시적으로 바디로 전달할 수 있습니다.
📦 예: RestTemplate 사용 시 Unit 전달
val restTemplate = RestTemplate()
val url = "https://api.example.com/trigger"
val response = restTemplate.postForEntity(url, Unit, String::class.java)
println(response.body)
- Unit은 Content-Length: 0인 요청을 의미
- null을 쓰는 것보다 더 명시적이고 타입 안정성도 유지됨
📦 예: WebClient 사용 시
val client = WebClient.create()
val response = client.post()
.uri("https://api.example.com/trigger")
.bodyValue(Unit)
.retrieve()
.bodyToMono(String::class.java)
.block()
- bodyValue(Unit)을 사용하여 빈 요청 바디임을 명확하게 전달
- 자주 사용하는 패턴이며, 실무에서 유용
✅ Nothing을 사용하는 대표적인 경우
1. 예외를 던지는 함수
fun error(message: String): Nothing {
throw IllegalStateException(message)
}
2. 무한 루프
fun loopForever(): Nothing {
while (true) {
println("Still looping...")
}
}
3. 표현식 내에서 예외를 던져 타입 일관성을 유지할 때
fun getColorCode(color: String): String {
return when (color) {
"red" -> "#FF0000"
"blue" -> "#0000FF"
else -> throw IllegalArgumentException("Invalid color: $color")
}
}
- else 분기에서 throw가 Nothing 타입이기 때문에 전체 표현식은 String으로 추론됨
- 이처럼 Nothing은 코드 흐름 중단을 명확히 하며, 표현식의 타입 안정성 유지에 기여
🚀 결론
타입 | 의미 | 사용 목적 | 예시 |
Unit | 반환값이 없는 함수 | 함수형 프로그래밍, 고차 함수, HTTP 빈 바디 | fun doSomething(): Unit |
Nothing | 반환되지 않는 함수 | 예외, 무한 루프, 표현식 타입 추론 | fun fail(): Nothing |
🤔 추가로 생각해 볼 질문들
- Kotlin에서 Unit을 명시적으로 사용하는 것이 void보다 어떤 장점이 있을까?
- 예외를 던지는 함수가 Nothing을 반환할 수 있다는 점이 어떤 코드 최적화에 도움이 될까?
- HTTP 요청에서 바디가 없다는 것을 Unit으로 표현하는 것이 왜 더 안전할까?
- Nothing을 활용하면 when 표현식에서 어떤 타입 추론이 가능해질까?
- 자바의 void와 Void.class, 코틀린의 Unit, Nothing은 어떻게 대응되며, 어떤 점에서 다를까?