코틀린 while 루프는 자바와 동일하다.
for는 자바의 for-each 루프에 해당하는 형태만 존재한다.
이런 for 루프는 컬렉션에 대한 이터레이션에 가장 많이 쓰인다.
이터레이션(Iteration)이란?
결과를 생성하기 위한 프로세스의 반복을 뜻한다.
while(조건) {
/* ... */
}
그리고 do while 루프
do {
/*...*/
} while(조건)
코틀린의 for는 범위를 사용한다.
val oneToTen = 1..10
코틀린의 범위는 양 끝을 포함하는 구간이다. 첫번째 값인 1과 마지막 값인 10을 모두 포함한다는 뜻이다.
이런 식으로 어떤 범위에 속한 값을 일정한 순서로 이터레이션 하는 경우를 수열이라고 부른다.
fun fizzBuzz(i: Int) = when {
i % 15 == 0 -> "FizzBuzz " // i가 15로 나눠 떨어지면(3 또는 5) FizzBuzz 반환
i % 3 == 0 -> "Fizz " // i가 3으로 나눠떨어지면 Fizz 반환
i % 5 == 0 -> "Buzz " // i가 5로 나눠떨어지면 Buzz 반환
else -> "$i" // 다른 경우에는 그 수 자체를 반환
}
for ( i in 1..100 ) { // 1부터 100까지 순차적으로
... print(fizzBuzz(i))
}
for (i in 100 downTo 1 step 2) { // 100부터 1까지 2씩 건너뛰어서 ( step을 증가값이 아니라 건너뛰는 개념으로 이해하자. 사실은 역방향 수열에서 절대값이 2만큼 증가하는 이터레이션이지만 고려하기 귀찮다.)
... print(fizzBuzz(i))
}
만약 마지막 범위를 포함하고 싶지 않다면 until을 사용한다.
for(x in 0 until size)
는
for(x in 0..size-1) 과 같다.
val binaryReps = TreeMap<Char, String>() // 키에 대해 정렬하기 위해 TreeMap을 사용한다.
for ( c in 'A'..'F' ) { // A부터 F까지 문자의 범위를 사용해 이터레이션한다.
val binary = Integer.toBinaryString(c.toInt()) // 아스키 코드를 2진 표현으로 바꾸는 메서드
binaryReps[c] = binary // c를 키로 c의 2진 표현을 맵에 넣는다.
}
for ((letter, binary) in binaryReps) {
println("$letter = $binary")
}
.. 연산자를 숫자 타입의 값뿐 아니라 문자 타입의 값에도 적용할 수 있다.
binaryReps[c] = binary 는 자바의 binaryReps.put(c, binary) 와 같다. 코틀린 기능상 get과 put을 사용하는 대신 map[key]나 map[key] = value를 사용해 값을 가져오고 설정할 수 있어서 더 편리해졌다.
var list = arrayListOf("10", "11", "1001")
for ((index, element) in list.withIndex()) { // 인덱스와 함께 컬렉션을 이터레이션 한다.
println("$index: $element")
}
withIndex의 정체에 대해서는 다음 장에서 살펴보자.
in 연산자를 사용해 어떤 값이 범위에 속하는지 검사할 수 있다. 반대로 !in을 사용하면 어떤 ㄱ밧이 범위에 속하지 않는지 검사할 수 있다.
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'
fun isNotDigit(c: Char) = c !in '0'..'9'
-> println(isLetter('q')) // q가 포함되어 있는가?
true
-> println(isNotDigit('x')) // x가 포함되어 있지 않은가?
true
in과 !in 연산자를 when 식에서 사용해도 된다.
fun recognize(c: Char) = when(c) {
in '0'..'9' -> "It's a digit!"
in 'a'..'z' in 'A'..'Z' -> "It's a letter!"
else -> "I don't know..."
}
-> println(recognize('8'))
It's a digit!
Comparable(비교가 가능한 인터페이스를 구현한 클래스)을 사용하는 범위의 경우 그 범위 내의 모든 객체를 항상 이터레이션하지는 못한다. 예를 들어 'Java'와 'Kotlin' 사이의 모든 문자열을 이터레이션할 수 있을까? 그럴 수 없다. 하지만 in 연산자를 사용하면 값이 범위 안에 속하는지 항상 결정할 수 있다.
-> println("Kotlin" in "Java".."Scala") // "Java" <= "Kotlin" && "Kotlin" <= "Scala" 와 같다.
true
String에 있는 Comparable 구현이 두 문자열을 알파벳 순서로 비교하기 때문에 여기 있는 in 검사에서도 문자열을 알파벳 순서로 비교한다.
-> println("Kotlin" in setOf("Java", "Scala")) // 이 집합에는 Kotlin이 들어있지 않다.
false
위 예제처럼 컬렉션에도 in 연산을 사용할 수 있다.