ABOUT ME

작은 디테일에 집착하는 개발자

Today
-
Yesterday
-
Total
-
  • [Kotlin] 코틀린 중급 (feat. 람다, 확장함수, Scope function, 초기화 지연 등...)
    IT Study/Android 2024. 1. 15. 15:37
    728x90

    람다

    package fastcampus.part0.kotlin
    
    fun main() {
        // 1. 람다
        // 익명 함수 (일회용 함수)
        // 변수처럼 사용할 수 있다. (함수의 argument, return으로 사용)
        val a = fun() { println("hi") }
        val b: (Int) -> Int = { it * 10 } // (input) -> return = { 함수 구현부 }
        val c = { i: Int, j: Int -> i * j } // { input -> 함수 구현부 }
        val d: (Int, String, Boolean) -> String = { _, string, _ -> string } // _ : 미사용 파라미터
    
        a()
        println(b(10))
        println(c(2, 5))
        println(d(3, "three", true))
    
        hello(10, b)
        println(hello2(20, b))
    }
    
    // 1-1. 함수의 argument로 사용
    fun hello(n: Int, m: (Int) -> Int) {
        print("$n ")
        println(m(20))
    }
    
    // 1-2. 함수의 return으로 사용
    fun hello2(n: Int, m: (Int) -> Int): (Int) -> Int {
        print("$n ")
        println(m(30))
        return m
    }
    package fastcampus.part0.kotlin
    
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.view.View
    
    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            // 1-3. 람다 특징 : 일회용 함수
            // View에서 setOnClickListener 사용 시, SAM interface로 구현
    
            // SAM (Single Abstract Method, 단일 추상 메서드)
            // SAM 인터페이스 : 단 하나의 추상 메서드를 가진 인터페이스 (ex : setOnClickListener)
            // Kotlin에서는 SAM 인터페이스를 아래와 같이 람다식으로 표현 가능
    
            val view = View(this)
    
            // 1-3-1. 직접 구현
            // 익명 클래스를 통해 OnClickListener 설정
    //        view.setOnClickListener(
    //            new View . OnClickListener () {
    //                @Override
    //                public void onClick(View: View) {
    //                    // 클릭 시 수행할 동작을 구현
    //                }
    //            }
    //        )
    
            // 1-3-2. 간단 표현
            // 람다식을 통해 OnClickListener 설정
            // {} 를 통해 OnClickListener의 onClick 함수 표현
            view.setOnClickListener {}
        }
    }

     

    확장함수

    package fastcampus.part0.kotlin
    
    fun main() {
        // 2. 확장함수 (기존 정의 클래스에 함수를 추가하는 기능)
        Test().hello()
        Test().bye()
    
        val test = Test()
        test.thank()
    }
    
    // Test 클래스에 thank라는 함수를 추가하는 것과 동일한 형태
    fun Test.thank() = println("thank u")
    
    class Test() {
        fun hello() = println("hi")
        fun bye() = println("bye")
    }

     

    범위 지정함수 (Scope function, 스코프 함수)

    스코프 함수는 특정 객체에 대한 연산을 범위 안에서 수행할 수 있도록 돕습니다.

    수신객체 확장함수로 호출 함수의 인자
    this apply run with
    it also let  
    return 수신객체 람다식의 마지막 행
    package fastcampus.part0.kotlin
    
    fun main() {
        // 3. 범위 지정함수 (Scope function) : let, run, apply, also, with
    
        // 1. let : null 체크 시, 명시적으로 지역 변수 표현 시
        // 수신객체.let { it ->
        //     ...
        //     마지막 줄 // return
        // }
        val person = Person("김한슬", 24, true, false)
        val name = person.let {
            person.name
        }
        println(name)
    
        // 2. run : 객체 초기화 및 리턴 값이 있을 경우
        // 수신객체.run { this ->
        //     ...
        //     마지막 줄 // return
        // }
        val kid = Person("아이", 3, false, false)
        val kidAge = kid.run {
            age // 이름 없이 직접 접근 가능
        }
        println(kidAge)
    
        // 3. apply : 객체 초기화 시
        // 수신객체.apply { this ->
        //     ...
        //     마지막 줄 // return 수신객체 (자기 자신)
        // }
        val female = Person("한슬", 26, true, true)
        val femaleValue = female.apply {
            hasGlasses = false
            // return 수신객체 (자기 자신)
        }
        println(femaleValue.hasGlasses) // true → false 변경
    
        // 4. also : 명시적으로 수신객체를 사용하거나 로그 남길 경우
        // 수신객체.also { it ->
        //     ...
        //     마지막 줄 // return 수신객체 (자기 자신)
        // }
        val male = Person("완재", 29, false, false)
        val maleValue = male.also {
            println(it.name)
        }
    
        // 5. with : 객체 초기화, 람다의 리턴 값이 필요하지 않을 경우
        // with(수신객체) { this ->
        //     ...
        //     마지막 줄
        // }
        val result = with(male) {
            hasGlasses = true
            true
        }
        println(result)
    }
    
    class Person(
        val name: String,
        val age: Int,
        val gender: Boolean,
        var hasGlasses: Boolean,
    )

     

    초기화 지연

    val test = 100

    프로그램 시작 시점에 변수가 초기화됩니다.

    변수의 초기화가 빠르고, 메모리 사용량이 크게 문제가 되지 않으며,
    해당 변수가 프로그램 실행 동안 반드시 필요한 경우에 사용합니다.

    즉, 프로그램 실행 초기부터 변수의 값을 필요로 하는 경우에 적합합니다.

    val test: Int by lazy { 100 }

    변수가 처음 호출될 때 초기화됩니다.

    변수의 초기화 비용이 크거나, 초기화 과정이 복잡하거나,
    해당 변수가 프로그램 실행 중에 항상 필요하지 않은 경우에 사용합니다.
    예를 들어, 초기화 작업이 시간이 많이 소요되거나 많은 리소스를 필요로 하는 경우,
    또는 해당 변수를 사용하는 경우가 프로그램 실행 중에 가끔 발생하는 경우에 lazy를 사용하는 것이 효율적입니다.

    이렇게 하면 메모리 사용량을 줄이고, 불필요한 초기화 작업을 피하여 성능을 향상시킬 수 있습니다.
    package fastcampus.part0.kotlin
    
    // 4. 초기화 지연 (lateinit, lazy)
    // 변수 선언 시 값을 지정하지 않고, 나중에 지정하 사용
    // 특징 : 효율적인 메모리 사용, null safe 사용
    
    // 4-1. lateinit var(변수 타입 지정 필수, 선언 후 사중에 초기화 가능)
    lateinit var text: String
    
    // 원시 타입 (primitive type) 불가 : boolean, 정수, 실수, 문자
    // lateinit var age: Int
    
    // 4-2. lazy val (선언과 동시에 초기화 필수, 호출 시점에 이뤄지는 초기화)
    val test: Int by lazy {
        println("초기화 중")
        100
    }
    
    fun main() {
        text = "name"
        println(text)
    
        println("메인 함수 실행")
        println("첫 번째 호출 $test") // 첫 호출 시, 초기화
        println("두 번째 호출 $test") // ∴ "초기화 중" 생략
    }

     

    data class, sealed class

    package fastcampus.part0.kotlin
    
    // 5-1. data class : 데이터를 담기 위한 클래스
    // toString, hashCode, equals, copy 메서드 자동 생성
    // 1개 이상의 프로퍼티 필요 (val 변수: 타입, ...)
    // abstract, open, sealed, inner 키워드 사용 불가
    // 상속 불가
    
    // 5-2. sealed class
    // 추상 클래스, 상속받은 자식의 종류를 제한
    // when과 사용
    
    fun main() {
        // 5-1. data class
        val person = People("한슬", 24)
        val dog = Dog("도그", 2)
    
        println(person) // 주소
        println(dog)   // 데이터
    
        // toString()으로 인해
        // basic    : Dog(name=도그, age=2)
        // override : 이름=도그, 나이=2
    
        println(dog.copy(age = 3))
    
        // 5-2. sealed class
        val cat: Cat = BlackCat()
        val result = when (cat) {
            is BlackCat -> "black"
            is RedCat -> "red"
            is WhiteCat -> "white"
            // abstract → sealed 변경 : else 문 redundant (불필요)
            // else -> "etc"
        }
        println(result)
    }
    
    class People(
        val name: String,
        val age: Int,
    )
    
    class Whale()
    
    data class Dog(
        val name: String,
        val age: Int
    ) {
        override fun toString(): String {
            return "이름=$name, 나이=$age"
        }
    }
    
    // abstract 시, 컴파일러는 Cat을 상속받은 하위 클래스를 알지 못한다.
    // abstract class Cat
    
    // sealed 시, 컴파일러는 Cat을 상속받은 하위 클래스를 알고 있다.
    // 하위 클래스가 추가될 경우, 컴파일러는 해당 하위 클래스를 인지하여 추가 구현되어야 하는 부분을 알려줄 수 있다.
    sealed class Cat
    class BlackCat : Cat()
    class RedCat : Cat()
    class WhiteCat : Cat()

     

    object, companion object

    package fastcampus.part0.kotlin
    
    import fastcampus.part0.kotlin.Book.Companion.NAME
    
    // 6-1. object : 클래스 정의와 동시에 객체 생성 (ex : error code)
    fun main() {
        // 6-1-1. 싱글톤 (객체의 인스턴스 오직 1개 생성, 고정된 메모리 영역을 사용) 생성 용이
        println(Counter.count) // 초기화 + 0 출력
        Counter.countUp()
        Counter.countUp()
        println(Counter.count) // 2
    
        Counter.hello()
    
        // 6-2-1. 클래스명으로 바로 접근 가능
        NAME
        Book.create()
    }
    
    // 6-1-2. 생성자 사용 불가
    // 6-1-4. 다른 클래스/인터페이스 상속 받기 가능
    object Counter: Hello() {
        // 6-1-3. 프로퍼티, 메서드, 초기화 블록 사용 가능
        var count = 0
        init {
            println("카운터 초기화")
        }
        fun countUp() {
            count++
        }
    }
    
    open class Hello() {
        fun hello() = println("hello")
    }
    
    // 6-2. companion object (Java의 static과 동일)
    // 클래스 내 오직 하나만 생성 가능
    class Book {
        companion object {
            val NAME = "Three"
            fun create() = Book()
        }
    }
Designed by Tistory.