[Kotlin] 기본 문법 정리

leeeha·2021년 12월 30일
0

코틀린

목록 보기
1/28

참고 영상

https://www.inflearn.com/course/코틀린-요약-강의/dashboard

1. 함수

fun main(){
    helloWorld()
    print(add(4, 5))
}

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

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

void를 뜻하는 Unit은 생략 가능하지만, 그 외의 리턴 타입은 생략 불가능하다.


2. val vs var

val → value, 값, immutable (변경할 수 없는)
var → variable, 변수, mutable (변경할 수 있는)

fun hi(){
    val a : Int = 10
    var b : Int = 9
    //a = 100 // 변경 불가능한 val
    b = 100 // 변경 가능한 var
    
    // 초기화 했을 때는 타입 생략 가능 (자동 추론)
    val c = 100
    var d = 100
    var name = "haeun"
    
    // 초기화를 안하면 타입 추론을 할 수 없으니까 타입 지정 필수
    var e : String
}

3. String Template

fun main(){
    val name = "Haeun"
    val lastName = "Lee"
    println("my name is ${name + lastName} I'm 22")
    println("my name is ${"$name $lastName"} I'm 22")
    println("Is this ture? ${1 == 0}")

    // 백슬래시를 붙이면 $를 그냥 문자로 인식
    println("This is 2\$")
}

my name is HaeunLee I'm 22
my name is Haeun Lee I'm 22
Is this ture? false
This is 2$


4. 조건문

Expression과 Statement의 차이점

어떤 연산을 거쳐 값을 반환하면 Expression이고, 단순히 명령을 지시하는 문장이면 Statement이다.
자바의 if-else문과 달리, 코틀린의 if-else문은 Statement뿐만 아니라 값을 리턴하는 Expression이 될 수 있다. 그래서 아래 코드의 maxBy2라는 메소드를 보면, if-else문이 삼항 연산자의 역할을 하고 있다.

fun main(){
    println(maxBy(4, 5))
    println(maxBy2(4, 5))
}

fun maxBy(a : Int, b : Int) : Int {
    if(a > b){
        return a
    }else{
        return b
    }
}

fun maxBy2(a : Int, b : Int) = if(a > b) a else b
//return (a > b) ? a : b

5
5

아래 코드에서도 when문은 Statement뿐만 아니라 값을 반환하는 Expression이 될 수 있다. 이 경우에는 else문을 필수로 작성해줘야 한다.

fun main(){
    checkNum(1)
}

fun checkNum(score: Int){
    // Statement로 사용된 when문
    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") // else문 생략 가능
    }

    // Expression으로 사용된 when문
    var b = when(score){ 
        1-> 1
        2-> 2
        else-> 3 // when문이 값을 리턴할 때는 else문 필수
    }
    println("b : $b")

    when(score){ // Statement
    	// 부등호를 쓰지 않고 범위를 매우 쉽게 나타낼 수 있다!!
        in 90..100 -> println("You are genius")
        in 10..80 -> println("not bad")
        else -> println("okay")
    }
}

this is 1
b : 1
okay

코틀린에서 모든 함수는 Expression이다. 함수가 값을 반환하지 않더라도 항상 Unit이 리턴되기 때문에 Expression으로 본다. (반면에, 자바의 void형은 Statement이다.)


5. Array vs List

기본적으로 Array는 mutable, List는 immutable이다. 변경 가능한 리스트는 MutableList라고 따로 있다.

fun array(){
    val array = arrayOf(1, 2, 3)
    val list = listOf(1, 2, 3)

    val array2 = arrayOf(1, "d", 3.4f)
    val list2 = listOf(1, "d", 11L)

    array[0] = 3 // mutable
    //list[0] = 2 // immutable
    var result = list.get(0)
    // 기본적인 List는 참조만 할 수 있고, 값 변경은 불가

    // MutableList의 대표적인 예시가 ArrayList
    val arrayList = arrayListOf<Int>() 
    // 어레이리스트의 내용은 바뀌지만, 그 주소값은 바뀌지 않기 때문에 val
    arrayList.add(10)
    arrayList.add(20)
    
    //arrayList = arrayListOf() 
    // Val cannot be reassigned. val은 새로 생성된 객체를 가리킬 수 없음.
}

6. 반복문

for문

fun forAndWhile(){
    val students = arrayListOf("aaa", "bbb", "ccc", "ddd")
    for(name in students){
        println(name)
    }

    var sum = 0
    for(i in 1..10){ // 55
        sum += i
    }
    println(sum)
}
for(i in 1..10 step 2) // 1+3+5+7+9 = 25
for(i in 10 downTo 1)  // 55 (주의! 10..1은 0으로 출력됨)
for(i in 1 until 10)   // 10은 제외

while문

fun forAndWhile(){
    var i = 0
    while(i < 10){
        println("current index: $i")
        i++
    }

    val students = arrayListOf("aaa", "bbb", "ccc", "ddd")
    for((index, name) in students.withIndex()){
        println("${index + 1}번째 학생: $name")
    }
}

current index: 0
current index: 1
current index: 2
current index: 3
current index: 4
current index: 5
current index: 6
current index: 7
current index: 8
current index: 9
1번째 학생: aaa
2번째 학생: bbb
3번째 학생: ccc
4번째 학생: ddd


7. NonNull, Nullable

fun main(){
    nullCheck()
}

