If expression
코틀린에서 if문은 표현식(값을 반환한다.)이다. 따라서, 일반 if가 역할을 잘 수행하기 때문에 삼항 연산자 (조건 ? then : else)가 없다.
var max = a
if (a < b) max = b
// With else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// As expression
val max = if (a > b) a else b
if 표현식의 분기는 블록이 될 수 있다. 이 경우에 블록의 값은 마지막 표현식이다. if 문을 값을 반환하는 식이나 변수에 값을 대입하기 위한 표현식으로 사용하는 경우, else 분기가 필수다.
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
When expression
when은 여러 분기가 있는 조건식을 정의한다. C와 같은 언어의 switch 문과 유사하다.
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
when은 일부 분기 조건이 충족될 때까지 모든 분기에 대해 인수를 순차적으로 일치시킨다.
when은 표현식이나 명령문으로 사용할 수 있다. 표현식으로 사용할 경우 첫번째 일치 분기의 값이 전체 표현식의 값이 된다. 명령문으로 사용하는 경우 개별 분기의 값은 무시된다. if와 마찬가지로 각 분기는 블록이 될 수 있으며 해당 값은 블록의 마지막 표현식이다.
다른 분기 조건이 충족되지 않으면 else 분기가 평가된다.
만약, when이 표현식으로 사용되는 경우 컴파일러가 가능한 모든 경우가 분기 조건으로 덮여 있음을 증명할 수 없는 경우, else 분기는 필수이다.
예) 열거형 클래스 항목 및 봉인된 클래스 하위 유형
enum class Bit {
ZERO, ONE
}
val numericValue = when (getRandomBit()) {
Bit.ZERO -> 0
Bit.ONE -> 1
// 'else' is not required because all cases are covered
}
When 명령문에서 else 분기는 다음 조건에서 필수이다.
- Boolean, enum, sealed class 또는 이들의 nullable type을 다룰 때
- when의 모든 분기가 가능한 케이스를 전부 포함하고 있지 않은 경우
enum class Color {
RED, GREEN, BLUE
}
when (getColor()) {
Color.RED -> println("red")
Color.GREEN -> println("green")
Color.BLUE -> println("blue")
// 'else' is not required because all cases are covered
}
when (getColor()) {
Color.RED -> println("red") // no branches for GREEN and BLUE
else -> println("not red") // 'else' is required
}
여러 사례에 대해 공통적인 동작을 정의할때는 해당 조건을 쉼표로 한줄에 결합한다.
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
임의의 표현식 (상수뿐만 아니라)을 분기 조건으로 사용할 수 있다.
when (x) {
s.toInt() -> print("s encodes x")
else -> print("s does not encode x")
}
범위 또는 컬렉션에 있는 값을 확인할 수 도 있다.
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
is 또는 !is 연산자를 사용하여 값이 특정 타입인지 체크하는 코드를 작성할 수 있다. smart cast가 동작하기 때문에 추가 검사 없이 타입의 멤버 함수나 속성에 접근이 가능하다.
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
when은 if- else if 체인의 대체제로 사용할 수 있다. when의 인수가 제공되지 않으면 분기 조건은 논리 표현식이 되고 참인 경우에 해당 분기가 실행된다.
when {
x.isOdd() -> print("x is odd")
y.isEven() -> print("y is even")
else -> print("x+y is odd")
}
when의 주체로 변수를 사용할 수 있다. when의 인수로 선언된 변수의 범위는 when의 본문으로 제한된다.
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
For loops
코틀린에서 for 루프는 iterator를 제공하는 모든 항목을 반복한다. C#의 foreach와 유사하다. for 루프의 본문도 블록으로 감쌀 수 있다.
for (item in collection) print(item)
for (item: Int in ints) {
// ...
}
앞서 말했듯이, for는 반복자를 제공하는 모든 항목을 반복한다. 이는 다음을 의미한다.
- 멤버 함수 또는 확장 함수로 Itertator<> 를 반환하는 iterator()함수가 존재한다.
- 멤버 함수 또는 확장 함수 next()가 존재한다.
- Boolean을 반환하는 hasNext() 멤버 함수 또는 확장 함수가 존재한다.
이 세가지 조건은 모두 연산자로 표현되어 있어야 한다.
숫자 범위의 반복
범위 도는 배열에 대한 for 루프는 반복기 개체를 생성하지 않는 인덱스 기반 루프로 컴파일 된다.
While loops
while 및 do-while 루프는 조건이 충족되는 동안 계속해서 본문을 실행한다. 그들 사이의 차이점은 상태 확인 시간이다.
- while : 조건 확인 → 참이면 본문을 실행 → 조건 확인
- do-while : 본문 확인 → 조건 확인 → 참이면 반복
따라서, do-while 의 본문은 조건에 관계없이 한 번 이상 실행된다.
while (x > 0) {
x--
}
do {
val y = retrieveData()
} while (y != null) // y is visible here!