기본 지식 - 변수와 자료

 

기본 연산자

// **1. 산술 연산자 (Arithmetic Operators)**
val sum = 10 + 5  // 덧셈
val diff = 10 - 5 // 뺄셈
val product = 10 * 5 // 곱셈
val quotient = 10 / 5 // 나눗셈
val remainder = 10 % 3 // 나머지

// **2. 복합 대입 연산자 (Assignment Operators)**
var num = 10
num += 5  // num = num + 5 (덧셈 후 대입)
num -= 3  // num = num - 3 (뺄셈 후 대입)
num *= 2  // num = num * 2 (곱셈 후 대입)
num /= 2  // num = num / 2 (나눗셈 후 대입)
num %= 3  // num = num % 3 (나머지 후 대입)

// **3. 증가 및 감소 연산자 (Increment and Decrement Operators)**
var count = 0
count++ // 후위 증가: count 값을 사용한 후 1 증가
++count // 전위 증가: count 값을 증가시킨 후 사용
count-- // 후위 감소: count 값을 사용한 후 1 감소
--count // 전위 감소: count 값을 감소시킨 후 사용

// **4. 비교 연산자 (Comparison Operators)**
val a = 10
val b = 20
val isEqual = (a == b) // 값이 같은지 비교
val isNotEqual = (a != b) // 값이 다른지 비교
val isGreater = (a > b) // a가 b보다 큰지 비교
val isLess = (a < b) // a가 b보다 작은지 비교
val isGreaterOrEqual = (a >= b) // a가 b보다 크거나 같은지 비교
val isLessOrEqual = (a <= b) // a가 b보다 작거나 같은지 비교

// **5. 논리 연산자 (Logical Operators)**
val condition1 = true
val condition2 = false
val andResult = condition1 && condition2 // AND 연산: 둘 다 true일 때만 true
val orResult = condition1 || condition2 // OR 연산: 둘 중 하나라도 true면 true
val notResult = !condition1 // NOT 연산: true → false, false → true

// **6. 비트 연산자 (Bitwise Operators)**
val x = 5  // 0b0101
val y = 3  // 0b0011
val bitAnd = x and y // AND 연산: 0b0001 (비트 단위)
val bitOr = x or y  // OR 연산: 0b0111
val bitXor = x xor y // XOR 연산: 0b0110
val bitInv = x.inv() // 비트 반전: -6 (0b...11111010)
val leftShift = x shl 2 // 왼쪽 시프트: 0b10100 (5 * 2^2)
val rightShift = x shr 1 // 오른쪽 시프트: 0b0010 (5 / 2)

// **7. 범위 연산자 (Range Operators)**
val range = 1..5 // 1에서 5까지 포함된 범위
val untilRange = 1 until 5 // 1에서 5 미만 (1, 2, 3, 4)
val downToRange = 5 downTo 1 // 5에서 1까지 감소
val stepRange = 1..10 step 2 // 1, 3, 5, ..., 9 (2씩 증가)

// **8. 인 연산자 (in Operator)**
val isInRange = 3 in range // true (3이 range 안에 포함)
val isNotInRange = 6 !in range // true (6이 range에 포함되지 않음)

// **9. 타입 연산자 (Type Operators)**
val str: Any = "Hello"
val isString = str is String // true (str이 String 타입인지 확인)
val isNotString = str !is String // false (str이 String 타입이 아닌지 확인)

// **10. 엘비스 연산자 (Elvis Operator)**
val nullable: String? = null
val result = nullable ?: "Default" // nullable이 null이면 "Default" 반환

// **11. 안전 호출 연산자 (Safe Call Operator)**
val nullableStr: String? = "Hello"
val length = nullableStr?.length // nullableStr이 null이 아니면 length 반환, null이면 null 반환

// **12. 강제 호출 연산자 (Not-null Assertion Operator)**
val nonNullLength = nullableStr!!.length // nullableStr이 null이 아니라고 확신하는 경우 사용 (null이면 예외 발생)

// **13. 기타 연산자**
val aStr = "Kotlin"
val bStr = "kotlin"
val ignoreCaseEquals = (aStr.equals(bStr, ignoreCase = true)) // 대소문자 무시하고 비교

요약

  • Kotlin 연산자는 Java의 연산자와 유사하지만, 더 간결하고 안전성을 높인 연산자를 제공합니다.
  • 특히 Elvis 연산자 (?:), 안전 호출 연산자 (?.), 강제 호출 연산자 (!!) 등은 Kotlin의 강력한 특징 중 하나로 Null 안전성을 보장합니다.
  • 기본적으로 자바보다도 더 가독성이 좋은 형태로 구성이 되어 있어, 코딩시에 유리합니다.

 

출력과 입력

📌 흔히 다른 장치로 데이터를 전송하는 행위를 Output(출력), 반대로 데이터를 불러오는 행위를 Input(입력)이라고 합니다.

  • 프로그램에서 스피커로 사운드 출력
  • 마이크에서 녹음한 목소리를 불러와서 프로그램에서 확인

 

1. 출력 (Output)

// **기본 출력**
println("Hello, Kotlin!") // 줄 바꿈과 함께 메시지 출력
print("Hello, ") // 줄 바꿈 없이 메시지 출력
print("World!") // 이어서 출력

