본문 바로가기

Programming/Kotlin

[3일차] 깡샘의 안드로이드 앱 프로그래밍 with 코틀린(Do it!) / 03 코틀린 시작하기

해당 내용은 이지스 퍼블리싱 카페에서 공부하며 올렸던 글을 다듬었습니다.

< 코틀린 언어 소개 >

- 코틀린 파일의 확장자 : .kt

- 코틀린 컴파일러(kotlinc)가 .kt 파일을 컴파일하면 자바 바이트 코드가 만들어진다.

- 코틀린의 이점 4가지

  * 표현력과 간결함 => 훨씬 간결한 구문으로 프로그램 작성 가능

  * 안전한 코드 => 자바의 런타임 오류인 널 포인트 예외를 고려하지 않고 개발 가능

    널 허용(nullable)과 널 불허용(not null)으로 구분해서 선언 가능

  * 상호 운용성 => 코트린은 자바와 100% 호환

  * 구조화 동시성 => 코루틴(coroutines) 기법을 이용해 비동기 프로그래밍을 간소화

    ex) 네트워크 연동, 데이터 베이스 갱신 등

- package : 이 파일을 컴파일했을 때 만들어지는 클래스 파일의 위치를 나타내며

               소스 파일에서 맨 처음 한 줄로 선언

- import : package 구문 아래에 여러 줄 작성 가능

             어떤 파일에 선언한 멤버(변수, 함수, 클래스)를 다른 코틀린 파일에서 참조할 때

package 구문
import 구문
같게 선언
X
다르게 선언
O

 

코틀린 파일을 컴파일하면 클래스는 각각의 클래스 파일로 만들어진다.
User.kt라는 파일 내 클래스를 선언했다면 User.class 파일이 만들어지고, (User.class)
최상위에 선언한 변수와 함수는 자동으로 '파일명+Kt'라는 이름의 클래스에 포함된다. (UserKt.class)
P.82 참고

 

 

 

< 변수와 함수 >

- 변수 : val, var 키워드로 선언

  * val : value. 초깃값 할당 후 바꿀 수 없는 변수 (상수)

  * var : variable. 초깃값 할당 후 바꿀 수 있는 변수 (변수)

val(혹은 var) 변수명: 타입 = 값
    

- 타입 지정과 타입 추론

  * 변수명 뒤에 콜론(:)을 추가해서 타입 명시 가능

  * 대입하는 값에 따라 타입을 유추할 수 있을 때(타입 추론)는 생략 가능

val data1: Int = 10 // 타입 지정
val data2 = 10      // 타입 추론

- 최상위에서 선언한 변수나 클래스의 멤버 변수는 선언과 동시에 초기화해야 함

- 초기화 미루기

  * lateinit 키워드

    => var 키워드로 선언한 변수만 사용 가능

    => String 타입에만 사용 가능

  * lazy 키워드

    => 변수 선언문 뒤 by lazy { } 형식으로 선언

    => 변수가 최초로 이용되는 순간 중괄호로 묶은 부분이 자동으로 실행

    => lazy문의 중괄호를 여러 줄로 작성한다면 마지막 줄의 실행 결과가 변수의 초깃값이 됨

val data4: Int by lazy {
    println("in lazy...")
    10
}

fun main() {
    println("in main...")
    println(data4 + 10)
}



------< 실행 결과 >------
in main...
in lazy...
20

- 코틀린의 모든 변수는 객체

- null은 메모리 할당이 되지 않았음을 의미

- 기초 타입 객체 : Int, Short, Long, Double, Float, Byte, Boolean

var data1: Int = 10      // 기초 타입
var data2: Int? = null   // 객체 타입

- String은 큰따옴표(")나 삼중 따옴표(""")로 감싸서 표현

  * 삼중 따옴표는 정렬한 그대로 출력함

- 문자열 템플릿 : String 타입의 데이터에 변숫값이나 어떤 연산식의 결괏값을 포함해야 할 때는 $ 기호를 이용

  예) ${arr1[0]}

// 삼중 따옴표 사용 예시 
println( 
        """ 
            array size : ${arr1.size}
            array data : ${arr1[0]}, ${arr1[1]}, ${arr1.get(2)} 
        """
)

- Any : 모든 타입의 데이터 할당 가능

- Unit : 반환 문이 없는 함수

  * 특수한 상황을 표현하려는 목적

  * Unit 타입으로 선언한 변수에는 Unit 객체만 대입 가능 => 선언할 수 있지만 의미 없음

  * 주로 함수에서 반환문이 없음을 명시적으로 나타낼 때 사용

  * 함수 선언 시 반환 타입을 생략하면 자동으로 Unit이 적용

