Kotlin 톺아보기 2

KangWook·2025년 7월 27일
0

kotlin

목록 보기
2/2

1. 컬렉션 API 확장

코틀린은 자체 컬렉션 클래스를 정의하지 않고, 자바 컬렉션을 확장하여 더 풍부한 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
}

2. 함수 파라미터 디폴트 값과 이름붙인 인자

디폴트 파라미터

함수 오버로딩 없이도 다양한 방식으로 함수를 호출할 수 있습니다.

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)
}

3. 최상위 함수와 프로퍼티

클래스 없이도 함수와 프로퍼티를 직접 선언할 수 있어 코드 구조가 더 유연해집니다.

// 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")}")
}

4. 확장 함수와 프로퍼티

외부 라이브러리 클래스를 포함해 모든 클래스의 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
}

5. 중위 호출 (Infix Functions)

인자가 하나인 메소드나 확장 함수를 더 깔끔한 구문으로 호출할 수 있습니다.

// 중위 함수 정의
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}
}

6. 문자열 처리 함수

코틀린은 정규식과 일반 문자열 처리에 유용한 다양한 함수를 제공합니다.

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
    }
}

7. 삼중 따옴표 문자열

이스케이프가 많이 필요한 문자열을 더 깔끔하게 표현할 수 있습니다.

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)
}

8. 실전 예제: 모든 기능 조합

// 확장 함수와 중위 함수
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"
    )
}

profile
꾸준히 성장하는 개발자

0개의 댓글