DBILITY

kotlin fundamental summary ( 기초정리 ) 본문

android/kotlin

kotlin fundamental summary ( 기초정리 )

DBILITY 2023. 8. 30. 10:58
반응형

기초 실습은 웹에서 가능하다.

https://play.kotlinlang.org/

 

Kotlin Playground: Edit, Run, Share Kotlin Code Online

 

play.kotlinlang.org

확장자 kt로 jvm에서 실행된다.

언제나 그렇듯 main 함수가 프로그램의 entry point다.

fun키워드로 함수를 정의한다.

리턴타입이 없으면 Unit( java void에 대응되는)을 지정한다. 안해도 된다. object pascal의 unit이 생각난다..그립다 델파이.

package com.dbility.apps.kotlinpractice

fun main() {
    helloWorld()
}

fun helloWorld(): Unit {
    println("Hello World!")
}

상수(값)는 val ( value ), 변수는 var (variable) 로 선언한다. val은 java의 final과 같다.static final이 아니라서 그런가? 상수는 아니라는데..뭥미...누구말이 맞는겨.ㅋㅋ companion object 안에 const val로 선언하면 static final과 같음?

타입은 상수나 변수명 뒤에 콜론 다음에 지정한다. Byte,Short,Int ,Long,Float,Double,String,Char,Boolean 모두 객체다는 점을 기억하자.java는 primitive도 있는데 말이다.

자료형을 명시하지 않으면 알아서 추론한다. 할당하는 값(리터럴)에 따라서. String은 쌍따옴표, Char은 홑따옴표를 쓴다.

package com.dbility.apps.kotlinpractice

fun main():Unit {
    welcome()
    var age: Int = 100
    var x = 1
    var y = 1
    var z = add(x,y)
    var loremIpsum = """모든 국민은 법 앞에 평등하다. 누구든지 성별·종교 또는 사회적 신분에 의하여 정치적·경제적·사회적·문화적 생활의 모든 영역에 있어서 차별을 받지 아니한다.

피고인의 자백이 고문·폭행·협박·구속의 부당한 장기화 또는 기망 기타의 방법에 의하여 자의로 진술된 것이 아니라고 인정될 때 또는 정식재판에 있어서 피고인의 자백이 그에게 불리한 유일한 증거일 때에는 이를 유죄의 증거로 삼거나 이를 이유로 처벌할 수 없다.

모든 국민은 능력에 따라 균등하게 교육을 받을 권리를 가진다. 국가는 사회보장·사회복지의 증진에 노력할 의무를 진다. 정당은 법률이 정하는 바에 의하여 국가의 보호를 받으며, 국가는 법률이 정하는 바에 의하여 정당운영에 필요한 자금을 보조할 수 있다.

공무원인 근로자는 법률이 정하는 자에 한하여 단결권·단체교섭권 및 단체행동권을 가진다. 국가는 노인과 청소년의 복지향상을 위한 정책을 실시할 의무를 진다.

대한민국의 경제질서는 개인과 기업의 경제상의 자유와 창의를 존중함을 기본으로 한다. 이 헌법공포 당시의 국회의원의 임기는 제1항에 의한 국회의 최초의 집회일 전일까지로 한다.

국가원로자문회의의 의장은 직전대통령이 된다. 다만, 직전대통령이 없을 때에는 대통령이 지명한다. 정당은 그 목적·조직과 활동이 민주적이어야 하며, 국민의 정치적 의사형성에 참여하는데 필요한 조직을 가져야 한다.
""".trimMargin()
    println("I am ${age} years old.${x}+${y}=${z}")
    println(loremIpsum)
}

fun welcome():Unit {
    println("hello kotlin!")
}

fun add(x:Int,y:Int) : Int {
    return x+y
}

