1. for문과 foreach문
fun main() {
for (i in 1..10)
println(i) //output : 1, 2, 3, 4, ... 10
(1..10).forEach { i ->
println(i) //output : 1, 2, 3, 4, ... 10
}
}
일반적인 for문과 forEach문 사용방법입니다.
모든 작업은 for문으로 대체가 가능합니다.
그럼에도 불구하고 forEach문을 사용하는 이유는 무엇일까요??
2. Performance
1) 일반적인 반복문에 대한 시간 계산
fun loop(i: Int){
for(i in 0..i){}
}
fun main() {
println("ForLoop Time: " + measureNanoTime {
for (i in 0..10000) { loop(i) }
})
println("ForEach Time: " + measureNanoTime {
(0..10000).forEach { i -> loop(i) }
})
}
일반적인 반복문에선 for문이 우세합니다.
이 이유는 단순 계산작업일 뿐더러 forEach문은 람다형식으로 함수를 계속 호출하는 형태이므로 퍼포먼스가 저하가됩니다.
2) Collection 의 반복문 시간 계산
fun loop(i: Int){
for(i in 0..i){}
}
fun main() {
val list = (1..10000).toList()
println("ForLoop Time: " + measureNanoTime {
for (i in list) { loop(i) }
})
println("ForEach Time: " + measureNanoTime {
list.forEach { i -> loop(i) }
})
}
자바의 자료구조에는 List, Set, Map이 있습니다.
이 클래스들은 Collection을 상속받고 있으며 해당 클래스들에 대한 몇몇 함수들은 inline을 제공하게 됩니다.
그 중 forEach도 포함되는데, 그덕에 for문보다 더 좋은 퍼포먼스를 낼 수 있습니다.
3) asSequence()
fun loop(i: Int){
for(i in 0..i){}
}
fun main() {
val list = (1..100000).toList()
println("ForLoop Time: " + measureNanoTime {
for (i in list) { loop(i) }
})
println("ForEach Time: " + measureNanoTime {
list.forEach { i -> loop(i) }
})
list.asSequence()
println("ForEach Time: " + measureNanoTime {
list.forEach { i -> loop(i) }
})
}
※ 좀 더 차이를 보기위해 반복횟수를 10,000 -> 100,000으로 변경했습니다.
asSequence() 함수를 통해 list호출시 최적화를 진행할 수 있습니다.
asSequnece()는 lazy collection의 한 종류인데, 체인 형식으로 collection이 호출될 경우(list -> filter -> map)
list는 값들을 저장하기위해 temp collection을 따로 만든 후 값을 저장하는 형태를 띄우게 됩니다.
결국 이는 오버헤드로 이어지며 퍼모먼스가 저하됩니다.
하지만 Java 8 에서는 stream에 대응되는 lazy collection이 제공되므로 이를 해결할 수 있게 되었습니다.
4) run
import kotlin.system.measureNanoTime
fun loop(i: Int){
for(i in 0..i){}
}
fun main() {
val list = (1..10000).toList()
println("ForEach Time: " + measureNanoTime {
list.forEach { i -> loop(i) }
})
println("ForEach Time: " + measureNanoTime {
list.forEach { i -> if(i > 5000) return@forEach
else loop(i) }
})
println("ForEach Time: " + measureNanoTime {
run loop@{
list.forEach { i -> if(i > 5000) return@loop
else loop(i)
}
}
})
}
두번째의 return@forEach문은 for문에서의 continue와 같은 역할을 합니다.
즉, 중간에 break가 되지 않았습니다.(여기서 @forEach는 list.forEach의 forEach입니다.)
세번째 return@loop는 run이라는 람다함수를 제공함으로 써 아에 forEach문 loop를 빠져나간 것입니다.
때문에 for문의 break역할을 하게 됩니다.
'프로그래밍 > Kotlin' 카테고리의 다른 글
Kotlin] MutableList 기능 설명 (0) | 2020.07.19 |
---|---|
Kotlin] List 기능 설명(vector와 array의 차이점) (0) | 2020.07.18 |
Kotlin] for문, while문 사용법 (0) | 2020.07.17 |
Kotlin] 코틀린 if문 형식(when, 범위지정) (0) | 2020.07.16 |
Kotlin] 변수 입력 방법.(타입 캐스팅, null) (0) | 2020.07.16 |
댓글