// **문자열 보간(String Interpolation)**
val name = "Alice"
val age = 25
println("My name is $name, and I am $age years old.") // 변수 값을 문자열에 삽입
println("Next year, I will be ${age + 1} years old.") // 중괄호를 사용해 식도 삽입 가능

// **서식 지정 출력**
val pi = 3.14159
println("The value of pi is %.2f".format(pi)) // 소수점 둘째 자리까지 출력
println("Hello, %s! You are %d years old.".format(name, age)) // %s: 문자열, %d: 정수

2. 입력 (Input)

// **readLine() 사용 (기본 입력)**
print("Enter your name: ")
val userName = readLine() // 사용자 입력을 문자열로 읽음
println("Hello, $userName!")

// **숫자 입력 처리**
print("Enter your age: ")
val userAge = readLine()?.toIntOrNull() // 문자열을 정수로 변환 (null 안전)
if (userAge != null) {
    println("You are $userAge years old!")
} else {
    println("Invalid input. Please enter a valid number.")
}

// **여러 값 입력**
print("Enter two numbers separated by a space: ")
val (num1, num2) = readLine()!!.split(" ").map { it.toInt() } // 공백으로 구분된 두 숫자를 읽어 정수로 변환
println("Sum of $num1 and $num2 is ${num1 + num2}")

// **예외 처리와 함께 입력 처리**
try {
    print("Enter a decimal number: ")
    val decimal = readLine()!!.toDouble() // 문자열을 실수(Double)로 변환
    println("The value you entered is $decimal")
} catch (e: NumberFormatException) {
    println("Invalid input. Please enter a valid decimal number.")
}

3. 입력 및 출력 예제

fun main() {
    // 사용자 이름과 나이 입력받기
    print("What's your name? ")
    val name = readLine() ?: "Unknown" // Null 안전성을 위해 기본값 설정
    print("How old are you? ")
    val age = readLine()?.toIntOrNull() ?: 0 // 숫자 변환 실패 시 기본값 0
    
    // 입력 결과 출력
    println("Nice to meet you, $name!")
    println("You are $age years old.")
    
    // 두 숫자를 입력받아 합 계산
    print("Enter two numbers (e.g., 5 10): ")
    val (a, b) = readLine()!!.split(" ").map { it.toInt() }
    println("The sum of $a and $b is ${a + b}")
}

요약

작업 방법 설명
출력 print, println, format 사용 문자열 출력, 서식 지정 출력, 문자열 보간 등 다양한 방식 제공.
입력 readLine 사용 사용자로부터 문자열 입력받음. 숫자 변환 시 toIntOrNull, toDouble 활용.
에러 처리 try-catch 또는 null 체크 잘못된 입력에 대한 에러 처리 및 기본값 설정 가능.

 

 

조건식

 

1. if-else 조건문

// **기본 if-else**
val a = 10
val b = 20

if (a > b) {
    println("a is greater than b") // 조건이 참일 때 실행
} else {
    println("a is not greater than b") // 조건이 거짓일 때 실행
}

// **if-else if-else (여러 조건 처리)**
val number = 15

if (number > 0) {
    println("$number is positive") // 양수일 때 실행
} else if (number < 0) {
    println("$number is negative") // 음수일 때 실행
} else {
    println("$number is zero") // 0일 때 실행
}

// **if-else 표현식 (Expression)**
val max = if (a > b) a else b // 조건 결과를 변수에 저장
println("The maximum value is $max")

2. when 조건문

// **기본 when 사용**
val x = 2

when (x) {
    1 -> println("x is 1") // x가 1일 때
    2 -> println("x is 2") // x가 2일 때
    else -> println("x is neither 1 nor 2") // 어떤 경우에도 해당되지 않을 때
}

// **범위와 여러 값 검사**
val y = 10

when (y) {
    in 1..10 -> println("y is in the range 1 to 10") // 범위 검사
    in 11..20 -> println("y is in the range 11 to 20")
    else -> println("y is out of range")
}

// **is 연산자 사용**
val obj: Any = "Hello"

when (obj) {
    is String -> println("obj is a String") // obj가 String 타입일 때
    is Int -> println("obj is an Integer") // obj가 Int 타입일 때
    else -> println("obj is of an unknown type") // 다른 타입일 때
}

// **결과를 반환하는 when**
val z = 5
val result = when (z) {
    1 -> "One" // z가 1일 때 반환값
    2, 3 -> "Two or Three" // z가 2 또는 3일 때 반환값
    else -> "Other" // 어떤 경우에도 해당되지 않을 때
}
println("Result: $result")

3. 조건식 간소화

// **삼항 연산자 대체 (Kotlin은 삼항 연산자를 지원하지 않음)**
val isEven = if (x % 2 == 0) "Even" else "Odd" // 삼항 연산자 대신 if-else 표현식 사용
println("x is $isEven")

4. 조건식 활용 예제

fun main() {
    // 숫자 크기 비교
    val a = 10
    val b = 15
    println("Larger number: ${if (a > b) a else b}")

    // 범위와 타입 검사
    val input: Any = 42
    when (input) {
        in 1..50 -> println("Input is in range 1 to 50")
        is String -> println("Input is a string")
        else -> println("Input is something else")
    }

    // 다양한 조건 처리
    val score = 85
    val grade = when {
        score >= 90 -> "A"
        score >= 80 -> "B"
        score >= 70 -> "C"
        else -> "F"
    }
    println("Your grade is $grade")
}

요약