fun nullCheck(){
    // NPE: Null Pointer Exception
    // 자바에서는 NPE이 런타임에만 발생하기 때문에 에러 원인을 찾기 매우 힘들 수 있음.

    // 기본적으로는 non-null 타입이지만, 타입 뒤에 ?를 붙이면 Nullable로 변함.
    var name = "Haeun" // 타입 생략 가능
    var nullableName : String? = null // Nullable 변수는 타입 지정 필수

    var nameInUpperCase = name.toUpperCase() // non-null
    var nullableNameInUpperCase = nullableName?.toUpperCase()
    // Nullable 변수가 null이면 null을 반환하고,
    // null이 아니면 toUpperCase 함수 실행
    // 번거롭게 if문으로 null 검사를 해주지 않아도 된다!!

    println(nameInUpperCase) // HAEUN
    println(nullableNameInUpperCase) // null

    // ?: (Elvis 연산자)
    // Nullable 변수가 null일 때, 디폴트 값을 지정한다.
    val lastName : String? = null
    val fullName = name + " " + (lastName?: "NO lastName")
    println(fullName)
}

HAEUN
null
Haeun NO lastName

fun main(){
    ignoreNulls("Haeun")
}

fun ignoreNulls(str: String?){
    // !! (컴파일러에게 non-null 타입이라고 확실하게 알려주기)
    val nonNullName : String = str!!
    val upper = nonNullName.toUpperCase()
    println(upper)

    val email : String? = "jxlhe46@gmail.com"
    email?.let { // email이 null이 아니면 실행
        // let 함수는 리시버 객체인 email을 람다식 내부로 옮겨서 실행한다.
        println("my email is $email")
    }
}

HAEUN
my email is jxlhe46@gmail.com


8. 클래스

자바에서와 달리, 코틀린은 클래스명과 파일명이 일치하지 않아도 되며 하나의 파일에 여러 개의 클래스를 정의할 수 있다.

생성자

ClassPractice.kt 파일 생성 후 Human 클래스 정의하기

class Human {
    val name = "Haeun" // 속성 (property)
    fun eatingCake(){ // 메소드 (method)
        println("This is yummy~~~")
    }
}

fun main(){
    val human = Human() // 객체 생성할 때 new 연산자 필요 없음.
    human.eatingCake()
    println("This human's name is ${human.name}")
}

This is yummy~~~
This human's name is Haeun

// 이 자체가 name을 매개변수로 하는 생성자여서 클래스 내에서 따로 정의할 필요 없음.
class Human(val name: String) {
    fun eatingCake(){
        println("This is yummy~~~")
    }
}

fun main(){
    val human = Human("Minsu") 
    human.eatingCake()
    println("This human's name is ${human.name}")
}

This is yummy~~~
This human's name is Minsu

// 전달된 인자가 없는 경우를 대비하여 디폴트 값 지정하기
class Human(val name: String = "Anonymous") { 
    fun eatingCake(){
        println("This is yummy~~~")
    }
}

fun main(){
    val human = Human("Minsu")
    human.eatingCake()
    
    val stranger = Human() // name이 디폴트 값으로 초기화됨.
    println("This human's name is ${stranger.name}")
}

This is yummy~~~
This human's name is Anonymous

class Human(val name: String = "Anonymous") {
    init{ // 객체가 생성될 때 호출됨 (초기화 작업)
        println("New human has been born!")
    }

    fun eatingCake(){
        println("This is yummy~~~")
    }
}

fun main(){
    val human = Human("Minsu")
    println("This human's name is ${human.name}")
    human.eatingCake()

    val stranger = Human() // name이 디폴트 값으로 초기화됨.
    println("This human's name is ${stranger.name}")
}

New human has been born!
This human's name is Minsu
This is yummy~~~
New human has been born!
This human's name is Anonymous

코틀린에서는 객체를 생성할 때 new 키워드 없이 클래스명 뒤에 괄호()를 붙인다. 그리고 클래스를 정의하자마자 바로 생성자 및 속성까지 정의할 수 있기 때문에 자바보다 코드 길이가 훨씬 단축된다.

생성자 오버로딩

자바에서 생성자를 오버로딩 할 때는?

class Person {
   public Person(String name) {
   }
   
   public Person(String name, int age){
      this(name);
   }
}

코틀린에서 부 생성자는 this를 통해 주 생성자를 필수적으로 위임받아야 한다. 아래 코드에서 부 생성자는 객체의 이름과 나이를 출력한다.

class Human(val name: String = "Anonymous") { // 주 생성자
    constructor(name: String, age: Int) : this(name) { // 부 생성자
        println("My name is $name, ${age}years old")
    }

    init{ 
        println("New human has been born!")
    }

    fun eatingCake(){
        println("This is yummy~~~")
    }
}

fun main(){
    val mom = Human("Kuri", 50)
}

New human has been born!
My name is Kuri, 50years old

상속

기본적으로 코틀린의 모든 클래스는 final이기 때문에, 다른 클래스에서 사용하려면 open 키워드를 붙여줘야 한다. 메소드 역시 부모 클래스에서 open을 해줘야 오버라이딩 가능하다.

open class Human(val name: String = "Anonymous") {
    init{
        println("New human has been born!")
    }

    open fun singASong(){
        println("lalala")
    }
}

class Korean : Human() { // Human 클래스 상속
    override fun singASong(){
        super.singASong()
        
        println("라라라")
        println("My name is $name")
    }
}

fun main(){
    val korean = Korean()
    korean.singASong()
}

New human has been born!
lalala
라라라
My name is Anonymous

profile
꾸준히!

0개의 댓글