chapter 2. Kotlin Basics

kotlin function body

function-body

kotlin의 function 구조는 위와 같다.

expression

Kotlin은 반복문(for, while)을 제외하고는 expression으로 판단된다. (If, when 등) expression은 value를 갖는다는 점에서 statement와 차이점을 보인다. 반면 java에서는 모든 control structure들이 statement이다.

여기서 value를 갖는다는 것은 expression 자체(expression의 결과)가 value를 갖는 것을 말한다.

// 예를 들면 아래 if expression은 value를 갖고 있다.
fun max(a: Int, b: Int): Int = if (a > b) a else b

expression body

Block body와 expression body로 function의 body를 구분한다.
Block body: {}으로 body가 쌓여진 일반적인 함수.
Expression body: {} 없이 구현된 함수. 보통 one line function에서 사용하는 함수.

variable

변수에 타입을 명시하지 않아도 된다.
명시할수도 있는데, 초기 값을 넣어주지 않으면 타입 추론이 안되므로 명시해주어야 한다.

val(from value): immutable (final in java)
var(from variable): mutable

기본적으로 val을 사용하고, 수정이 필요한 경우만 var를 사용하도록 한다.
var이 change value를 허락해도, type은 fix되서 바뀔 수 없다.

$로 local variable에 접근할 수 있고, 이건 $(expression) 으로도 사용이 가능하다.

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

class

kotlin은 public이 default라 public을 생략할 수 있다.
property를 선언하면 기본적으로 내부적으로 getter/setter가 같이 선언된 것이라고 보면 된다.
그냥 class의 property를 사용하면 java의 getter를 호출해준다.

getter/setter 외의 custom accessors를 만들 수 있다.
custom accessors와 function을 만드는것의 차이는

  • 성능 상으로는 차이가 없다
  • 가독성에만 차이가 있다

package

kotlin에도 package가 있고 java의 package 정책과 유사하다.
import로 class와 method를 구분하지 않고 method도 import할 수 있다.

여러 class를 하나의 file에 넣을 수 있다.

enum

enum이 java랑 좀 다르다.

// 예제가 이해하기 편할 듯 하다.
enum class Color(
    val r: Int, val g: Int, val b: Int
) {
    RED(255, 0, 0), ORANGE(255, 165, 0),
    YELLOW(255, 255, 0), GREEN(0, 255, 0), BLUE(0, 0, 255),
    INDIGO(75, 0, 130), VIOLET(238, 130, 238);

    fun rgb() = (r * 256 + g) * 256 + b
}
>>> println(Color.BLUE.rgb())

when

when과 함께 쓰일 때 enum의 효과가 더 크다.
when은 java의 switch와 비슷한데, 더 파워풀하다.

  • any objects나 들어올 수 있다. (set 등)

no arg when 을 사용할 때도 있다.

  • 가독성은 좀 떨어질 수 있다.
  • 성능상 이점을 얻기 위할 때 사용할 수 있다.
  • no arg이기 때문에 extra objects를 생성하지 않는다는 장점이 있다.

is

is는 java의 instanceof와 유사하다.
instanceof 체크하고 type casting을 해야하는 java와 달리 is는 compiler가 smart cast를 해준다. (더 강력하고 편리하다)

  • smart cast를 위해서 property가 val이어야 하고, custom accessor를 가질 수 없다. 그렇지 않으면 property에 대한 access가 동일한 값을 주는지에 대해 보장할 수 없다.
  • 명시적 type cast는 as를 이용한다.

block value

ifwhen의 branch에 block을 가질 수 있다. block이 있으면, block의 가장 마지막 expression이 block의 result가 된다.

  • if나 when은 kotlin에서 expression이고 반환 값을 갖는다는 점을 상기하자.
fun evalWithLogging(e: Expr): Int =
    when (e) {
        is Sum -> {
            val left = evalWithLogging(e.left)
            val right = evalWithLogging(e.right)
            println("sum: $left + $right")

            left + right // return value
        }
    }

loop

java의 for loop과 완전히 매칭되는 for loop은 없다.

  • while은 java랑 완전히 같음.

그래서 range, progression을 사용한다.
range는 1..10 처럼 사용될 수 있고, 이런 range를 progression이라고 한다.

  • range는 char에도 된다. (‘A’..’F’, ‘0’..’9’)

또, downTo, step, until을 제공하는데 직관적이다.

for (i in 1..10)
for (i in 100 downTo 1 step 2)
for (i in 0 until size)

exception

exception은 java와 유사하다.
try, catch, finally도 java와 유사하다.

java와 다른 점은 kotlin의 throw, try도 expression이다.

  • try는 if와 다르게 {} body를 항상 가져야 한다.
    val number = try {
          Integer.parseInt(reader.readLine())
      } catch (e: NumberFormatException) {
          return
      }
    

또 다른 점은 kotlin은 함수에 throws를 명시하지 않아도 된다.

  • java와 다르게 checked exceptionunchecked exception을 구분하지 않는다는 것.
  • 경험 상 checked exception에서 rethrow나 ignore exception 같은 처리들이 불필요하게 수행되는 경우가 많아 구분을 하지 않는 설계를 했다고 한다.