조건식 유형 설명 사용 예제
if-else 조건이 참인지 거짓인지 확인 후 실행. if (a > b) println("a > b") else println("a <= b")
if-else 표현식 조건 결과를 값으로 반환. val max = if (a > b) a else b
when 여러 조건을 확인하거나 값을 반환. when (x) { 1 -> ...; else -> ... }
범위/타입 검사 in으로 범위 확인, is로 타입 확인 가능. when (x) { in 1..10 -> ...; is String -> ... }
삼항 연산자 대체 Kotlin은 삼항 연산자를 지원하지 않아 if-else 표현식을 사용. val result = if (a > b) a else b

 

 

반복문

 

1. for 반복문

// **1. 기본 for문**
for (i in 1..5) { // 1부터 5까지 포함된 범위
    println("i = $i")
}

// **2. with step (간격 설정)**
for (i in 1..10 step 2) { // 1부터 10까지 2씩 증가
    println("i = $i")
}

// **3. downTo (역방향 반복)**
for (i in 5 downTo 1) { // 5부터 1까지 감소
    println("i = $i")
}

// **4. until (미포함 범위)**
for (i in 1 until 5) { // 1부터 4까지 (5는 포함하지 않음)
    println("i = $i")
}

// **5. 배열 및 리스트 반복**
val fruits = listOf("Apple", "Banana", "Cherry")
for (fruit in fruits) {
    println("Fruit: $fruit")
}

// **6. 인덱스와 함께 반복**
for ((index, value) in fruits.withIndex()) {
    println("Index $index: $value")
}

2. while 반복문

// **1. 기본 while문**
var count = 5
while (count > 0) {
    println("Count: $count")
    count--
}

// **2. 조건이 참일 때 실행**
val numbers = listOf(1, 2, 3, 4, 5)
var index = 0
while (index < numbers.size) {
    println("Number: ${numbers[index]}")
    index++
}

3. do-while 반복문

// **1. 기본 do-while문**
var num = 3
do {
    println("Number: $num")
    num--
} while (num > 0)

// **2. 무조건 한 번 실행**
do {
    println("This will run at least once!")
} while (false)

4. 반복문 제어 키워드

// **1. break (반복문 종료)**
for (i in 1..5) {
    if (i == 3) break // i가 3이면 반복문 종료
    println("i = $i")
}

// **2. continue (다음 반복으로 넘어감)**
for (i in 1..5) {
    if (i == 3) continue // i가 3이면 아래 코드 건너뜀
    println("i = $i")
}

// **3. 라벨(label)을 사용한 제어**
outer@ for (i in 1..3) {
    for (j in 1..3) {
        if (i == 2 && j == 2) break@outer // outer 반복문 종료
        println("i = $i, j = $j")
    }
}

5. 반복문 활용 예제

fun main() {
    // 1부터 10까지의 숫자 중 짝수만 출력
    for (i in 1..10) {
        if (i % 2 == 0) println("Even number: $i")
    }

    // 리스트 요소 출력
    val items = listOf("Kotlin", "Java", "Python")
    for (item in items) {
        println("Language: $item")
    }

    // 2중 반복문으로 구구단 출력
    for (i in 2..9) {
        for (j in 1..9) {
            print("${i * j}\t")
        }
        println()
    }

    // while문으로 합 계산
    var sum = 0
    var n = 1
    while (n <= 10) {
        sum += n
        n++
    }
    println("Sum of 1 to 10: $sum")
}

요약

반복문 설명 예제
for문 특정 범위 또는 컬렉션을 순회하며 반복. for (i in 1..5) println(i)
while문 조건이 참인 동안 반복 실행. while (x > 0) { x-- }
do-while문 조건과 관계없이 블록을 최소 한 번 실행한 후 조건을 확인. do { x-- } while (x > 0)
break 반복문을 즉시 종료. if (x == 3) break
continue 현재 반복을 건너뛰고 다음 반복 실행. if (x == 3) continue
라벨 사용 다중 반복문에서 특정 반복문을 제어. break@outer

 

 

형변환

📌 어떤 타입의 값을 다른 타입으로 변환하는 것을 말합니다. 흔히 타입 캐스팅이라고도 불립니다.

 

1. Kotlin에서의 형변환

  • Kotlin은 타입 안정성을 중시하여 명시적 형변환을 요구.
  • 형변환을 위해 toInt(), toDouble(), toString() 등의 변환 함수를 제공.
  • 안전한 형변환과 비안전한 형변환 연산자도 사용 가능.

2. 기본 형변환 (Primitive Type Casting)

// **정수형 변환**
val number = 42
val doubleValue = number.toDouble() // Int → Double
val stringValue = number.toString() // Int → String
println("Double: $doubleValue, String: $stringValue")

// **실수형 변환**
val decimal = 3.14
val intValue = decimal.toInt() // Double → Int (소수점 버림)
val longValue = decimal.toLong() // Double → Long
println("Int: $intValue, Long: $longValue")

// **문자열 변환**
val str = "123"
val parsedInt = str.toInt() // String → Int
val parsedDouble = str.toDouble() // String → Double
println("Parsed Int: $parsedInt, Parsed Double: $parsedDouble")

// **예외 처리**
val invalidStr = "abc"
val safeConversion = invalidStr.toIntOrNull() // 실패 시 null 반환
println("Safe Conversion: $safeConversion")

3. 스마트 캐스팅 (Smart Casting)

