Kotlin

저번 챕터 때 작성하지 않은 코틀린 스크립트 실행 방법이 빠져있어서 추가해본다.

이 방식은 셔뱅(shebang)이라고 한다.

 

#!/usr/bin/env kotlinc-jvm -script

println(Runtime.getRuntime().availableProcessors())

 

실행권한을 부여하고 스크립트를 실행 시, 해당 컴퓨터 CPU 의 수를 출력한다.

 

맥북에서 실행하니 8 이라는 숫자가 나온다.

 

이번 파트에서는 코틀린의 컨셉에 대해 정리해보도록 한다.

 

1. 더 적은 타이핑

  • 세미콜론 생략 가능함
    • 6 + 2 와 같이 코드를 입력해도 동작한다. (마치 파이썬 처럼)
  • 변수 타입 지정 생략 가능
    • 값에 기반하여 타입을 정의한다.
    • 명확한 타입의 경우에만 생략이 가능하다.
val greet = "hello"
println(greet)
println(greet::class)
println(greet.javaClass)

 

 

val greet 에 문자열로 초기화 한 순간, greet 은 문자열 타입이 된다.

  • 클래스와 함수는 생략 가능
fun nofluff() {
    println("nofluff called...")
    throw RuntimeException("oops")
}

println("not in a function, calling nofluff()")
try {
    nofluff()
} catch(ex: Exception) {
    val stackTrace = ex.getStackTrace()
    println(stackTrace[0])
    println(stackTrace[1])
}

 

위의 코드를 실행 시, 아래와 같은 결과가 나온다.

 

not in a function, calling nofluff()
nofluff called...
Standalone.nofluff(standalone.kts:3)
Standalone.<init>(standalone.kts:8)

 

클래스 이름은 파일 이름을 보고 추론한다.

 

  • try-catch 는 선택사항
    • 방어적 프로그래밍을 하기 위해선 필요하나, 없어도 동작한다.
println("Lemme take a nap")
Thread.sleep(3000)
println("ah that feels good")

 

Thread.sleep 은 InterruptedException 에 대한 고민이 필요하지만, 없어도 동작을 한다.

 

2. 현명한 경고

  • 사용하지 않는 파라미터에 대한 경고 후 실행이 되며, -Werror 추가 시 경고를 오류처럼 다루며 실행시키지 않음
    • ex) kotlinc-jvm -Werror -script 파일명.kts

아래와 같은 예시를 작업하고, 컴파일 하면 경고가 나오면서 완료됨

// UnusedInMain.kt

fun compute(n: Int) = 0

// kotlin 1.3 버전 부터 사용하지 않는 args 를 생략할 수 있다고 함
fun main() = println(compute(4))
fun main(args: Array<String>) = println(compute(4))

 

경고가 나면서 빌드 됨

 

 

정상적으로 실행 됨

 

jar 로 빌드 후 실행하였다.

 

3. var 보다는 val

  • var 는 뮤터블(mutable, 변할 수 있는), val 은 이뮤터블 (immutable, 변경할 수 없는) 의 속성을 가짐 (이건 좀 헷갈리는 듯)
  • 코틀린은 val과 이뮤터블을 기본으로 사용

 

4. 향상된 동일성 체크

  • 코틀린은 기본적으로 NULL 체크를 안전하게 다룬다.
#!/usr/bin/env kotlinc-jvm -script

println("hi" == "hi") //true
println("hi" == "Hi") //false
println(null == "hi") //false
println("hi" == null) //false
println(null == null) //true

 

결과는 아래처럼 나온다.

 

true
false
false
false
true
equality.kts:5:9: warning: condition 'null == "hi"' is always 'false'
println(null == "hi") //false
        ^
equality.kts:6:9: warning: condition '"hi" == null' is always 'false'
println("hi" == null) //false
        ^
equality.kts:7:9: warning: condition 'null == null' is always 'true'
println(null == null) //true
        ^

 

5. 문자열 템플릿

  • $ 심볼을 변수 앞에 붙여주면 어떤 변수라도 문자열 안에 들어감
  • ${} 으로 감쌀 수 있음
#!/usr/bin/env kotlinc-jvm -script

val price = 12.25
val taxRate = 0.08
val output = "The amount $price after tax comes to $${price * (1 + taxRate)}"
val disclaimer = "The amount is in US$, that's right in \$only"
println(output)
println(disclaimer)

 

 

6. RAW 문자열

  • 이스케이프(\) 문자열 필요 없이 홑따옴표('), 쌍따옴표(") 있는 그대로 입력이 가능하다.
  • 변수는 아까처럼 $변수 로 사용하므로, 이스케이프(\)가 필요하다.
  • 멀티라인 문자열을 지원한다. (""" 문자열 """)
  • 멀티라인 문자열 사용 시, 개행 후 첫 문자열에 | 문자를 넣으면 들여쓰기가 무시된다. (이스케이프 문자도 사용할 수 있음)

 

#!/usr/bin/env kotlinc-jvm -script

fun createMemoFor(name: String): String {
    if (name == "Eve") {
        /*
        val memo = """Dear $name, a quick reminder about the
            |party we have scheduled next Tuesday at
            |the 'Low Ceremony Cafe' at Noon. | Please plan to..."""
        return memo.trimMargin()
        */
        
        // 앞에 ~ 문자가 붙은 것만 trim 처리 됨
        val memo = """Dear $name, a quick reminder about the
            ~party we have scheduled next Tuesday at
            the 'Low Ceremony Cafe' at Noon. | Please plan to..."""
        return memo.trimMargin("~")
    }

    return ""
}

println(createMemoFor("Eve"))

 

7. 표현식은 많이, 명령문은 적게

  • 명령문(statement) 보다는 표현식(expression) 이 좋다.
val age = 18

/* 해당 방식은 지양한다.

var status: String

if (age > 17) {
	status = "man"
} else {
	status = "boy"
}
*/

val status = if (age>17) "man" else "boy"

println(status)

 

  • try ~ catch 도 표현식으로 취급하여 마지막 부분이 결과가 된다.
Welcome to Kotlin version 1.6.10 (JRE 17.0.1+1)
Type :help for help, :quit for quit
>>> fun tryExpr(blowup: Boolean): Int {
... return try {
...     if (blowup) {
...         throw RuntimeException("fail")
...     }
...     2
... }
... catch(ex: Exception) {
...     4
... } finally {
...     // ...
... }
... }
>>> println(tryExpr(false))
2
>>> println(tryExpr(true))
4

 

  • a = b 는 실행이 되지만, a = b = c 와 같은 코드는 실행되지 않는다.
    • 코틀린은 델리게이션(Delegate, 위임)을 통해 get, set 하도록 허용한다. (이 부분은 어떤 얘긴지 모르겠다.)