2장. 코틀린 기초

2장. 코틀린 기초

기본적인 내용은 생략한다.

키워드
#프로퍼티 #변수 #함수 #클래스 #스마트캐스트 #예외처리

식 : 값을 만들어 내는 것
문장(문) : 값을 만들어내지 않는 것


2.1 기본 요소 : 함수와 변수 #

아래 내용을 통해 알 수 있는 것은 다음과 같다.

  • 함수, 변수를 최상위 수준에 정의 가능 (꼭 클래스 내에 정의하는 것이 아니라)
  • println : 코틀린 표준 라이브러리 → 표준 자바 라이브러리 함수를 간결하게 사용할 수 있도록 래핑
fun main(args: Array<String>) {
    println("Hello, world!")
}



함수 #

종류설명
블록이 본문인 함수본문이 중괄호({})로 둘러싸인 함수
식이 본문인 함수등호(=)와 식(expression)으로 이뤄진 함수
* 코틀린에서는 식이 본문인 함수가 자주 사용된다.

/** 예시 : 블록이 본문인 함수 */
fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

// '블록이 본문인 함수'의 경우, '반환 타입'을 꼭 명시해줘야한다.
/** 예시 : 식이 본문인 함수 */
fun max(a: Int, b: Int): Int = if (a > b) a else b

// '식이 본문인 함수'의 경우, '반환 타입'에 대해서 컴파일러가 타입 추론한다.
// 따라서, 반환 타입을 생략할 수 있다. (반환 타입만 생략 가능하다.)
/** 예시 : 식이 본문인 함수 */
fun max(a: Int, b: Int) = if (a > b) a else b

// '식이 본문인 함수'의 경우, '반환 타입'에 대해서 컴파일러가 타입 추론한다.
// 따라서, 반환 타입을 생략할 수 있다. (반환 타입만 생략 가능하다.)

‘식이 본문인 함수’의 경우, ‘반환 타입’에 대해서 컴파일러가 타입 추론한다. 따라서, 반환 타입을 생략할 수 있다. (반환 타입만 생략 가능하다.)



변수 #

종류설명
val(value)immutable
정확히 1번만 초기화되어야 한다.

* 자바의 final 변수
var(variable)mutable

* 자바의 일반 변수

기본적으로 모든 변수를 val 로 사용하고, 필요 시에만 var 을 사용하는 것을 권장한다.

단, val의 경우 초기화를 한번만 하면 되기에 아래 코드도 가능하다.

val message: String
if(~~~) {
    message = "success"
}
else {
    message = "error"
}

초기화 식이 있다면,

타입 추론할 수 있다. (타입을 지정하지 않으면, 컴파일러가 초기화 식을 이용)

val answer = 42

초기화 식이 없다면,

타입 추론할 수 없다. (추론할 수 있는 요소가 없는 것이니까)

val answer: Int
answer = 42



문자열 템플릿 #

println("Hello, $name!")

단, 아래처럼 중괄호로 감싸는 습관을 들이는 것을 권장한다.

println("Hello, ${name}!")
println("Hello, ${if (args.size > 0) args[0] else "someone"}!")



클래스와 프로퍼티 #

언어프로퍼티 개념
Java필드(Field)와 접근자(accessor method)를 묶어 → 프로퍼티(property)
Kotlin기본으로 ‘프로퍼티’라는 개념 사용
val, var (?)

“대부분의 프로퍼티에는 그 프로퍼티의 값을 저장하기 위한 필드가 있다. 이를 프로퍼티를 뒷받침하는 필드(backing field)라고 부른다.”



커스텀 접근자 #

class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() {
            return height == width
        }
}



디렉터리 / 패키지 #

디렉터리, 패키지 개념은 자바와 비슷하다.

패키지 안에 모든 선언(클래스, 함수, 프로퍼티 + 최상위 함수, 프로퍼티 포함)가 선언된다.