// **스마트 캐스팅이란?**
// Kotlin 컴파일러가 타입을 자동으로 추론하여 형변환을 수행.

fun printLength(obj: Any) {
    if (obj is String) { // is 연산자로 타입 검사
        println("String length: ${obj.length}") // obj는 자동으로 String으로 스마트 캐스팅
    } else {
        println("Not a String")
    }
}

printLength("Hello") // 출력: String length: 5
printLength(123)     // 출력: Not a String

4. 안전한 형변환 (Safe Casting)

// **as? 연산자 사용**
val obj: Any = "Kotlin"
val str: String? = obj as? String // 안전한 형변환 (실패 시 null 반환)
println("Safe Cast Result: $str") // 출력: Kotlin

val notString: Any = 123
val failedCast: String? = notString as? String // 실패 시 null 반환
println("Failed Cast Result: $failedCast") // 출력: null

5. 비안전한 형변환 (Unsafe Casting)

// **as 연산자 사용**
val obj: Any = "Kotlin"
val str: String = obj as String // 명시적 형변환
println("Unsafe Cast Result: $str") // 출력: Kotlin

val notString: Any = 123
// val failedCast: String = notString as String // ClassCastException 발생

6. Any, Unit, Nothing 타입

// **Any 타입**
val anyValue: Any = "This can be any type"
println("Any Value: $anyValue")

// **Unit 타입 (void와 유사)**
fun printMessage(): Unit { // 반환값이 없는 함수
    println("This function returns Unit")
}

// **Nothing 타입 (절대 반환되지 않음)**
fun throwError(): Nothing {
    throw IllegalArgumentException("This function always throws an exception")
}

7. 형변환 활용 예제

fun main() {
    // 1. 입력 값을 숫자로 변환 후 계산
    print("Enter a number: ")
    val input = readLine()?.toIntOrNull() ?: 0 // Null-safe 변환
    println("Double of your input: ${input * 2}")

    // 2. 다양한 타입을 처리하는 스마트 캐스팅
    val values: List<Any> = listOf(42, "Kotlin", 3.14, true)
    for (value in values) {
        when (value) {
            is Int -> println("$value is an Integer")
            is String -> println("$value is a String")
            is Double -> println("$value is a Double")
            else -> println("$value is of an unknown type")
        }
    }

    // 3. 안전한 형변환
    val unknown: Any = "Kotlin"
    val safeString: String? = unknown as? String
    println("Safe Cast: $safeString")
}

요약

형변환 종류 설명  예제
기본 형변환 toInt(), toDouble(), toString() 등 기본 제공 함수로 타입 변환. val x = "123".toInt()
스마트 캐스팅 is 연산자로 타입 확인 후 자동 형변환. if (obj is String) obj.length
안전한 형변환 as? 연산자로 실패 시 null 반환. val str = obj as? String
비안전한 형변환 as 연산자로 명시적 형변환, 실패 시 예외 발생. val str = obj as String
Any, Unit, Nothing Any: 모든 타입의 최상위 클래스.Unit: 반환값 없는 함수.Nothing: 반환 불가 타입. val x: Any = "Hello"

 

 

 

함수 사용

📌 특정 로직을 가지는 소스코드에 별명을 붙인 것으로, 특정 기능을 수행하는 로직을 함수라고 부릅니다.

 

1. 함수 기본 구조

// **기본 함수**
fun greet() {
    println("Hello, Kotlin!") // 출력만 수행
}

greet() // 함수 호출

2. 매개변수와 반환값이 있는 함수

// **매개변수와 반환값이 있는 함수**
fun add(a: Int, b: Int): Int { // 두 개의 정수 매개변수와 반환값(Int)을 선언
    return a + b // 두 값을 더해 반환
}

val sum = add(3, 5) // 함수 호출 후 결과를 변수에 저장
println("Sum: $sum") // 출력: Sum: 8

3. 단일 표현식 함수

// **단일 표현식 함수**
fun multiply(a: Int, b: Int): Int = a * b // 단일 식을 사용하는 함수

val product = multiply(4, 5) // 결과: 20
println("Product: $product")

4. 기본값을 가진 매개변수

// **기본값 매개변수**
fun greetUser(name: String = "Guest") {
    println("Hello, $name!")
}

greetUser("Alice") // 출력: Hello, Alice!
greetUser() // 출력: Hello, Guest!

5. 가변인자 (Varargs)

// **가변인자**
fun printAll(vararg numbers: Int) {
    for (num in numbers) {
        println(num)
    }
}

printAll(1, 2, 3, 4, 5) // 가변 개수의 매개변수를 전달

6. 함수 호출 시 이름 붙인 매개변수

// **이름 붙인 매개변수**
fun formatMessage(greeting: String, name: String): String {
    return "$greeting, $name!"
}

val message = formatMessage(greeting = "Hi", name = "Bob") // 매개변수 이름을 명시적으로 지정
println(message) // 출력: Hi, Bob!

7. 고차 함수 (함수를 매개변수로 받는 함수)

// **고차 함수**
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b) // 전달받은 함수로 계산 수행
}

val sumResult = calculate(3, 7) { x, y -> x + y } // 람다 표현식으로 함수 전달
println("Sum Result: $sumResult") // 출력: Sum Result: 10

8. 확장 함수

// **확장 함수**
fun String.addExclamation(): String {
    return this + "!" // 문자열에 느낌표 추가
}

