모바일&임베디드/안드로이드

[Kotlin] 기본 문법

차가운오미자 2021. 6. 15. 11:06

1. 함수 선언

// 1. 함수
fun helloWorld() : Unit{
    println("Hello world")

}

fun add(a : Int, b : Int) : Int {
    return a+b
}

 

- return하지 않으면 Unit을 더해줘야 하지만, redundant라서 굳이 넣지 않아도 된다.

- 변수 타입이 나중에 온다 (변수이름 : 자료형)

 

2. 변수 선언

// 2. val vs var
// val = value : 불변한다

fun hi(){
    val a : Int = 10 // val은 상수
    var b : Int = 9 //변할 수 있음 variable
    // a = 100 에러 뜸
    b = 100
    val c = 10 //이렇게 해도 변수형 정의 안해줘도 알아서 int로 알아들음
    var d = 10 //이것도 가능

    var name = "omija"
}

 

변수에 val 타입과 var 이 존재한다.

val은 상수여서 추후에 값을 변경할 수 없고, var은 변수여서 값을 변경할 수 있다.

* 반드시 자료형을 정의해주지 않아도 된다.

 

3. String Template

// 3. String template
     val name = "tara"
     val lastName = "bae"
     println("my name is $name I'm 23") // $로 변수 출력 가능,
     // 대신 뒤에 띄어쓰기를 해야하는데, 대괄호 해주면 띄어쓰기 안할 수 있음
     println("my name is {$name}I'm 23")
     println("my name is ${name + lastName}")
     println("is this true? ${1==0}")
     println("this is 2\$a") // \를 더해주면 $를 명령어가 아닌 문자 $로 받을 수 있음

 

- 스트링 내에서 변수/상수와 함께 프린트해주고 싶으면 $ 표시를 이용한다.

- 띄어쓰기를 하지 않고 string을 형성하기 위해서는 구분을 위해 {} 을 사용한다.

- {} 안에 {1==0} 같이 넣을 수도 있다는 점

- $를 문자로 표현할 때는 \을 이용한다.

 

 

4. 조건문

1) if 문

a) 원래 알듯이 사용하면 됨

//방식 1
    if(a > b){
        return a
    }else {
        return b
    }

 b) 간단하게 그냥 함수에다 바로 갖다 때려박을 수도 있음

fun maxBy(a: Int, b: Int) : Int = if(a>b) a else b

 

2) when

마치 switch문 같은 역할을 한다.

a) 스위치 문과 비슷하게 적용가능하다. -> 을 사용한다.

when(score){
        0 -> println("this is 0")
        1 -> println("this is 1")
        2, 3 -> println("this is 2 or 3")
        else -> println("I don't know")
} //switch 역할

 

 b) 변수에다가 바로 저장해줄 수도 있다.

var b = when(score){
        1->1
        2->2
        // 단 바로 리턴하는 경우는 else가 만드시 필요함
        else -> 3
    }

 

* 대신 이 때는 else가 반드시 들어가야 한다.

 

c) 범위로 값을 지정할 수도 있다.

when(score){
        in 90..100 -> println("You are genius!") // 90~100
        in 10..80 -> println("not bad")
        else -> println("okay") // else문이 필수는 아님
    }

 

5. Expression vs. Statement

리턴 값을 만들면 expression, 그냥 안에서 작동하는거면 statement

* 자바와의 차이점

1. 자바는 모든 if문이 statement일 뿐이고 함수도 statement일 수 있음(void 반환)

2. 코틀린의 모든 함수는 "Unit"이라도 expression임

when(score){
        0 -> println("this is 0");
        1 -> println("this is 1");
        2, 3 -> println("this is 2 or 3")
        else -> println("I don't know")
        // 여기는 return 하지 않으므로 Statement
    } //switch 역할

var b = when(score){
        1->1
        2->2
        // 단 바로 리턴하는 경우는 else가 만드시 필요함
        else -> 3
        // 여기는 리턴을 하고 있으니까 expression
    }

 

6. Array & List

Array: 정해져있는 사이즈, 메모리 미리 할당

List:

1. immutable list: 수정 불가능 - read only

2. mutable list: 수정 가능 - read and write, add, remove등 함수 사용해서 바꿀 수 있음

fun arrayAndList(){
    val array : Array<Int> = arrayOf(1, 2, 3)
    val list : List<Int> = listOf<Int>(1, 2, 3)

    val array2 : Array<Any> = arrayOf(1, "d", 3.4f)
    val list2 : List<Any> = listOf<Any>(1, "d", 11L)

    //val mlist: MutableList<Any> = mutableListOf(1, "d")

    array[0] = 3
    //list[0] = 3 -> error
    var res : Int = list.get(0)
    mlist.add(2, 11L)
    mlist.add(3)
    mlist.remove(2)

    val arrayList : ArrayList<Int> = arrayListOf<Int>()
    // 주소를 주는 거니까 val을 써도 된다.
    arrayList.add(10)
    arrayList.add(20)
    arrayList[0] = 30 // mutable
    // val arrayList : error val cannot be reassigned

 

- 선언은 arrayOf, listOf 등으로 해주고, ()안에 엘리먼트들을 넣어주면 된다.

- Any타입 배열, 리스트를 선언해서 다양한 자료형이 들어갈 수도 있다.

- 그냥 List 선언 시에 immutable list라서 변경할 수 없다. get으로 값을 받아올 수는 있다.

- arrayList는 mutable해서 변경해줄 수 있음

 

 

7. 반복문

For

1) 파이썬에서처럼 list 안에 요소를 traverse하는 형식으로 for문을 사용할 수 있다.

