UUID
UUID
Uuid 클래스는 UUID(Universally Unique Identifier, 범용 고유 식별자)를 나타냅니다. GUID(Globally Unique Identifier)라고도 불러요.
Uuid는 ID를 부여하는 중앙 시스템에 의존하지 않고 개체를 고유하게 식별하는 데 사용되는 128비트 값이에요. 그래서 UUID는 분산 애플리케이션, 데이터베이스, 클라이언트에서 생성하는 레코드, 또는 Kotlin Multiplatform 애플리케이션에서 유용하게 쓰입니다.
Uuid 클래스를 사용해 UUID 값을 다뤄 보세요. 단순한 문자열과 달리, 전용 UUID 타입을 사용하면 코드가 더 명확해지고 잘못된 값을 실수로 쓰는 일도 막아 줍니다.
출처: UUIDs
본문
프로젝트에서 UUID를 사용하려면 kotlin.uuid 패키지에서 Uuid 클래스를 가져오세요:
import kotlin.uuid.Uuid
UUID 생성하기
사용자 ID나 데이터베이스 ID 같은 일반 식별자용으로 무작위 버전 4 UUID를 생성하려면 Uuid.random() 함수를 사용하세요:
import kotlin.uuid.Uuid
fun main() {
val id = Uuid.random()
println(id)
}
다음과 같은 Experimental(실험적) 함수로 특정 버전의 UUID를 생성할 수도 있어요:
Uuid.generateV4()함수는Uuid.random()함수와 같은 종류의 UUID를 생성하지만, 값이 버전 4 UUID임을 명시적으로 나타냅니다.Uuid.generateV7()함수는 UUID 정렬에 사용할 수 있는 타임스탬프가 포함된 버전 7 UUID를 생성해요.Uuid.generateV7NonMonotonicAt()함수는 특정 시점에 대한 버전 7 UUID를 생성합니다.
이러한 UUID 생성 함수는 Experimental이에요. 사용하려면 @OptIn(ExperimentalUuidApi::class) 애너테이션을 사용하거나, 빌드 파일에 다음 컴파일러 옵션을 추가하면 됩니다:
kotlin {
compilerOptions {
freeCompilerArgs.add("-opt-in=kotlin.uuid.ExperimentalUuidApi")
}
}
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-opt-in=kotlin.uuid.ExperimentalUuidApi</arg>
</args>
</configuration>
</plugin>
</plugins>
</build>
버전별 UUID를 생성하는 예시를 볼게요:
import kotlin.time.Instant
import kotlin.time.ExperimentalTime
import kotlin.uuid.Uuid
@OptIn(kotlin.uuid.ExperimentalUuidApi::class, ExperimentalTime::class)
fun main() {
// 버전 4 UUID 생성
val idVersion4 = Uuid.generateV4()
println(idVersion4)
// 버전 7 UUID 생성
val idVersion7 = Uuid.generateV7()
println(idVersion7)
// 지정된 타임스탬프에 대한 버전 7 UUID 생성
val timestamp = Instant.fromEpochMilliseconds(1757440583000L)
val idVersion7SpecificTime = Uuid.generateV7NonMonotonicAt(timestamp)
println(idVersion7SpecificTime)
}
UUID 파싱하기
UUID 값은 URL 파라미터나 데이터베이스 레코드처럼 문자열로 표현되는 경우가 많아요.
String 값을 Uuid 값으로 변환하려면 Uuid.parse() 함수를 사용하세요:
import kotlin.uuid.Uuid
fun main() {
val id = Uuid.parse("de2bc56c-ea73-4f3c-8a37-5a46fdb2d79a")
println(id)
}
Uuid.parse() 함수는 표준 16진수-하이픈 형식과 하이픈이 없는 16진수 형식을 모두 받아들입니다.
입력이 잘못된 경우 Uuid.parse() 함수는 IllegalArgumentException을 던져요:
import kotlin.uuid.Uuid
fun main() {
val id = Uuid.parse("10")
println(id)
}
애플리케이션이 하나의 표현만 받아들인다면, 형식별 함수를 사용하세요:
Uuid.parseHexDash()는 16진수-하이픈 문자열 표현용이에요.Uuid.parseHex()는 하이픈이 없는 16진수 문자열 표현용입니다.
예를 들어:
import kotlin.uuid.Uuid
fun main() {
val standard = Uuid.parseHexDash("de2bc56c-ea73-4f3c-8a37-5a46fdb2d79a")
val compact = Uuid.parseHex("de2bc56cea734f3c8a375a46fdb2d79a")
println(standard)
println(compact)
}
외부 소스의 UUID를 다루면서 잘못된 입력을 안전하게 처리해야 한다면 Uuid.parseOrNull(), Uuid.parseHexDashOrNull(), Uuid.parseHexOrNull()을 사용하세요. 이 함수들은 입력이 잘못되면 null을 반환합니다:
fun parseId(input: String): Uuid? {
return Uuid.parseOrNull(input)
}
UUID를 문자열로 변환하기
Uuid 값을 String 값으로 변환하는 함수는 다음과 같아요:
toString()은 표준 문자열 표현용이에요.toHexDashString()은 16진수-하이픈 형식용입니다.toHexString()은 하이픈이 없는 16진수 형식용이에요.
예를 들어:
import kotlin.uuid.Uuid
fun main() {
val id = Uuid.parse("de2bc56c-ea73-4f3c-8a37-5a46fdb2d79a")
println(id.toString())
// de2bc56c-ea73-4f3c-8a37-5a46fdb2d79a
println(id.toHexDashString())
// de2bc56c-ea73-4f3c-8a37-5a46fdb2d79a
println(id.toHexString())
// de2bc56cea734f3c8a375a46fdb2d79a
}
UUID 비교하기
== 연산자로 Uuid 값이 같은지 확인할 수 있어요.
Kotlin은 텍스트 표현이 아니라 UUID 값에 따라 값을 비교합니다. 예를 들어, 서로 다른 형식의 두 값이 같은 128비트 값을 나타내면 같다고 판단해요:
import kotlin.uuid.Uuid
fun main() {
val first = Uuid.parse("de2bc56c-ea73-4f3c-8a37-5a46fdb2d79a")
val second = Uuid.parse("de2bc56cea734f3c8a375a46fdb2d79a")
println(first == second)
// true
}
이 덕분에 UUID 비교는 문자열 비교보다 더 신뢰할 수 있어요. 문자열 비교는 같은 값을 다른 형식으로 표현하면 서로 다른 값으로 취급하지만, UUID 비교는 실제 식별자 값을 확인하기 때문이에요.
Uuid는 Comparable<Uuid> 인터페이스를 구현하므로, UUID 값을 sorted() 같은 표준 컬렉션 함수로 정렬할 수 있습니다. 이때 Kotlin은 값을 사전식(가장 큰 비트에서 가장 작은 비트 순)으로 비교해요:
import kotlin.uuid.Uuid
fun main() {
val first = Uuid.generateV7()
val second = Uuid.generateV7()
val sorted = listOf(first, second).sorted()
println(sorted)
}
이진 표현 다루기
일부 API, 저장 형식, 이진 프로토콜은 UUID를 문자열로 표현하지 않아요. 대신 128비트 UUID 값을 다음 중 하나로 저장합니다:
- 16바이트 배열
- 두 개의 64비트 값
이진 UUID 데이터를 기대하는 시스템과 UUID를 교환해야 한다면 이 표현들을 사용하세요.
UUID와 16바이트 표현 사이를 변환하려면 .toByteArray()와 Uuid.fromByteArray() 함수를 사용하세요:
import kotlin.uuid.Uuid
fun main() {
val id = Uuid.random()
val bytes = id.toByteArray()
val original = Uuid.fromByteArray(bytes)
println(id)
println(bytes)
println(original)
println(id == original)
// true
}
같은 128비트 UUID 값을 두 개의 Long 값으로도 표현할 수 있어요. Kotlin에는 기본 제공 128비트 정수 타입이 없기 때문에 유용합니다. 두 Long 값은 UUID를 두 부분으로 나눠 저장해요:
mostSignificantBits파라미터는 UUID의 첫 64비트용이에요.leastSignificantBits파라미터는 UUID의 마지막 64비트용입니다.
두 Long 값에서 Uuid 값을 만들려면 Uuid.fromLongs() 함수를 사용하세요:
import kotlin.uuid.Uuid
fun main() {
val id = Uuid.fromLongs(
mostSignificantBits = -4653685776373167443,
leastSignificantBits = -6288180676521310383.toLong()
)
println(id)
// bf6ac971-52fd-4aad-a8bb-e4fdac78c751
}
기존 Uuid 값에서 두 부분을 추출하려면 Uuid.toLongs() 함수를 사용하세요:
import kotlin.uuid.Uuid
fun main() {
val id = Uuid.random()
id.toLongs { mostSignificantBits, leastSignificantBits ->
println(mostSignificantBits)
println(leastSignificantBits)
}
}
UUID 직렬화하기
Kotlin은 Uuid 값에 대한 직렬화(serialization)를 지원해요. JSON API나 설정 파일처럼 Kotlin 코드 밖에서 UUID 값을 저장하거나 전송할 때 사용하면 됩니다.
Uuid 값을 직렬화하려면, 애플리케이션이 다른 형식을 요구하지 않는 한 문자열로 표현하세요. kotlinx.serialization 라이브러리는 16진수-하이픈 형식을 사용합니다:
import kotlin.uuid.Uuid
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@Serializable
data class User(
val id: Uuid,
val name: String
)
fun main() {
val user = User(
id = Uuid.parse("de2bc56cea734f3c8a375a46fdb2d79a"),
name = "Kotlin"
)
println(Json.encodeToString(user))
// {"id":"de2bc56c-ea73-4f3c-8a37-5a46fdb2d79a","name":"Kotlin"}
}
Java API와 함께 UUID 사용하기
Java는 java.util.UUID 클래스를 사용해 UUID를 표현합니다. JVM에서는 Java API가 이 타입을 받거나 반환할 수 있어요. java.util.UUID와 kotlin.uuid.Uuid는 둘 다 UUID를 나타내지만, 서로 다른 두 타입입니다.
Kotlin과 Java 사이에서 UUID를 전달하려면 값을 명시적으로 변환하세요:
- Java UUID를 Kotlin으로 변환하려면
.toKotlinUuid()확장 함수를 사용하세요:
import kotlin.uuid.toKotlinUuid
val kotlinId: Uuid = javaId.toKotlinUuid()
- Kotlin UUID를 Java로 변환하려면
.toJavaUuid()확장 함수를 사용하세요:
import kotlin.uuid.toJavaUuid
val javaId: java.util.UUID = kotlinId.toJavaUuid()
이 함수들을 사용하면 JVM 상호운용 경계에서 Uuid로 UUID 값을 표현할 수 있어요.
📝 참고
java.util.UUID와kotlin.uuid.Uuid클래스는 비교가 가능하지만, 정렬 순서가 다를 수 있어요. Java API에서 Kotlin API로 마이그레이션하기 전에 UUID 정렬에 의존하는 코드를 꼭 확인하세요.
Kotlin은 Java 버퍼 작업도 지원합니다. ByteBuffer에서 UUID를 다룰 때는 JVM 전용 함수를 사용하세요:
- 버퍼에서 UUID를 읽으려면
.getUuid()함수를 사용해요. - 버퍼에 UUID를 쓰려면
.putUuid()함수를 사용합니다.