val excited = "Kotlin".addExclamation() // 기존 String 클래스에 함수 추가
println(excited) // 출력: Kotlin!

9. 인라인 함수

// **인라인 함수**
inline fun executeInline(action: () -> Unit) {
    action() // 전달받은 함수 실행
}

executeInline { println("Inline function executed!") } // 출력: Inline function executed!

10. 지역 함수

// **지역 함수**
fun outerFunction(a: Int, b: Int): Int {
    fun innerFunction(x: Int): Int { // 외부 함수 내부에서 정의된 함수
        return x * x
    }
    return innerFunction(a) + innerFunction(b)
}

val result = outerFunction(2, 3) // 결과: 13
println("Result: $result")

11. 재귀 함수

// **재귀 함수**
fun factorial(n: Int): Int {
    return if (n == 1) 1 else n * factorial(n - 1) // 자기 자신 호출
}

val fact = factorial(5) // 결과: 120
println("Factorial: $fact")

요약

유형 설명 예제
기본 함수 입력값 없이 실행되는 함수. fun greet() { ... }
매개변수와 반환값 매개변수와 반환 타입을 지정. fun add(a: Int, b: Int): Int
단일 표현식 함수 간단한 식으로 반환값을 처리. fun multiply(a: Int, b: Int): Int = a * b
기본값 매개변수 매개변수에 기본값을 설정. fun greet(name: String = "Guest")
가변인자 여러 개의 값을 배열처럼 받을 수 있음. fun printAll(vararg nums: Int)
고차 함수 함수를 매개변수로 전달하거나 반환. fun calculate(a: Int, b: Int, op: (Int, Int) -> Int)
확장 함수 기존 클래스에 새로운 함수 추가. fun String.addExclamation(): String
인라인 함수 컴파일 시 코드가 삽입되어 성능 최적화 가능. inline fun executeInline(action: () -> Unit)
지역 함수 함수 내에 정의된 함수로 외부 함수 내부에서만 사용 가능. fun outer() { fun inner() { ... } }
재귀 함수 자기 자신을 호출하여 작업을 반복. fun factorial(n: Int): Int

 

 

 

Collection과 반복

📌 Collection은 데이터를 수집하거나 그룹화하는 자료구조입니다. Kotlin에서는 주로 List와 Map을 사용합니다.

  • List: 순서가 있는 데이터의 목록으로, 중복된 값이 포함될 수 있습니다.
  • Map: 키와 값의 쌍으로 이루어진 데이터 구조로, 각 키는 유일해야 합니다.
  • Set: 중복되지 않는 요소의 집합

1. List

// **불변 리스트**
val immutableList = listOf("Apple", "Banana", "Cherry") // 불변 리스트 (수정 불가)
println(immutableList[1]) // 인덱스로 접근 (출력: Banana)

// **가변 리스트**
val mutableList = mutableListOf("Apple", "Banana")
mutableList.add("Cherry") // 요소 추가
mutableList[0] = "Orange" // 요소 수정
println(mutableList) // 출력: [Orange, Banana, Cherry]

// **리스트 반복**
for (item in immutableList) { // for-each 반복
    println(item)
}

// **인덱스와 함께 반복**
for ((index, value) in immutableList.withIndex()) {
    println("Index $index: $value") // 출력: Index 0: Apple, Index 1: Banana, ...
}

2. Set

// **불변 집합**
val immutableSet = setOf("Apple", "Banana", "Cherry", "Apple") // 중복 허용하지 않음
println(immutableSet) // 출력: [Apple, Banana, Cherry]

// **가변 집합**
val mutableSet = mutableSetOf("Apple", "Banana")
mutableSet.add("Cherry") // 요소 추가
mutableSet.remove("Banana") // 요소 제거
println(mutableSet) // 출력: [Apple, Cherry]

// **Set 반복**
for (item in mutableSet) {
    println(item)
}

3. Map

// **불변 맵**
val immutableMap = mapOf("A" to 1, "B" to 2, "C" to 3) // 키-값 쌍 생성
println(immutableMap["B"]) // 키로 값 접근 (출력: 2)

// **가변 맵**
val mutableMap = mutableMapOf("A" to 1, "B" to 2)
mutableMap["C"] = 3 // 키-값 추가
mutableMap["A"] = 10 // 기존 키의 값 수정
mutableMap.remove("B") // 키-값 제거
println(mutableMap) // 출력: {A=10, C=3}

// **Map 반복**
for ((key, value) in immutableMap) {
    println("$key -> $value") // 출력: A -> 1, B -> 2, ...
}

4. 반복문을 사용한 컬렉션 처리

// **forEach 사용**
val fruits = listOf("Apple", "Banana", "Cherry")
fruits.forEach { fruit -> println(fruit) } // 각 요소에 대해 작업 수행

// **map을 사용한 변환**
val lengths = fruits.map { it.length } // 각 문자열의 길이를 계산
println(lengths) // 출력: [5, 6, 6]

// **filter를 사용한 조건 필터링**
val filtered = fruits.filter { it.startsWith("A") } // "A"로 시작하는 요소만 필터링
println(filtered) // 출력: [Apple]

// **flatMap으로 중첩된 리스트 처리**
val nestedList = listOf(listOf(1, 2, 3), listOf(4, 5))
val flatList = nestedList.flatMap { it } // 중첩 리스트를 단일 리스트로 변환
println(flatList) // 출력: [1, 2, 3, 4, 5]