fun forAndWhile(){

    val myList : ArrayList<String> = arrayListOf("jennie", "michelle", "michael")
    for(name:String in myList){
        println("${name}")
    }

 

2) 범위를 정해서 for(int i = 0; i<n; i++) 처럼 돌릴 수도 있다.

- 이때 step 을 이용해서 간격을 1이 아닌 2로도 바꿀 수 있고, downTo를 이용해서 내림차순으로 돌릴 수도 있다.

- until을 이용할 수도 있는데 1 until 100 이 1..10과 다른 점은 맨 끝 수, 즉 100을 포함하지 않는다는 것이다.

  var sum :Int = 0
    for(i in 1..10){
        sum += i
    }
    println(sum)

    for(i in 1..10 step 2){
        sum += i
    }

    for(i in 10 downTo 1){
        sum += i
    } // 역순으로 됨

    for(i in 1 until 100){ //1..100이랑 다름. 100을 포함하지 않음: 1~99까지
        sum += i
    }

 

3) 리스트에 있는 키 값(이라 하기 뭐하지만)과 엘리먼트를 아래와 같이 사용할 수도 있다.

var index : Int = 0
for((index, name) in myList.withIndex()){
        println("${index}번째 학생 : ${name}")
    }
}

 

While

우리가 아는 while과 같이 사용한다.

var index : Int = 0
    while(index < 10){
        println("cur: ${index}")
        index++
    }

 

 

8. Nullable & NonNull

Java에서는 null ptr exception을 런타임에서만 잡을 수 있다는 문제가 있었는데, 코틀린은 이를 컴파일 시점에 잡기 위해서 ? 등의 nullable 개념을 사용한다.

nullable: ?

fun nullcheck(){
    // NPE: null ptr exception
    // 자바에서 컴파일 시점에서 잡을 수 없고 런타임에서만 잡힌다.
    // 컴파일 시점에 npe를 하기 위해서 ?가 등장

    var myname : String = "Tara" // 기본적으로 nonNull타입임
    //var nullName : String = null // 에러뜸, 타입 생략 가능
    var nullName : String ? = null // null을 넣을 수 있음, 이 경우 타입 생략 불가
    var nameInUpperCase = myname.uppercase()
    var nullNameInUpperCase : String? = nullName?.uppercase();
    // null이 아니면 uppercase실행, null이면 전체가 null을 반환

    // ?:
    var lastName : String? = null
    var fullName = myname +" "+ (lastName?: "No lastName")
    println(fullName)
    lastName = "Bae"

}

 

원래 var 타입 변수에는 null 이 들어가지 않는다. 하지만 ?을 넣으면 null값을 저장할 수 있다. 이때 변수의 자료형은 반드시 명기해줘야 한다. 이렇게 선언된 것이 nullable 변수

 

nullable변수를 이용할 때는 역시 ?을 사용해줘서

a) null이 아니면 이용하고, 아니면

b) null을 반환하도록 해준다.

 

위의 예시에서는 nullable한 변수 nullName를 가지고 uppercase()라는 함수를 호출하는데, 이때 nullName의 값이 null이면 nullNameInUpperCase 변수에 그냥 null이 들어가버리고, nullName에 어떤 값이 있다면 그 값으로 uppercase()를 실행한 다음 결과값을 저장해준다.

 

ignore null : !!

!!을 이용해서 null이 아님을 보장해주겠다고 말해주는 것

//!!: 이거 null 아니라고 말해주는 것, nullable이지만 내가 보장한다
fun ignoreNulls(str: String?){
    // val mNotNull : String = str; //에러뜸, nullable이라서
    val mNotNull : String = str!!
    val upperMNotNull : String = mNotNull.uppercase()

    val email : String? = "nohaja904@naver.com"
    email?.let{
        //email이 null이 아니면 아래를 실행해라 -> very safe
        // let: 자신의 receiver 객체(email)를 람다식? 내부로 옮긴다
        println("my email is: ${email}")
    }
}

 

let

if (variable != null) 체크를 해주는 것으로 생각하면 된다.

근데 인터넷 검색을 하다보니, 웬만해서는 let보다는 그냥 저 if문을 사용해서 널 체크를 하는 게 낫다는 얘기가 많다.

https://tourspace.tistory.com/208

 

위 블로그를 읽어보면 불필요한 코드가 삽입되기 때문에 if문으로 직접 널체크를 하는게 더 효율적이라고 한다.

let을 검색하면 위와 같은 이야기가 많이 나온다.