- Nothing : null이나 예외 반환

  * 주로 함수 반환 타입에 사용

  * 반환하지만 의미 있는 값은 아니라는 의미

// Any 사용 예시
val data1: Any = 10

class User
val data3: Any = User()


// Unit 사용 예시
val data1: Unit = Unit   // 가능하지만 의미 없음

fun someFun(): Unit {    // 반환문이 없는 함수
    println(10+20)
}

fun someFun() {    // 위와 같은 함수 (명시하지 않아도 자동 적용)
    println(10+20)
}


// Nothing 사용 에시
val data1: Nothing? = null

fun some1(): Nothing? {    // null 반환
    return null
}

fun some2(): Nothing {    // 예외 반환
    throw Exception()
}​
 }

- 널 허용과 널 불허용

  * nullable : 널 허용. null을 대입할 수 있는 변수

    => 타입 뒤에 물음표(?)로 표시

  * not null : 널 불허용. null을 대입할 수 없는 변수

var data1: Int = 10
data1 = null    // 오류

var data2: Int? = 10
data2 = null    // 성공

- 함수 : fun 키워드 사용

  * 매개변수에는 var나 val 사용 불가

    => val 자동 적용

    => 함수 안에서 매개 변숫값 변경 불가

- 함수의 매개변수에는 기본값 선언 가능

  * 호출할 때 인자를 전달하지 않아도 됨

fun main() {
    fun some(data1: Int, data2: Int=10): Int {
        return data1 * data2
    }

    println(some(10))         // 두번째 인자는 기본값 10으로 처리
    println(some(10, 20))     // 두번째 인자는 20으로 처리
}

 

- 함수의 매개변수는 전달한 인자를 순서대로 할당

* 호출할 때 매개변수명을 지정(명명된 매개변수)하면 매개 변숫값의 순서를 바꿔도 됨

some(data2 = 20, data1 = 10)

- 컬렉션 타입 : 여러 개의 데이터를 표현하는 방법

  * Array, List, Set, Map

- Array : 배열 표현

  * 매개변수

    => 첫 번째 : 배열의 크기

    => 두 번째 : 초깃값

  * 배열 타입은 제너릭으로 표현

    => 제너릭 : 이용하는 곳에서 타입을 지정하는 기법

val data1: Array<Int> = Array(3, { 0 })    // 기본 방식
val data1: Array<Int> = Array(3) { 0 }     // 최근 버전에선 이 방식을 추천함

 

* 배열에 접근할 때는 대괄호([])나 set(), get() 함수를 이용할 수 있음

=> 최신 버전에선 대괄호([]) 방법으로 추천함

// Array 객체 타입 예제
    val arr1: Array<Int> = Array(3, { 0 })    // 배열 선언. Array(배열의 크기, 초깃값)
    arr1[0] = 10
    arr1[1] = 20                              // 대괄호([]) 형태
    arr1.set(2, 30)                           // set(인덱스, 값) 형태로 설정하기

    println(
        """
           array size : ${arr1.size} 
           array data : ${arr1[0]}, ${arr1[1]}, ${arr1.get(2)}     // get(인덱스) 형태로 가져오기
        """
    )

- 기초 타입의 배열 : Array를 사용하지 않고 각 기초 타입의 배영을 나타내는 클래스를 이용할 수도 있음

  * BooleanArray, ByteArray, CharArray, DoubleArray, FloatArray, IntArray, ShortArray 클래스 이용 가능

val data1: IntArray = IntArray(3, { 0 })

- arrayOf() 함수

* 기초 타입도 있음 => booleanArrayOf(), byteArrayOf(), charArrayOf() 등

val data1 = arrayOf<Int>(10, 20, 30)    // arrayOf()로 배열 선언. 각 인덱스에 초깃값 할당
val data2 = intArrayOf(10, 20, 30)      // intArrayOf() 기초 타입 함수.

- 컬렉션 타입 클래스: List, Set, Map

 
순서
중복 허용
List
O
O
Set
O
X
Map
X
X (키의 중복만)

- 컬렉션의 가변 클래스와 불변 클래스

* 가변 : 초깃값을 대입한 이후에도 데이터를 추가하거나 변경 가능

=> mutableListOf(), mutableSetOf(), mutableMapOf()