5. 기타 컬렉션 함수

// **find: 조건에 맞는 첫 번째 요소 반환**
val firstMatch = fruits.find { it.contains("e") } // "e"를 포함하는 첫 번째 요소
println(firstMatch) // 출력: Apple

// **any: 조건에 맞는 요소가 하나라도 있으면 true**
val hasLongName = fruits.any { it.length > 5 }
println(hasLongName) // 출력: true

// **all: 모든 요소가 조건을 만족하면 true**
val allShortNames = fruits.all { it.length < 7 }
println(allShortNames) // 출력: true

// **count: 조건에 맞는 요소의 개수**
val countStartsWithB = fruits.count { it.startsWith("B") }
println(countStartsWithB) // 출력: 1

// **sort: 정렬**
val sortedFruits = fruits.sorted() // 오름차순 정렬
println(sortedFruits) // 출력: [Apple, Banana, Cherry]

// **groupBy: 조건에 따라 그룹화**
val grouped = fruits.groupBy { it.first() } // 첫 글자로 그룹화
println(grouped) // 출력: {A=[Apple], B=[Banana], C=[Cherry]}

요약

컬렉션 타입  불변 가변
List listOf("A", "B") mutableListOf("A", "B")
Set setOf("A", "B") mutableSetOf("A", "B")
Map mapOf("A" to 1, "B" to 2) mutableMapOf("A" to 1, "B" to 2)

 

반복문 사용  설명 예제
for 각 요소에 대해 순회. for (item in list) { ... }
forEach 고차 함수를 사용해 각 요소에 대해 작업 수행. list.forEach { println(it) }
map 각 요소를 변환하여 새로운 컬렉션 생성. list.map { it.length }
filter 조건에 맞는 요소만 포함한 새로운 컬렉션 생성. list.filter { it.startsWith("A") }
flatMap 중첩된 리스트를 단일 리스트로 변환. nestedList.flatMap { it }
groupBy 조건에 따라 요소를 그룹화. list.groupBy { it.first() }

 

고차함수

📌 고차 함수는 함수를 매개변수로 받거나, 함수를 반환하는 함수입니다.

  • Kotlin은 함수형 프로그래밍을 지원하며, 고차 함수는 코드의 간결성과 재사용성을 높입니다.

 

 

1. 고차 함수의 정의

// **함수를 매개변수로 받는 고차 함수**
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b) // 전달받은 함수를 호출
}

// 고차 함수 호출
val sum = calculate(5, 10) { x, y -> x + y } // 람다식으로 함수 전달
println("Sum: $sum") // 출력: Sum: 15

// **함수를 반환하는 고차 함수**
fun getOperation(type: String): (Int, Int) -> Int {
    return when (type) {
        "add" -> { x, y -> x + y } // 덧셈 함수 반환
        "multiply" -> { x, y -> x * y } // 곱셈 함수 반환
        else -> { _, _ -> 0 } // 기본값 반환
    }
}

// 반환된 함수 호출
val operation = getOperation("add")
println("Result: ${operation(3, 7)}") // 출력: Result: 10

2. 람다 표현식 (Lambda Expressions)

// **람다 기본 문법**
val add: (Int, Int) -> Int = { x, y -> x + y }
println("Add: ${add(3, 4)}") // 출력: Add: 7

// **단일 매개변수 사용**
val square: (Int) -> Int = { it * it } // `it` 키워드로 단일 매개변수 사용
println("Square: ${square(5)}") // 출력: Square: 25

// **다양한 람다 사용법**
val printMessage: (String) -> Unit = { message -> println("Message: $message") }
printMessage("Hello, Kotlin!") // 출력: Message: Hello, Kotlin!

3. 익명 함수 (Anonymous Functions)

// **익명 함수**
val subtract = fun(a: Int, b: Int): Int {
    return a - b
}

println("Subtract: ${subtract(10, 4)}") // 출력: Subtract: 6

4. 주요 고차 함수 예제

1. forEach

  • 컬렉션의 각 요소에 대해 작업 수행.
val numbers = listOf(1, 2, 3, 4, 5)
numbers.forEach { println("Number: $it") } // 각 요소 출력

2. map

  • 컬렉션의 각 요소를 변환하여 새 컬렉션 생성.
val squaredNumbers = numbers.map { it * it } // 각 요소를 제곱
println("Squared: $squaredNumbers") // 출력: Squared: [1, 4, 9, 16, 25]

3. filter

  • 조건에 맞는 요소만 포함한 새 컬렉션 생성.
val evenNumbers = numbers.filter { it % 2 == 0 } // 짝수만 필터링
println("Even Numbers: $evenNumbers") // 출력: Even Numbers: [2, 4]

4. reduce

  • 컬렉션의 모든 요소를 하나의 값으로 누적.
val sum = numbers.reduce { acc, num -> acc + num } // 요소들의 합 계산
println("Sum: $sum") // 출력: Sum: 15

5. fold

  • 초기값과 함께 컬렉션을 누적.
val sumWithInitial = numbers.fold(10) { acc, num -> acc + num } // 초기값 10 포함
println("Sum with Initial: $sumWithInitial") // 출력: Sum with Initial: 25

6. flatMap

  • 중첩된 리스트를 단일 리스트로 변환.
