본문 바로가기

프로그래밍/Book

[코틀린 인 액션] 2장. 코틀린 기초

함수와 변수

코틀린 함수 기본구조

fun 함수이름 (파라미터 목록) : 반환타입 {
    return 함수 본문
} 
// 아무런 값을 반환하지 않는 함수
fun printHelloWorld() {
    println("Hello World")
}
// 블럭문이 아닌 식으로 정의 가능
fun printHelloWorld() = println("Hello World")

// if는 문장이 아니고 식(expression)이다.
fun sum(a: Int, b: Int): Int {
    return if (a > b) a else b
}

// 식이 본문인 함수
fun maxNum2(a: Int, b: Int) = if (a > b) a else b
  • 반환 타입을 생략할 수 있는이유는 정적 타입 지정 언어여서 컴파일러가 타입추론을 해서 정해준다.

변수

// 타입 생략 가능
val test = "test"

//
val maxNum: Int = 100

// immutable - 변경 불가능
 val name: String = "Yang"

// mutable - 변경가능
 var name2: String "Hong"
  • 기본적으로 Val로 선언하고 꼭 필요한경우 var로 변경

문자열 템플릿

val name = "yang"
println("이름은: $name!")
println("이름은: ${if (name.length > 2) "long name" else "short name"}!")

클래스

class Person(
    val name: String,
    var isMarried: Boolean
)

val person = Person("yang", true)

//getIsMarried가 아니라 변수를 사용하듯 사용하면된다.
//내부적으로 getter를 사용하는것과 같다.
person.isMarried=false
println(person.isMarried) // false

커스텀 접근자

class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() { //프로퍼티 getter 선언 블록을 제거해도 된다
            return height == width
        }
}

enum 과 when

enum

코틀린에서 enum은 class앞에 있을때만 enum이라는 의미를 지니고 다른 곳에서는 이름에 사용할 수 있다(소프트 키워드)

enum class Color {
    RED, GREEN, BLUE;
}
  • 프로퍼티와 메서드가 있는 enum 클래스
enum class Color(
    val R: Int,
    val G: Int,
    val B: Int
) {
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    YELLOW(255, 255, 0),
    BLUE(0, 255, 0),
    GREEN(0, 0, 255);

    fun rgb() = (R * 256 + G) * 256 + B
}

when

함수의 반환값으로 when식을 직접 사용

fun getMnemonic(color: Color) {
    when (color) {
        Color.BLUE -> "Blue color"
        Color.RED -> "Red color"
        else -> "Other color"
    }
}
  • 인자가 없는 when을 사용할 수 있다.
fun mixOptimized(c1: Color, c2: Color) =
    when {
        (c1 == Color.RED && c2 == Color.YELLOW) ||
                (c1 == Color.YELLOW && c2 == Color.RED) -> Color.ORANGE
        (c1 == Color.YELLOW && c2 == Color.BLUE) ||
                (c1 == Color.BLUE && c2 == Color.YELLOW) -> Color.GREEN
        else -> throw Exception("Dirty color")
    }

스마트 캐스트

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
fun eval(e: Expr): Int {
    if (e is Sum) {
        return eval(e.right) + eval(e.left)
    }

    throw IllegalArgumentException("exception")
}

자바의 instanceof와 비슷하게 코틀린에서는 is를 사용해 변수 타입을 검사하는데 is로 타입을 검사하고나면 캐스팅하지 않고 사용한다.
is를 통해 원하는 타입인지 검사하고 나면, 굳이 변수를 원하는 타입으로 캐스팅하지 않고 사용해도 컴파일러가 캐스팅을 해준다.

while과 for 루프

while

코틀린에는 while과 do-while이 존재하며 자바와 동일하다.

for

코틀린에는 자바의 기본 for루프(초기값;종료여부;증감값;)가 없다.
for-each와 유사한 형태로 범위를 사용해서 이터레이션을 구현한다.

for (n in 0 .. 10)
    println(n) //0,1,2,3,4 ... 9,10


for(i in 100 downTo 1 step 2)
    println(i)  //100,98,96 ... 4,2

범위의 ..는 항상 끝값을 포함한다.

  • 맵에 대한 이터레이터
    컬렉션에 대한 이터레이션을 할때는 for .. in 루프를 자주 사용한다.
val binaryReps = TreeMap<Char, String>
for (c in "A".. "F") { // A부터 F까지의 문자의 범위
    binaryReps[c] = Integer.toBinaryString(c.toInt()) // c를 키로 c의 2진 표현을 맵에 넣음
}

for ((key, value) in binaryReps) { //맵 반복
    print("$key = $value")
}
  • in으로 컬렉션이나 범위의 원소검사
    in을 사용해서 범위에 속하는지 검사할 수 있다.
    !in을 사용하면 범위에 속하지 않는지 검사할 수 있다.
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z' 
fun isNotDigit(c: Char) = c !in '0'..'9' 

예외처리

코틀린의 예외처리는 자바와 비슷하다.

if (percentage !in 0..100) {
    throw IllegalArgumentException("Exception")
}

throw역시 식이여서 다른 식에 포함될 수 있다.

val percentage =
    if (number in 0..100) number 
    else throw IllegalArgumentException("Exception")

try, catch, finally

자바와 마찬가지로 예외 처리에 try, catch, finally 절을 함께 사용한다.
다른점은 throws절이 코드에 없다.

fun readNumber(reader: BufferedReader): Int? {
    try {
        return Integer.parseInt(reader.readLine())
    } catch (e: NumberFormatException) {
        return null
    } finally {
        reader.close()
    }
}

readNumber(BufferedReader(StringReader("239")))

코틀린은 checked와 unchecked exception을 구분하지 않는다.
코틀린에서는 함수가 던지는 예외를 지정하지 않고 발생한 예외를 잡아내도 되고 잡아내지 않아도 된다.

참고문서

코틀린 인 액션 - 드미리 제로프, 스트나 이코바