* 불변 : 초기에 데이터를 대입하면 변경 불가

=> listOf(), setOf(), mapOf()

- Map 객체 : 키와 값으로 구성

* 키와 값을 설정하는 2가지 방법

① Pair

② '키 to 값'

// Map 예제
    var map = mapOf<String, String>(Pair("one", "one hello"), "two" to "two world")
    println(
        """
           map size: ${map.size}
           map data: ${map.get("one")}, ${map.get("two")}
        """
    )


---------- < 실행 결과 > ----------
map size: 2
map data: one hello, two world

 

 

 

 

 

 

< 조건문과 반복문 >

- if~else : 조건문. 프로그램의 흐름을 제어하는데 가장 많이 사용.

  * 표현식으로 표현 가능. 단, else 생략할 수 없음!

  * 표현식이 반환하는 결괏값은 각 영역의 마지막 줄에 해당함.

    var data = 10
    val result = if (data > 0) {   // 표현식은 else문 생략 불가!!
        println("data > 0")
        true    // 참일 때 반환값
    } else {
        println("data <= 0")
        false   // 거짓일 때 반환값
    }
    printf(result)

---------- < 실행 결과 > ----------
data > 0
true
----------------------------------
 

 

- when : 조건문. (switch와 비슷)

  * 정수가 아닌 다른 타입의 데이터를 지정 가능.

    // 1. 문자열 예제
    var data1 = "hello"
    when (data1) {
        "hello" -> println("data is hello")
        "world" -> println("data is world")
        else -> {
            println("data is not valid data")
        }
    }

---------- < 실행 결과 > ----------
data is hello
----------------------------------



    // 2. 다양한 유형의 조건 예제
    var data2: Any = 10
    when (data2) {
        is String -> println("data is String")  // data가 문자열 타입이면
        20, 30 -> println("data is 20 or 30")   // data가 20 또는 30이면
        in 1..10 -> println("data is 1..10")    // data가 1~10의 값이면
        else -> println("data is not valid")
    }

---------- < 실행 결과 > ----------
data is 1..10
----------------------------------
 

  * 데이터를 명시하지 않고 조건만 명시 가능.

    // 3. 조건만 명시한 예제
    var data3 = 10
    when {    // 데이터를 명시하지 않음
        data3 <= 0 -> println("data is <= 0")
        data3 > 100 -> println("data is > 100")
        else -> println("data is valid")
    }

---------- < 실행 결과 > ----------
data is valid
----------------------------------
 

 

  * when문도 표현식으로 사용 가능!

    if문의 표현식처럼 else문 생략 불가!

    // 4. when문을 표현식으로 사용한 예제
    var data4 = 101
    var result = when {
        data4 <= 0 -> "data is <= 0"
        data4 > 100 -> "data is > 100"
        else -> "data is valid"
    }
    println(result)

---------- < 실행 결과 > ----------
data is > 100
----------------------------------
 

 

 

- for : 반복문. 제어 변숫값을 증감하면서 특정 조건이 참일 때까지 구문을 반복해서 실행.

  * 범위 연산자인 in을 사용

    // 기본 예제
    var sum: Int = 0
    for (i in 1..10) {    // 범위 연산자 in => 1부터 10까지
        sum += i
    }
    println(sum)

---------- < 실행 결과 > ----------
55
----------------------------------
 

 

  * 증감 조건을 숫자로 명시하지 않고 컬렉션 타입의 데이터도 표현 가능

    var data = arrayOf<Int>(10, 20, 30)
    for(i in data.indices) {    // indices = '컬렉션 타입의 인덱스 값'을 의미
        print(data[i])
        if(i !== data.size - 1) {
            print(", ")
        }
    }

---------- < 실행 결과 > ----------
10, 20, 30
----------------------------------
 

 

  * 인덱스와 데이터를 함께 가져오려면 withIndex() 함수 이용

    // 인덱스와 데이터를 가져오는 withIndex() 함수
    var data1 = arrayOf<Int>(10,20,30)
    for ((index, value) in data.withIndex()) {
        print(value)
        if(index !== data.size - 1) print(",")
    }

---------- < 실행 결과 > ----------
10,20,30
----------------------------------
 

 

- while : 반복문. 조건이 참이면 중괄호{} 영역을 반복해서 실행.

    var x = 0
    var sum1 = 0
    while (x < 10) {     // x < 10이 참(true)이면
        sum1 += ++x
    }
    println(sum1)

---------- < 실행 결과 > ----------
55
----------------------------------