val nestedList = listOf(listOf(1, 2), listOf(3, 4, 5))
val flatList = nestedList.flatMap { it }
println("Flat List: $flatList") // 출력: Flat List: [1, 2, 3, 4, 5]

7. take / drop

  • 일부 요소를 선택하거나 제외.
val firstTwo = numbers.take(2) // 처음 두 요소 선택
println("First Two: $firstTwo") // 출력: First Two: [1, 2]

val dropTwo = numbers.drop(2) // 처음 두 요소 제외
println("After Drop: $dropTwo") // 출력: After Drop: [3, 4, 5]

5. 고차 함수의 장점

장점 설명
코드 간결화 반복적이고 장황한 코드 대신 고차 함수를 사용해 간결하게 작성 가능.
재사용성 고차 함수는 추상화 수준을 높여 다양한 상황에서 재사용 가능.
유연성 매개변수로 함수를 전달하여 동작을 동적으로 변경 가능.
함수형 프로그래밍 지원 Kotlin의 함수형 프로그래밍 특성을 활용하여 더 높은 수준의 코드를 작성 가능.

6. 예제: 고차 함수 활용

fun performOperation(numbers: List<Int>, operation: (Int) -> Int): List<Int> {
    return numbers.map { operation(it) }
}

// 고차 함수 사용
val doubledNumbers = performOperation(listOf(1, 2, 3, 4)) { it * 2 } // 각 숫자를 2배로
println("Doubled: $doubledNumbers") // 출력: Doubled: [2, 4, 6, 8]

val squaredNumbers = performOperation(listOf(1, 2, 3, 4)) { it * it } // 각 숫자를 제곱
println("Squared: $squaredNumbers") // 출력: Squared: [1, 4, 9, 16]

요약

항목 설명 예제
고차 함수 함수를 매개변수로 받거나 반환하는 함수. fun calculate(a: Int, b: Int, op: (Int, Int) -> Int)
람다 표현식 익명 함수의 간결한 표현으로 함수형 프로그래밍 지원. { x, y -> x + y }
주요 고차 함수 map, filter, reduce, fold, flatMap, forEach. list.map { it * 2 }
장점 코드 간결화, 유연성, 재사용성 증가.  

 

 

Nullable type

📌 null이 될 수 있는 변수를 의미한다.

  • null은 값이 없음, 값이 존재하지 않음을 의미한다. 변수를 만들었지만 그 안에 값을 넣지 않은 경우를 흔히 말한다.
  • Kotlin에서 모든 타입은 기본적으로 NULL을 허용하지 않는다. 다만 타입에 ? 을 명시하면 사용이 가능하다.

1. Nullable 타입 선언

// **Nullable 타입 선언**
var name: String? = null // `?`를 사용해 Null을 허용
name = "Kotlin" // Null이 아닌 값 할당 가능
println(name) // 출력: Kotlin

// **Non-null 타입**
var nonNullableName: String = "Hello"
// nonNullableName = null // 컴파일 에러: Null 불허

2. Null 안전성 연산자

1) Safe Call Operator (?.)

  • Null 값을 허용하는 변수에서 안전하게 프로퍼티나 메서드를 호출.
val nullableName: String? = null
println(nullableName?.length) // 출력: null (예외 발생 없이 안전)

val nonNullName: String? = "Kotlin"
println(nonNullName?.length) // 출력: 6

2) Elvis Operator (?:)

  • Null 값일 경우 기본값을 반환.
val nullableText: String? = null
val result = nullableText ?: "Default Value" // Null이면 "Default Value" 반환
println(result) // 출력: Default Value

3) Non-null Assertion Operator (!!)

  • 변수 값이 Null이 아니라고 확신할 때 사용.
  • Null일 경우 NullPointerException 발생.
val nullableString: String? = "Kotlin"
println(nullableString!!.length) // 출력: 6

val nullValue: String? = null
// println(nullValue!!.length) // NullPointerException 발생

3. Nullable 타입 활용

1) if 문을 사용한 Null 체크

  • Null 여부를 확인하여 처리.
val str: String? = null
if (str != null) {
    println("Length: ${str.length}")
} else {
    println("String is null")
}

2) Smart Casting (is)

  • Kotlin은 Null 체크 후 해당 변수의 타입을 자동으로 변환(스마트 캐스팅).
val nullable: String? = "Kotlin"
if (nullable is String) {
    println("Length: ${nullable.length}") // 스마트 캐스팅으로 안전하게 호출
}

4. Safe Call with Let

  • **let**은 Null 값을 제외하고 실행할 코드를 작성 가능.
val nullableValue: String? = "Hello"
nullableValue?.let { println("Length: ${it.length}") } // 출력: Length: 5

val nullValue: String? = null
nullValue?.let { println(it) } // 아무 작업도 수행하지 않음

5. Nullable 타입과 컬렉션

1) 컬렉션에 Nullable 타입 포함

  • 컬렉션에 Null 값을 허용.
val list: List<String?> = listOf("A", null, "C")
println(list) // 출력: [A, null, C]

2) Null 값 필터링

  • 컬렉션에서 Null 값을 제거.
val nullableList: List<String?> = listOf("A", null, "C")
val nonNullList = nullableList.filterNotNull() // Null 제거
println(nonNullList) // 출력: [A, C]

6. Nullable 타입 예제

fun printLength(text: String?) {
    val length = text?.length ?: 0 // Null이면 0 반환
    println("Length: $length")
}

