코틀린은 자체 컬렉션 클래스를 정의하지 않고, 자바 컬렉션을 확장하여 더 풍부한 API를 제공합니다.
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// 자바에서는 복잡한 코드가 필요하지만 코틀린에서는 간단
val evenNumbers = numbers.filter { it % 2 == 0 }
val doubled = numbers.map { it * 2 }
val sum = numbers.sum()
println("짝수: $evenNumbers") // [2, 4]
println("2배: $doubled") // [2, 4, 6, 8, 10]
println("합계: $sum") // 15
}
함수 오버로딩 없이도 다양한 방식으로 함수를 호출할 수 있습니다.
fun createUser(
name: String,
age: Int = 0,
email: String = "",
isActive: Boolean = true
) {
println("User: $name, Age: $age, Email: $email, Active: $isActive")
}
fun main() {
createUser("김철수") // 나머지는 디폴트 값
createUser("이영희", 25) // age만 지정
createUser("박민수", 30, "park@example.com") // email까지 지정
}
함수 호출 시 가독성을 크게 향상시킵니다.
fun main() {
// 이름붙인 인자로 순서에 상관없이 호출 가능
createUser(
name = "최지우",
isActive = false,
age = 28,
email = "choi@example.com"
)
// 일부만 이름을 붙여도 됨
createUser("정수민", email = "jung@example.com", age = 32)
}
클래스 없이도 함수와 프로퍼티를 직접 선언할 수 있어 코드 구조가 더 유연해집니다.
// utils.kt 파일
val APP_VERSION = "1.0.0"
const val MAX_RETRY_COUNT = 3
fun formatDate(timestamp: Long): String {
return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
.format(Date(timestamp))
}
fun isValidEmail(email: String): Boolean {
return email.contains("@") && email.contains(".")
}
// main.kt 파일
fun main() {
println("앱 버전: $APP_VERSION")
println("오늘 날짜: ${formatDate(System.currentTimeMillis())}")
println("이메일 유효성: ${isValidEmail("test@example.com")}")
}
외부 라이브러리 클래스를 포함해 모든 클래스의 API를 소스코드 수정 없이 확장할 수 있습니다.
// String 클래스 확장
fun String.isEmailValid(): Boolean {
return this.contains("@") && this.contains(".")
}
fun String.removeWhitespace(): String {
return this.replace("\\s".toRegex(), "")
}
// Int 클래스 확장
fun Int.isEven(): Boolean = this % 2 == 0
val Int.squared: Int
get() = this * this
fun main() {
val email = "user@example.com"
println(email.isEmailValid()) // true
val text = "Hello World"
println(text.removeWhitespace()) // HelloWorld
val number = 5
println(number.isEven()) // false
println(number.squared) // 25
}
인자가 하나인 메소드나 확장 함수를 더 깔끔한 구문으로 호출할 수 있습니다.
// 중위 함수 정의
infix fun Int.power(exponent: Int): Int {
return Math.pow(this.toDouble(), exponent.toDouble()).toInt()
}
infix fun String.shouldBe(expected: String): Boolean {
return this == expected
}
fun main() {
// 일반 호출
println(2.power(3)) // 8
// 중위 호출 - 더 자연스러운 표현
println(2 power 3) // 8
val result = "Hello"
println(result shouldBe "Hello") // true
// 코틀린 표준 라이브러리의 중위 함수들
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
println(map) // {1=one, 2=two, 3=three}
}
코틀린은 정규식과 일반 문자열 처리에 유용한 다양한 함수를 제공합니다.
fun main() {
val text = "kotlin-java-python"
// 분할
println(text.split("-")) // [kotlin, java, python]
// 정규식 사용
val phoneNumber = "010-1234-5678"
val digits = phoneNumber.replace(Regex("[^0-9]"), "")
println(digits) // 01012345678
// 문자열 조작
val email = " USER@EXAMPLE.COM "
println(email.trim().lowercase()) // user@example.com
// 조건부 처리
val fileName = "document.pdf"
if (fileName.endsWith(".pdf")) {
println("PDF 파일입니다")
}
// 패턴 매칭
val pattern = Regex("""(\d{3})-(\d{4})-(\d{4})""")
val match = pattern.find("연락처: 010-1234-5678")
match?.let {
println("전화번호: ${it.value}") // 전화번호: 010-1234-5678
println("지역번호: ${it.groupValues[1]}") // 지역번호: 010
}
}
이스케이프가 많이 필요한 문자열을 더 깔끔하게 표현할 수 있습니다.
fun main() {
// 일반 문자열 - 이스케이프 필요
val jsonString = "{\"name\": \"John\", \"age\": 30, \"city\": \"Seoul\"}"
// 삼중 따옴표 - 이스케이프 불필요
val jsonStringRaw = """
{
"name": "John",
"age": 30,
"city": "Seoul"
}
""".trimIndent()
// 정규식 패턴
val regexPattern = """^\d{3}-\d{4}-\d{4}$"""
// 파일 경로 (Windows)
val windowsPath = """C:\Users\Documents\file.txt"""
// HTML 템플릿
val htmlTemplate = """
<!DOCTYPE html>
<html>
<head>
<title>${"코틀린 예제"}</title>
</head>
<body>
<h1>환영합니다!</h1>
<p>현재 시간: ${System.currentTimeMillis()}</p>
</body>
</html>
""".trimIndent()
println(jsonStringRaw)
println(htmlTemplate)
}
// 확장 함수와 중위 함수
infix fun String.matches(pattern: String): Boolean =
Regex(pattern).matches(this)
fun String.formatPhoneNumber(): String =
this.replace(Regex("[^0-9]"), "")
.let { digits ->
when {
digits.length == 11 -> "${digits.substring(0,3)}-${digits.substring(3,7)}-${digits.substring(7)}"
digits.length == 10 -> "${digits.substring(0,3)}-${digits.substring(3,6)}-${digits.substring(6)}"
else -> this
}
}
// 최상위 함수
fun validateUser(
name: String,
phone: String = "",
email: String = "",
printResult: Boolean = true
): Boolean {
val phonePattern = """^010-\d{4}-\d{4}$"""
val emailPattern = """^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"""
val isValid = name.isNotBlank() &&
(phone.isEmpty() || phone matches phonePattern) &&
(email.isEmpty() || email matches emailPattern)
if (printResult) {
val result = """
사용자 검증 결과:
- 이름: $name
- 전화번호: ${phone.ifEmpty { "미입력" }}
- 이메일: ${email.ifEmpty { "미입력" }}
- 유효성: ${if (isValid) "통과" else "실패"}
""".trimIndent()
println(result)
}
return isValid
}
fun main() {
val phoneNumbers = listOf("01012345678", "010-1234-5678", "0212345678")
phoneNumbers
.map { it.formatPhoneNumber() }
.forEach { println("포맷된 번호: $it") }
// 이름붙인 인자와 디폴트 파라미터 활용
validateUser(
name = "김개발자",
phone = "010-1234-5678",
email = "dev@example.com"
)
}