문자열을 여러줄 쓸때 쌍따옴표 3개로 묶는다. javascript에 뭐더라 backtick ( ` ) 과 같다.

문자열의 비교는 == (equals)를 쓴다. Object비교는 === 요걸 쓴다. 언어마다 돌아버리겠다ㅋㅋ

타입 뒤에 물음표(?)를 붙이여 Nullable Type이 되어 Null을 할당 할 수 있다. 물론 타입없이 선언하면 타입추론이 되고  Nullable이다.

타입을 명시하는 경우는 Non-Null Type이다. 객체를 불변으로 간주하니 null허용에 주의해야 하겠다.

    var name: String = "john"
    var lastName = null
    var middleName: String? = null

문장마다 세미콜론(;)이 필요하지 않다. 써도 되긴 한다.

연산자중에 삼항연산의 축약(?)버전이 존재한다. ?: Elvis operator라고 하는데 모양이 Elivis Presley 머리모양이 연상된다나 어쩐다나..무튼 영구변수?:"영구없다" 로 쓰면 영구변수가 Null인 경우 영구없다를 반환하는거다ㅋ 재미있군

    var 영구변수:String?=null;
    println(영구변수?:"영구없다")

javascript의 Nullable 연산자와 같이 ?. 도 된다.  변수?.메서드() 형태로 쓰면 되겠다. 변수가 Null이면 null 아니면 메서드()를 실행한다.

!!로 Nullable변수가 현재 Null이 아님을 컴파일러에 고지 할 수 있다. 말이 이상하군 Nullable 변순데 지금은 Null값이 들어 있지 않아..그러니까 Null Point Exception 뿜지마~ 내가 보증한다~guarantee?정도 되겠다. 사용할때 변수뒤에 !!를 적는다. 근데 정말 확실한 경우가 아니면 쓰면 안되겠다. 너 자신을 믿지마라. 

package com.dbility.apps.kotlinpractice

fun main() {
    println("===================")

    var 영구변수:String?=null;
    println(영구변수?:"영구없다!")

    myPrint(영구변수)
}

fun myPrint(영구변수:String?) {
    println(영구변수!!)
}

let method는 확장함수로 변수를 block 안으로 토스해 준다. 그냥 그정도만 null safety로 사용하지는 말라고 한다.

    //var 영구변수:String?=null;
    var 영구변수:String?="i am 09";
    println(영구변수?.uppercase())
    영구변수?.let{
        myPrint(it)
    }
    //Elvis도 된다..
    영구변수?.let{
        myPrint(it)
    }?:run {
        println("영구어따~")
    }
    
fun myPrint(영구변수:String?) {
    println(영구변수!!)
}

let처럼 객체를 사용할때 일시적으로 Scope를 만들어서 property나 method를 사용할 수 있게 해주는게 with, run, apply , also가 있다고 한다. with이 특이하다. 아래 코드를 보면 바로 이해가 되면 좋겠다.  also가 뭔가 이상하다.ㅋㅋ

fun main() {	    
    var price = 10000
    
    val food = Food("드럽게 매운 짬뽕",3, 9000).apply {
        name = "[타임세일] "+ name
        discount()
    } // apply 인스턴스를 그대로 반환하며 it,this참조없이 property,method에 접근
    
    food.run {
        println("주문명 : ${name} , 수량 : ${amount}, 단가 : ${price}, 합계 : ${ amount*price }")
    } // run 인스턴스 반환없이 마지막 라인 리턴, 참조없이 property,method에 접근 
    
    with(food) {
        println("주문명 : ${name} , 수량 : ${amount}, 단가 : ${price}, 합계 : ${ amount*price }")
    } // 객체를 파라미터로 나머지는 run과 같음
    
    food.let {
        println("주문명 : ${it.name} , 수량 : ${it.amount}, 단가 : ${it.price}, 합계 : ${ it.amount*it.price }")
    } // 객체 접근에 it을 사용, 마지막 라인 리턴
    
    val food2 = Food("드럽게 매운 짬뽕",3, 9000).also {
        it.name = "[쇼킹딜] "+ it.name
        it.discount()
    } // also 인스턴스를 그대로 반환하며 property를 전혀 사용하지 않거나 변경하지 않는 경우에 사용
    
    food2.run {
        println("주문명 : ${name} , 수량 : ${amount}, 단가 : ${price}, 합계 : ${ amount*price }")
    } // run 참조없이 property,method에 접근
}

class Food(var name: String, var amount: Int ,var price: Int) {
    
    fun discount() {
        price-=2000
    }
}

/*
주문명 : [타임세일] 드럽게 매운 짬뽕 , 수량 : 3, 단가 : 10000, 합계 : 30000
주문명 : [타임세일] 드럽게 매운 짬뽕 , 수량 : 3, 단가 : 10000, 합계 : 30000
주문명 : [타임세일] 드럽게 매운 짬뽕 , 수량 : 3, 단가 : 7000, 합계 : 21000
주문명2 : [쇼킹딜] 드럽게 매운 짬뽕 , 수량 : 3, 단가 : 10000, 합계 : 30000
*/

여느 언어처럼 String Format(문자열템플릿)은 그렇다.그냥 쓰면 된다. concatenation도 비슷하고, 특수문자로 $를 그대로 출력하는 것도 백슬래시(\)를 쓰니 비슷하다.

package com.dbility.apps.kotlinpractice

fun main() {
    var firstName = "캔디스"
    var middleName = "화이트"
    var lastName = "아드레이"
    var nickName = "캔디"

    println("내이름은~ 내이름은~ 내이름은 ${nickName}, 정식이름은 '${"$firstName $middleName $lastName"}'입니다")
}

늦은 초기화는 var은 lateinit, val은 lazy를 써야한다.

조건문도 비슷하다. if는 당연히 그렇고, switch case는 when else로 사용을 한다. else는 switch의 default라고 보면 되겠다. 특이하게도 범위(range)를 in 키워드로 줄 수 있다.이건 그냥 혹시나 해서 해봤다ㅋㅋ

package com.dbility.apps.kotlinpractice

fun main() {

    var x = 0
    var y = 1
    if (x > y)
        println("x가 y보다 크다")
    else if (x < y)
        println("x가 y보다 작다")
    else
        println("x는 y와 같다")

    when (x) {
        1 -> {
            println("x는 ${x}다")
        }

        in 2..9 -> println("x는 2와 9사이다")
        else -> {
            println("꺼져~")
        }
    }

}

배열은 arrayOf로 생성하나? Generic도 되나 보다. 복합적인 경우는 Any다..아무거나군.

헌데 for가 뭔가 이상하다. foreach네~ 범위의 지정은 0..10 형태다. 이게 도스 베이직도 그랬었나?ㅋㅋ아닌가

package com.dbility.apps.kotlinpractice

fun main() {
    
    val array : Array<Int> = arrayOf(1,2,3,4,5)    
    for (i in array) {
        println(i)
    }

	val array2 : Array<Any> = arrayOf(1,"two",3f,4.2f)
    for (j in array2) {
        println(j)
    }

}

java에서 많이 쓰는 List는 kotlin에서는 immutable이다 수정하고 싶다면 mutableList를 사용해야 한다.

List는 interface라서 그렇다고 한다. 생성은 listOf로 한다. 

mutableList는 arrayListOf로 생성하고, Type은 ArrayList가 되겠다.

그런데 mutableListOf가 따로 있고 Type은 MutableList가 있다.

size속성으로 크기를 알아 낼 수 있다. 순회할때 역방향으로는 downTo를 쓰면 되겠다.

인덱스는 0부터니 마지막 번호는 size-1해야한다. 다른 방법으론 until을 쓰면 된다. step은 순회시 간격이다.

Array,List,ArrayList 모두 withIndex()로 index와 value를 같이 추출할 수 있다.

package com.dbility.apps.kotlinpractice

fun main() {
   
    val list: List<Int> = listOf(1, 2, 3)
    for (i in list) {
        println(i)
    }

    for (i in 0..list.size - 1) {
        println(list.get(i))
    }

    println("----------")

    val arrayList: ArrayList<String> = arrayListOf<String>("일", "이", "삼")
    for (i in arrayList) {
        println(i)
    }

    println("----------")

    arrayList.add("사")

    for (i in arrayList) {
        println(i)
    }

    println("----------")

    for (i in 0 until arrayList.size step 2) {
        println(arrayList[i])
    }

    println("----------")

    for (i in arrayList.size-1 downTo 0 step 2) {
        println(arrayList[i])
    }
    
    println("----------")
    
    for((index,value) in arrayList.withIndex()) {
        println("arrayList[$index]=$value")
    }
    
    println("----------")
    
    val list: MutableList<Int> = mutableListOf(1, 2, 3)
    for (ele in list) {
        println(ele)
    }
    list[0] = 10;

    for (ele in list) {
        println(ele)
    }
    
    val arrayList2: ArrayList<Int> = arrayListOf<Int>(4, 5, 6);
    for (ele in arrayList2) {
        println(ele)
    }
    arrayList2[0]=7
    for (ele in arrayList2) {
        println(ele)
    }
}

arrayList를 val(상수)로 선언한 이유? 어차피 call by reference일텐데 shallow & deep copy관련 이슈를 알고 있다면 바로 이해되겠다. 상수의 값을 참조하는게 아니니까!

여타 언어와 같이 while 조건이 만족하면 순회하고, do~while은 내부 문장을 우선 1회 순회 후 조건을 비교한다.

package com.dbility.apps.kotlinpractice

fun main() {
    
    val arrayList: ArrayList<String> = arrayListOf<String>("일", "이", "삼")    

    println("----------")

    var index = 0
    while (index < arrayList.size) {
        println(arrayList[index])
        index++
    }

    println("----------")

    index = 0
    do {
        println(arrayList[index])
        index++
    } while (index < arrayList.size)
    
}

List와 마찬가지로 Map도 지원한다. mapOf로 immutableMap을 mutableMapOf로 mutableMap을 생성 할 수 있다.

Spring framework Repository 데이터를 받아오는 경우라면
List<Map<String,Object>> selectList = new ArrayList<Map<String,Object>>(); 이렇게 했던가...ㅋㅋ 기억이..

fun main() {

    val list: List<Map<String, Any>> = listOf(
        mapOf("id" to 0, "name" to "영구"),
        mapOf("id" to 1, "name" to "땡칠이")
    )

    for (map in list) {
        println(map)
        //println("${map["id"]} = ${map["name"]}")
    }
    
    println("----------")

    for (map in list) {
        for ((key, value) in map) {
            println("${key} = ${value}")
        }
    }
}

/*
{id=0, name=영구}
{id=1, name=땡칠이}
----------
id = 0
name = 영구
id = 1
name = 땡칠이
*/

set(집합)도 있으니 검색해서 보면 된다.

class의 기본은 그냥 그렇다...다음과 같다 constructor가 좀 특이하다. 다중 constructor도 그렇고 어차피 Usage가 다를뿐.

class 선언시 클래스명 뒤에 오는 constructor가 primary라는데 여기서는 val,var로 parameter선언이 되는데 나머지 class내부에 선언되는 sencondary에는 그냥 변수명:변수형으로만 주면 된다. java에서는 어쨌더라...secondary처럼 했던가ㅋ

생성할때 new가 필요없다.

package com.dbility.apps.kotlinpractice

fun main() {

    val 너 = 인간()
    너.오빠달려();
    println("내 이름은 ${너.이름}")

    val 나 = 인간("이순신", 478)
}

class 인간 constructor(val 이름: String = "아무개") {

    constructor(이름: String, 나이: Int) : this(이름) {
        println("${나이}세 ${이름}이 나타났다")
    }

    init {
        println("인간이 나타났다")
    }

    fun 오빠달려() {
        println("너나 달려~~~~~~~~~~~~~~~")
    }
}

//아래는 실행결과
인간이 나타났다
너나 달려~~~~~~~~~~~~~~~
내 이름은 아무개
인간이 나타났다
478세 이순신이 나타났다

init가 constuctor보다 먼저 실행된다. 테스트 해보니 그렇다.

package com.dbility.apps.kotlinpractice

fun main() {

    val 나 = 사람();
    val 너 = 사람("홍길동");
    val 누구 = 사람("이순신", 478);

    나.누구냐너();
    너.누구냐너();
    누구.누구냐너();

}

class 사람 {
    var 이름: String? = "아무개"
    var 나이: Int? = 999999;

    constructor()

    constructor(이름: String) {
        this.이름 = 이름
    }

    constructor(이름: String, 나이: Int) : this(이름) {
        this.나이 = 나이
    }

    init {
        println("init ${this} ${this.이름}이(가) 태어났다.${this.나이}살이다")
    }

    fun 누구냐너(){
        println("${this} ${this.이름}이(가) 태어났다.${this.나이}살이다")
    }
}

/*
init 사람@677327b6 아무개이(가) 태어났다.999999살이다
init 사람@12a3a380 아무개이(가) 태어났다.999999살이다
init 사람@29453f44 아무개이(가) 태어났다.999999살이다
사람@677327b6 아무개이(가) 태어났다.999999살이다
사람@12a3a380 홍길동이(가) 태어났다.999999살이다
사람@29453f44 이순신이(가) 태어났다.478살이다
*/

 

class의 상속은 부모 클래스가 private final인지 상속(상속금지)하려면 open이라는 keyword를 class앞에 써줘야 한다.

method도 overriding하려면 open을 써줘야 한다. 부모 method 앞에.. 말이 이상하지만ㅋ 맞나?!

package com.dbility.apps.kotlinpractice

fun main() {

    val 너 = 인간()
    너.오빠달려();
    println("내 이름은 ${너.이름}")

    val 나 = 인간("이순신", 478)

    var 아빠 = 아빠();
    아빠.오빠달려();

}

open class 인간 constructor(val 이름: String = "아무개") {

    constructor(이름: String, 나이: Int) : this(이름) {
        println("${나이}세 ${이름}이 나타났다")
    }

    init {
        println("인간이 나타났다")
    }

    open fun 오빠달려() {
        println("너나 달려~~~~~~~~~~~~~~~")
    }
}

class 아빠 : 인간()  {

    init {
        println("${이름}(이)라는 인간이 나타났다")
    }

    override fun 오빠달려() {
        println("아빠한테 오빠달려를 호출하다니 override된거다 ~~~~~~~~~~~~~~~")
    }
}

//아래는 실행결과
인간이 나타났다
너나 달려~~~~~~~~~~~~~~~
내 이름은 아무개
인간이 나타났다
478세 이순신이 나타났다
인간이 나타났다
아무개(이)라는 인간이 나타났다
아빠한테 오빠달려를 호출하다니 override된거다 ~~~~~~~~~~~~~~~

sub(child) class가 생성되면 super(parent) class부터 init가 실행된다. java는 최상위가 Object였는데 kotlin은 Any class란다

java처럼 filed마다 getter,setter를 만들어 주지 않아도 자동 생성된다.

val이면 private에 gettter만 var이면 private에 getter,setter가 생성된다.

물론, 별도로 줄 수 도 있다. 필드를 선언할때 아래 처럼 해주면 된다.

fun main() {

    val 나 = 사람();
    val 너 = 사람("홍길동");
    val 누구 = 사람("이순신", 478);

    나.누구냐너();
    너.누구냐너();
    누구.누구냐너();

    val 우리아빠 = 아빠();
    우리아빠.나이 = 1000
    println(우리아빠.이름 + ' ' + 우리아빠.나이)
    println(우리아빠.몇짤)
    우리아빠.몇짤 = 10000
    println(우리아빠.몇짤)

}

open class 사람 constructor() { // 주생성자를 헤더에 씀
    var 이름: String? = "아무개"
    var 나이: Int? = 999999;

    constructor(이름: String) : this() {
        this.이름 = 이름
    }

    constructor(이름: String, 나이: Int) : this(이름) {
        this.나이 = 나이
    }

    init {
        println("init ${this} ${this.이름}이(가) 태어났다.${this.나이}살이다")
    }

    open fun 누구냐너() {
        println("${this} ${this.이름}이(가) 태어났다.${this.나이}살이다")
    }
}

class 아빠 : 사람() {

    var 몇짤: Int?
        get() {
            return 나이
        }
        set(나이: Int?) {
            super.나이 = 나이
        }

    init {
        println("init ${this} ${this.이름}이(가) 태어났다.${this.나이}살이다")
    }
}

추상클래스는 java처럼 그렇다. 

abstract class 추상클래스 {
    abstract fun 추상메써드()
}

class 차일드클래스 : 추상클래스() {
    override fun 추상메써드() {
        TODO("Not yet implemented")
    }
}

java VO(?), DTO(?), Entity(?) 던가. 이에 해당하는 data class가 별도로 있다.

data class 클래스명 이런식이다. 중요한 것은 javascript처럼 구조분해할당(destructuring)이 된다는 것~좋구만.

implement없이 그냥 콜론으로..상속받는 것과 같음, 추상클래스의 extend도 없음

fun main() {

    val (이름,나이) = 인간("나",100)
    println("${이름}님은 ${나이}살 입니다")

}

data class 인간(val 이름:String,var 나이:Int)

인터페이스는 java처럼 멤버변수 없이 멤버메서드가 모두 추상메서드인 경우다.아닌가? java 8의 default 대응으로 구현된 메서드도 포함되는군..심지어 override도 된다.어렵네.

이벤트 처리에서 익명함수 object를 이용한 interface객체를 구현해야 할 경우가 있다. 구현할 메서드가 2개이상일 경우다.

뒤로가기 구현할때 이렇게 했다. 맞는지는 검색을~

        this.onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (binding.webView.canGoBack()) {
                    binding.webView.goBack()
                } else {
                    finish()
                }
            }
        })

1개인 경우 람다식이 편하다.

무튼 interface 인터페이스명 ..이런식이다. 검색해서 보자.

 

Lambda....익명함수...javascript의 arrow function..java 8부터 지원하던가.

고차함수(Higher-Order Function)란 하나 이상의 함수를 파라미터로 받거나 결과를 함수로 반환하는 함수다.

간략하게 함수를 넘겨받고 함수를 반환하는 함수라 하겠다.

다음은 고차함수 표현이다.

아래처럼 paramter에 ::콜백함수명으로 넘긴다. [ 고차함수(::콜백함수) ] . 더블콜론임을 기억하자

고차함수의 paramter를 보면 넘겨 받을 콜백함수의 paramter type과 return type을 기술한다.

fun main() {	    
   //고차함수란 하나 이상의 함수를 파라메터로 받거나 결과를 함수로 반환할 경우 고차함수다  
   //함수를 넘겨받고 반환하는 함수
   고차함수(::콜백함수)
   //실행결과 -> 고차함수가 호출 콜백함수 출력
}

fun 콜백함수(str:String) : Unit {
    println("${str} 콜백함수 출력")
}

fun 고차함수(함수변수:(String)->Unit) {
    함수변수("고차함수가 호출")
}

java에서 Filter,Map,Reduce가 고차함수다. 

익명함수는 문자그대로 이름이 없는 함수다. 나머지는 일반함수와 같다.

이름이 없으니 변수에 할당해서 쓰거나 익명함수의 선언하며 직접 주입(?)해도 된다. 주입..Spring DI를 떠올려야 하나?

{}없이 축약도 된다.

fun main() {	    
    println(sum(2,2))
    println(sum2(2,2))
}

val sum = fun(x:Int,y:Int):Int {
    return x+y
}

val sum2 = fun(x:Int,y:Int):Int = x+y

익명함수는 주로 고차함수의 parameter나 return으로 쓴다.

Lambda 대수는 함수를 표현식으로 간단하게 작성하게 한다.

Lambda 모양(?)은 다음과 같다. lambda 함수는 자체가 고차함수다.

변수에 형선언을 하는 것처럼 변수에 함수형으로 선언을 하고 실제 실행할 함수구문을 할당연산자로 할당하면 된다?

람다표현식

fun main() {	    
   //고차함수란 하나 이상의 함수를 파라메터로 받거나 결과를 함수로 반환할 경우 고차함수다  
   //함수를 넘겨받고 반환하는 함수
   고차함수(::콜백함수)
   고차함수(fun(str:String) {
    println("${str} 익명콜백함수 출력")   
   })     
   고차함수(콜백함수람다식)
   고차함수(콜백함수람다식2)
   
}

fun 콜백함수(str:String) : Unit {
    println("${str} 콜백함수 출력")
}

fun 고차함수(함수변수:(String)->Unit) {
    함수변수("고차함수가 호출")
}

val 콜백함수람다식 : (String)->Unit = {
   str -> println("${str} 콜백함수람다식 출력")
}

val 콜백함수람다식2 = {
   str:String -> println("${str} 콜백함수람다식2 출력")
}

/*
고차함수가 호출 콜백함수 출력
고차함수가 호출 익명콜백함수 출력
고차함수가 호출 콜백함수람다식 출력
고차함수가 호출 콜백함수람다식2 출력
*.
fun main() {	    
  
    println(afun("a"))
    println(bfun("b"))
    println(cfun("c"))
    println(stringLength("d",afun))
}

val afun = fun(str:String):Int {
    return str.length
}

val bfun:(String)->Int = {str->str.length}

val cfun = {str:String->str.length}

fun stringLength(str:String, callback:(String)->Int):Int {
    return callback(str)
}

선언자료형 부분을 보면 Int 한개의 파라미터를 받고 Int를 리턴하게 되어 있다. 함수의 리턴은 하나라 괄호를 생략해도 된다.

함수의 반환은 마지막 문장의 결과다.

 

익명함수로 쓰려면 당연히 이름없이 매개변수와 처리내용만 있겠다. { x, y -> x*y } 처럼.

Closure와 Lambda의 차이~ Closure는 외부변수를 참조하고 Lambda는 파라메터를 참조한다?

의존성 측면으로 보면 Closure는 외부변수에 의존적이다. 말이 이상하다.

무튼 안드로이드 스튜디오에서 버튼클릭에 적용해 봤다.어렵다.

익명함수를 가지 가지로 넣어 봤다. 멍청하면 손발이 고생하는게 맞다^^

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val txtView = findViewById<TextView>(R.id.textView)
        val buttonView = findViewById<Button>(R.id.buttonView)

        Log.i("info", txtView.text.toString())
        Log.i("info", buttonView.text.toString())

        /*buttonView.setOnClickListener(fun(view:View) {
            println(view.id.toString())
            txtView.text = "정말 눌렀네..어쩌냐..."
        })*/
        /*val onClickListner: (View) -> Unit = { view ->
            println(view.id.toString())
            txtView.text = "정말 눌렀네..어쩌냐..."
        }
        buttonView.setOnClickListener(onClickListner)*/

        /*val onClickListner = { view: View ->
            println(view.id.toString())
            txtView.text = "정말 눌렀네..어쩌냐..."
        }
        buttonView.setOnClickListener(onClickListner)*/
        
        buttonView.setOnClickListener {
            println(it.id.toString())
            txtView.text = "정말 눌렀네..어쩌냐..."
        }
    }
}

다음은 버튼 클릭 전후다 ㅋㅋ

클릭전
클릭후

확장함수란 어떤 클래스에 기능을 추가하고 싶을때 사용한다. java에선 클래스 상속 받고 추가해야 하는데?

확장함수도 람다표현식으로 사용할 수 있는데 일단 기존 클래스에 메서드를 추가하는 것으로 해본다.

String에 그냥 myPrint라는 함수를 추가하고 호출~

    val myPrint : String.() -> String = {
        println("input $this")
        "input $this"
    }
    
    var str = "hoho"
    str.myPrint()

위를 그냥 확장함수로 작성해 봤다

fun String.myPrint(): String {
    println("input $this")
    return "input $this"
}

정말 확장함수라는 표현이 마음에 든다.

static method가 없다. 동반객체(companion object)로 구현한단다

class instance마다 공통 property나 method가 필요할 때 사용하면 된다고 한다.

fun main() {	    
   
   var 신라면 = 취향저격("신라면")
   var 삼양라면 = 취향저격("삼양라면")
   
   삼양라면.좋아요()
   신라면.좋아요()
   삼양라면.좋아요()
      
   println("${신라면.라면이름} = ${신라면.점수} / ${취향저격.전체}")
   println("${삼양라면.라면이름} = ${삼양라면.점수} / ${취향저격.전체}")
    
}

class 취향저격 (val 라면이름:String) {
    companion object {
        var 전체 = 0
    }
    
    var  점수 = 0
    
    fun 좋아요() {
        점수++
        전체++
    }
    
}

/*
신라면 = 1 / 3
삼양라면 = 2 / 3
*/

이와 별도로 object...java의 singleton 이라고 보면 된다.

fun main() {	    
   
    println(Counter.count)
    
    Counter.up()
    println(Counter.count)
    
    Counter.down()
    println(Counter.count)
    
    Counter.clear()
    println(Counter.count)
    
}

object Counter {
    var count = 0
    val resetValue = 0
    fun up() {
        count++
    }
    fun down() {
        count--
    }
    fun clear() {
        count = resetValue;
    }
}

/*
0
1
0
0
*/

익명함수를 통한 옵저버패턴. 옵저버..지켜보며 듣고 있다...ㅋㅋ Listner...Event Listener...callback

 

 

나중에 살펴 보자.

기본은 이정도만^^

 

반응형

'android > kotlin' 카테고리의 다른 글

안드로이드 정리 3  (0) 2024.01.23
안드로이드 정리 2  (0) 2024.01.19
android avd path change ( 경로 변경 )  (0) 2024.01.16
android bmi  (0) 2024.01.11
안드로이드 정리 1  (0) 2023.09.15
Comments