fun main() {
    printLength("Kotlin") // 출력: Length: 6
    printLength(null) // 출력: Length: 0

    // Safe call과 let 활용
    val message: String? = "Hello Kotlin"
    message?.let { println("Message length: ${it.length}") } // 출력: Message length: 12
}

요약

연산자/기법 설명 예제
Safe Call (?.) Null일 경우 호출하지 않고 Null 반환. nullable?.length
Elvis Operator (?:) Null일 경우 기본값 반환. val result = nullable ?: "Default"
Non-null Assertion (!!) Null이 아니라고 확신할 때 사용, Null이면 예외 발생. nullable!!.length
if 문을 사용한 체크 Null 여부를 확인하여 안전하게 처리. if (str != null) { ... }
Smart Casting (is) Null 체크 후 자동으로 Non-null 타입으로 변환. if (nullable is String) { ... }
let 블록 사용 Null이 아닌 경우에만 코드 블록 실행. nullable?.let { println(it.length) }
Null 필터링 컬렉션에서 Null 값을 제거. list.filterNotNull()

 

 

예외 처리

📌 예외(Exception)는 프로그램 실행 중 발생하는 오류 상황을 말하며 이런 상황에 대한 대응을 예외 처리라 한다.

  • Kotlin은 try-catch-finally 블록을 사용하여 예외를 처리.
  • 모든 예외는 Throwable 클래스를 상속받음.

 

1. try-catch 블록

// **기본 구조**
try {
    // 예외 발생 가능성이 있는 코드
    val number = "abc".toInt() // 문자열을 정수로 변환하려다 예외 발생
    println("Number: $number")
} catch (e: NumberFormatException) {
    // 예외 처리
    println("Exception occurred: ${e.message}")
}

// **결과**
// 출력: Exception occurred: For input string: "abc"

2. 여러 catch 블록

try {
    val result = 10 / 0 // ArithmeticException 발생
    println("Result: $result")
} catch (e: ArithmeticException) {
    println("ArithmeticException: Division by zero is not allowed.")
} catch (e: Exception) {
    println("Generic Exception: ${e.message}")
}

// **결과**
// 출력: ArithmeticException: Division by zero is not allowed.

3. finally 블록

// **try-catch-finally 구조**
try {
    val value = "123".toInt() // 정상적으로 실행
    println("Value: $value")
} catch (e: Exception) {
    println("Exception: ${e.message}")
} finally {
    // 예외 발생 여부와 관계없이 항상 실행
    println("Finally block executed.")
}

// **결과**
// 출력:
// Value: 123
// Finally block executed.

4. 예외 발생시키기 (throw)

// **throw 키워드로 예외 발생**
fun divide(a: Int, b: Int): Int {
    if (b == 0) throw IllegalArgumentException("Division by zero is not allowed.") // 예외 발생
    return a / b
}

try {
    println(divide(10, 0)) // 예외 발생
} catch (e: IllegalArgumentException) {
    println("Caught Exception: ${e.message}")
}

// **결과**
// 출력: Caught Exception: Division by zero is not allowed.

5. 사용자 정의 예외

// **사용자 정의 예외 클래스**
class CustomException(message: String) : Exception(message)

fun checkValue(value: Int) {
    if (value < 0) throw CustomException("Negative values are not allowed.") // 사용자 정의 예외 발생
}

try {
    checkValue(-10) // 예외 발생
} catch (e: CustomException) {
    println("Custom Exception: ${e.message}")
}

// **결과**
// 출력: Custom Exception: Negative values are not allowed.

6. 예외 처리와 Null 안전성

// **toIntOrNull 사용으로 Null 안전 처리**
val number = "abc".toIntOrNull() ?: 0 // 변환 실패 시 Null 반환
println("Number: $number") // 출력: Number: 0

7. 예외 처리 활용 예제

fun readNumber(): Int {
    print("Enter a number: ")
    val input = readLine()
    return try {
        input?.toInt() ?: 0 // 입력값을 정수로 변환, 실패 시 0 반환
    } catch (e: NumberFormatException) {
        println("Invalid number format: ${e.message}")
        -1 // 예외 발생 시 -1 반환
    }
}

val result = readNumber()
println("Result: $result")

8. 예외 처리의 주요 키워드

키워드 설명 예제
try 예외 발생 가능성이 있는 코드를 실행. try { ... }
catch 발생한 예외를 처리. catch (e: Exception) { ... }
finally 예외 발생 여부와 관계없이 항상 실행되는 코드. finally { ... }
throw 예외를 명시적으로 발생. throw IllegalArgumentException("Error")
toIntOrNull 예외 없이 문자열을 안전하게 정수로 변환, 실패 시 Null 반환. "123".toIntOrNull()

9. 예외 처리의 장점

장점 설명
프로그램 안정성 유지 예외를 처리하여 프로그램이 중단되지 않고 계속 실행 가능.
문제 디버깅 용이 예외 메시지를 통해 문제를 정확히 파악 가능.
NullPointerException 방지 Kotlin의 toIntOrNull 등 Null 안전 기능과 결합하여 예외를 줄임.

 

'Back-End (Web) > Kotlin' 카테고리의 다른 글

[Kotlin] Kotlin의 테스트코드  (0) 2025.02.16
[Kotlin] Kotlin의 객체지향  (0) 2025.02.12
[Kotlin] Kotlin이란?  (0) 2025.02.10

+ Recent posts