추가적으로 소개할 특징은 다음과 같다.

  1. 여러 클래스를 한 파일에 넣을 수 있다.
  2. 파일의 이름도 자유롭게 정할 수 있다. (자바 처럼, 클래스 명과 동일해야 하는 규칙 없음)
  3. 디스크 상의 어느 디렉터리에 소스코드 파일을 위치시켜도 상관 없다.

“다만, 대부분의 경우 자바와 같이 패키지별로 디렉터리를 구성하는 편이 낫다. 특히 자바와 코틀린을 함께 사용하는 프로젝트, 자바 클래스를 코틀린 클래스로 마이그레이션할 때는 더더욱 그렇다”



enum / when #

enum

  • 소프트 키워드
    • enum clss : enum 클래스로 사용한다. (즉 class 앞에 사용될 때만 특별한 의미를 갖는 것)
    • enum : 키워드가 아니다. 변수명으로도 사용 가능하다.

when

자바의 if - elseif 는 when (+is)으로 대체할 수 있다.

fun getMnemonic(color: Color) =
    when (color) { // 이 위치에는 식(expression)이라면 모두 들어올 수 있다.
        RED, GREEN -> "Richard"
        YELLOW -> "Jackson"
        ...
    }
// 이러한 '객체'의 경우, '동등성' 비교를 한다.
fun max(c1: Color, c2: Color) =
    when (setOf(c1, c2)) {
        setOf(RED, YELLOW) -> ORANGE
        ...
    }

// 위 예시는 객체를 생성하고 버리기 때문에, 실무에서는 주의해야한다.
fun mixOptimized(c1: Color, c2: Color) =
    when {
        (c1 === RED && c2 === YELLOW) || 
        (c1 === YELLOW && c2 === RED) -> ORANGE
        ...
    }
fun eval(e: Expr): Int =
    when(e) {
        is Num -> e.value
        is Sum -> eval(e.right) + eval(e.left)
        else -> ...
    }
/** 블록의 경우, 마지막 문장이 return 되는 값이다. */
fun eval(e: Expr): Int =
    when(e) {
        is Num -> {
            println("hi")
            e.value
        }
        is Sum -> {
            println("hi")
            eval(e.right) + eval(e.left)
        }
        else -> ...
    }
  • break 를 넣지 않아도 된다.
  • 콤마(,) 사용 가능하다.
  • 객체 경우 → 동등성 비교를 한다.
    • 객체의 경우 객체를 생성하고 버린다는 것에 유의한다.
  • 인자 없이 사용 가능하다.
    • 인자 없이 사용하려면, 각 분기의 조건이 boolean 결과식이어야 한다.

블록의 마지막 식이 블록의 결과라는 규칙은 블록이 값을 만들어내야 하는 경우 항상 성립한다.
즉 when 에서만 성립하는게 아니라 코틀린 내의 모든 곳에 적용되는 규칙이다.



스마트 캐스트 #

스마트 캐스트 : 타입 검사 + 타입 캐스트

fun eval(e: Expr): Int {
    if (e is Num) {
        ...
    }
}



Loop (while / for) #

for <야이템> in <컬렉션>

val oneToTen = 1..10

val tenToOne = 10 downTo 1

val tenToOneBy2Step = 10 downTo 1 step 2

/** Map 예제 */
fun((letter, binray) in binaryReps) { // '구조 분해 문법' 사용
    ...
}

[추가 예시 - ‘범위 검사’]
c in 'a'..'z'
c !in '0'..'9'



예외 처리 #

1. 체크 예외 / 언체크 예외를 구분하지 않는다.

자바에서 체크 예외의 경우 명시적으로 throws 를 작성한다. 하지만 개발자들이 무의미하게 처리(다시 던지거나, 무시하거나)하는 경우가 흔하기 때문에, 코틀린에서는 이렇게 설계했다고 한다.

2. try 는 식이다.

try 의 경우 본문을 반드시 중괄호({})로 감싸야 한다.

val number = try {
    ~~~
} catch () {
    ...
}