목차
Function
- fun name(parameters): return Type { body }
- 각 파라미터는 default 값을 가질 수 있으며
- 함수를 호출할 때 파라미터 이름을 명시하면 선언 순서와 상관없이 전달할 수 있다.
fun message(name:String, message:String="Hello", age:Int):String {
return "Age:$age, $message, $name"
}
fun message2(name:String, age:Int, message:String="Hello"):String {
return "Age:$name, $age, $message"
}
fun main() {
println(message(age=22, name="user"))
println(message2("B", 20))
}
// 디폴트 매개변수를 사용할 때 주의할 점
// 함수 중간 디폴트 매개변수가 들어갔는데 message("A", 20)를 사용하면
// 컴파일러가 어느 매개변수를 뜻하는지 모르기때문에 꼭 명시해주어야 한다.
// -> message(name="A", age=20)
→ default 매개변수는 왠만하면 끝에 모아두는걸 추천
- overriding 된 함수는 base 함수의 default 값을 동일하게 사용한다.
- default 값이 있는 파라미터와 없는 파라미터를 동시에 사용하는 경우 기본값 보다 뒤쪽에 있는 파라미터는 이름을 지정해주어야 한다.

- 람다식을 파라미터로 받을 수 있으며 람다식이 마지막 파라미터인 경우 괄호 밖에 적을 수 있다.
fun foo(name:String, ex:()->Unit) {
println(name)
ex()
}
fun bar(param:Int=1, ex:()->Unit){
println(param)
ex()
}
fun main(){
foo("abc") { println("Hello") }
bar(1) { println("World") }
bar { println("Kotlin") }
}
- varargs 키워드를 이용해 가변 개수의 파라미터를 받을 수 있다.
fun foo(vararg items:Int) {
for(i in items)
print("$i ")
}
fun foo2(vararg items:Int) {
for(i in items)
print("$i ")
}
fun main() {
foo()
foo(1)
foo(1, 2, 3)
// 원래는 foo2(list[0], list[1], list[2], list[3]) 이런식으로 호출을 해주어야 하는데
// 그걸 줄여주는 역할 intArrayOf
val arr = intArrayOf(1, 2, 3 , 4)
foo2(*arr)
}
- infix 함수 만들기
- Member 함수 또는 Extension은 Infix 형태로 정의 가능
- 파라미터는 하나만 받아야 하고 기본값이 없어야 함
- 상대방이 반드시 있어야 한다.
- 중위연산자 정의
- 우리가 프로그램에서 사용할 때도 보면 1 + 2 의 ‘+’도 어찌보면 String 이다.
- “이걸 우리가 정의 해보자”와 같은 느낌 1.plus(2)
- 중위연산자 정의
infix fun Int.diff(other:Int) = if(this > other) this-other else other-this fun main(){ var diff = 3 diff 2 // 3.diff(2) 과 같음 println(diff) diff = 10 diff 33 println(diff) }
- Local functions : 다른 함수 내부에 선언된 함수
- local 함수는 외부 함수의 지역 변수에 접근 가능- 자바에서는 안되는 기능, 이 이유 때문에 코틀린이 함수형 프로그래밍 언어 라고도 불림
fun foo(){ var count = 0 fun add(){ println(count) count++ if(count < 3 ) add() } add() } fun main(){ //add() // Error foo() }
- Tail recursive functions
- Tail call : 함수의 마지막 코드가 함수 호출인 것 - 최적화 대상
- Tail recursion : 함수의 마지막 코드로 재귀 호출을 하는 것
- 함수의 마지막 줄이 다른 함수 호출이라는 것은 이전 함수에서 더 이상 실행 할 코드가 없다는 뜻 → 콜 스택에 모든 정보를 남길 필요가 없다 → 성능을 높일 수 있다.
- 재귀 호출 함수를 tail recursion 으로 작성했다면 tailrec 키워드를 이용해 최적화를 할 수 있다.
val eps = 1E-10
tailrec fun findFixPoint(x: Double = 1.0) : Double = if (Math.abs(x - Math.cos(x)) < eps)
x else findFixPoint(Math.cos(x))

고차원 함수와 람다
- 코틀린의 함수들은 First - class → 함수를 다른 변수와 동일하게 다룰 수 있다.
- 함수를 파라미터로 받을 수 있다.
- 함수의 실행 결과로 함수를 반환할 수 있다.
- 함수를 변수나 자료구조에 저장할 수 있다.
- 고차원 함수
- 함수를 파라미터로 받을 수 있다.
- 함수의 실행결과로 함수를 반환할 수 있다.
- 함수의 타입 표기법
- ( parameter type , parameter type.. ) -> return type
- ( ) -> Unit
- (Int) -> Int 등으로 파라미터 정의 및 함수의 return type 정의 가능
- Top level 함수와 확장 함수는 :: 로 참조할 수 있다.
함수 return
fun getBody(type:Int):()->Unit {
return if(type%2==0){
fun(){
println("Hello")
}
} else {
fun(){
println("World")
}
}
}
fun main(){
val f1 = getBody(1)
f1()
val f2 = getBody(2)
f2()
}
함수를 변수에 할당하기, 함수를 파라미터로 받기
fun foo(i:Int, f:(Int)->Int):Int {
return f(i)
}
fun bar(i:Int):Int = -i
fun main(){
val f1 = ::bar // 타입 추론
val f2:(Int)->Int = ::bar // 타입 지정
f1(1)
f2(-1)
foo(1, fun(v:Int):Int{ return v*10 }) //익명 함수 전달
foo(1) { it * 100 } //람다식
foo(1, ::bar)
}
- 람다식
함수로 선언되지는 않지만 함수 파라미터로 전달 가능
람다식이 함수의 마지막 파라미터인 경우 파라미터 바깥에 선언할 수 있다.
람다식이 사용하는 파라미터가 하나밖에 없을 경우 it을 사용할 수 있다.
- 람다식 단독으로는 return을 사용할 수 없다.
- return은 함수 또는 익명 함수 안에서만 사용할 수 있다.
- 함수 안의 람다식을 의도대로 return 하기 위해서는 Qualified return을 사용할 수 있다.
- https://kotlinlang.org/docs/returns.html#return-to-labels
- 수신자가 있는 함수의 타입 표기
- ReceiverType.(parameter types) → return 의 형태
-
val foo: String.(Int)->String = { times -> this.repeat(times) } fun main(){ val result = "Hello".foo(3) println(result) }
- 해당 수신자는 함수 내에서 this로 접근 할 수 있다.
Inline functions
- 함수 파라미터로 넘어가는 람다식은 익명 객체를 만들게 되는 부하가 있다.

- inline 함수로 지정할 경우 객체 생성 + 함수 호출 대신 람다식을 포함한 해당 함수의 코드를 삽입한다.

Operator overloading
https://kotlinlang.org/docs/operator-overloading.html
- 기본 연산자를 overloading 해서 사용할 수 있다.
- 단항 연산자 예제

Array & Collections
- Array : 기본 타입
- 하나의 변수에 여러 값을 저장하기 위한 연속된 메모리 공간
- 생성할 때 크기가 정해진다.
- List : Collection
- 하나의 변수에 여러 값을 저장하기 위한 불연속 메모리 공간
- List - immutable list. 생성 후 수정할 수 없다.
- MutableList - mutable list. 수정할 수 있다.
Array
- Array
- 배열을 나타내는 데이터 타입
- get(index) 함수 또는 [index]를 이용해 값에 접근한다.
- 초기화 방법 1 : arrayOf( ) 함수를 이용해 값을 초기화
-
fun main() { val arrayOfInt = arrayOf(1, 2, 3) // Array<Int> val arrayOfAny = arrayOf(1, "2", false) // Array<*> println(arrayOfInt[0]) println(arrayOfAny[2]) }
-
- 초기화 방법 2 : Array의 생성자 사용
-
fun main() { val arrayOfInt = Array(3) { it } println(arrayOfInt[2]) }
- size + 초기화 람다식
- 람다식에는 Array의 index가 파라미터로 전달된다.
-
기본 타입
- Primitive types: xxxArrayOf( )함수를 이용해 값을 초기화
- 기본 타입들은 Array 생성 함수가 있다.
- charArrayOf, intArrayOf, longArrayof
- floatArrayOf, doubleArrayOf
- shortArrayOf, byteArrayOf, booleanArrayOf
-
val x: IntArray = intArrayOf(1, 2, 3) x[0] = x[1] + x[2] println(x[0])
-
- 커스텀 타입을 사용하고 싶을 때는 Array 사용
-
data class Test(val value:Int) val arr2 = Array(10) { Test(it) }
- Array의 속성과 주요 함수
- size:Int
- any:Boolean - 항목이 하나라도 있으면 true
- any(predicate:(T)->Boolean): Boolean - 조건을 만족하는 항목이 있는가
- filter(predicate:(T)->Boolean):List - 조건을 만족하는 항목만 골라서 반환
- find(predicate:(T)->Boolean):T? - 조건을 만족하는 첫번째 항목. 없을 수 있음
- forEach(action:(T)->Unit) - 모든 항목에 공통으로 처리할 행동을 지시
- isEmpty, isNotEmpty, isNullOrEmpty
-
fun main() { val arr = Array(5) {it * 2} println(arr.size) // 반환형 int print(arr.any()) // 항목이 하나라도 있으면 true 반환 val arr2 = arr.filter { it > 5 } // arr의 모든 값에 대해 { } 안에 있는 문을 실행하여보고 true를 반환하는 요소들만 // 새로운 리스트로 반환을 해준다. val result = arr.find { it > 10 } // 최초로 찾은 값만 return , null일 수도 있다. arr.forEach { print("$it") } // 모든 항목에 대해 { } 문 안의 코드를 공통으로 처리함 }
- find : 최초로 만족하는 항목을 찾고 싶을 때
- filter : 조건을 만족하는 항목만 모은 새 리스트가 필요할 때
- forEach : 모든 항목에 대해 하고 싶은 동작이 있을 때
- map : 원본 배열(리스트)를 이용해 새로운 데이터를 가진 배열(리스트) 가 필요할 때
- 이 중에서 원본 배열과 반환형이 다른 것은 : filter, map
- find는 만족하는 항목을 찾으면 루프를 끝까지 돌지 않지만, filter, forEach, map은 무조건 끝까지 루프를 돌린다.
fun main() { val users = arrayOf("Sam", "James", "Petter", "Jack") val usersLength = users.map {it.length} val longNames = users.filter {it.length > 4} users.forEach { println(it) } // 리스트가 끝날 때 까지 반복됨 val nameStartingWithJ = users.find { it.startsWith("J") } // James 만 찾고 루프가 멈춤 }
Collections
- 0개 이상의 다양한 수의 아이템들의 집합.
- List: 순서를 가지며 정수형의 index 로 접근할 수 있는 type.
- Set: 순서를 가지지 않고 중복을 허용하지 않는 type.
- Map(Dictionary): key-value 쌍을 가지는 타입. key는 중복을 허용하지 않으며 각 키는 하나의 값을 가진다. 값은 중복 가능하다.
- read-only interface vs mutable interface
- 항목에 접근 할 수만 있는가? 항목을 추가/삭제/업데이트 할 수 있는가?
- val 로 선언된 collection이라도 mutable 이면 항목의 추가/삭제는 가능하다
- List<T> : 정해진 순서에 따라 항목을 지정하고 index를 이용해 접근한다.
- 중복된 값을 저장할 수 있다.
- List(size) { } 와 같이 생성자로 초기화할 수 있다.
- MutableList<T> : 항목을 추가하거나 삭제할 수 있는 List
- MutableList(Size) { } 와 같이 생성자로 초기화할 수 있다.
- Set<T> : 순서가 정해지지 않고 중복을 허용하지 않는 데이터들의 집합
- null을 허용하는 경우, null도 한 개만 저장 가능
-
fun main() { val list1 = listOf(1, 2, 3) val list2 = listOf(3, 2, 1) val set2 = setOf(3, 2, 1) println(list1 == list2) // 리스트는 갯수가 같고 각 인덱스의 모든 값이 같아야 true println(list1 == set2) // set은 순서가 없기 때문에 순서 상관 없이 같은 데이터면 true }
- MutableSet<T> : 순서가 정해지지 않고 중복을 허용하지 않는 데이터들의 집합
자바의 JDBC를 이용해 DB의 결과값들의 받아 올때 사용하는 ResultSet ResultSet rs = stmt.executeQuery(); 도 결국 iterator

- Map<K, V> : 중복되지 않는 Key와 짝지어진 Value를 저장한다.
- MutableMap<K, V>
Iterators
- Collection의 항목들을 traverse
fun main() {
val set1= setOf(1, 2, 3)
val it = set1.iterator()
while(it.hasNext()) { // iterator() 함수로 iterator 객체를 얻음
println(it.next())
}
for(s in set1) { // for를 사용 traverse
println(s)
}
set1.forEach {// forEach를 사용 traverse
println(it)
}
}
- Mutable 타입은 iterator에서 add, remove, set이 가능

Scope Functions
- 특정 개게를 대상으로 하는 코드 블록
- 람다식 기반으로 일시적인 Scope를 적용함.
- let, run, with, apply, also, takeIf, takeUnless

let
- 확장 함수로 수신 객체가 암시적으로 제공됨.
- 해당 객체는 파라미터로 명시적으로 전달 됨 (default name - it)
- 람다식의 결과를 반환
- 객체를 파라미터로 사용하는 하나 이상의 함수를 연속으로 호출해야 할 때 사용.
-
fun main() { val str = readln() val result = str.let { if(it.length > 5) true else false } // str의 요소 전체에 대해 하나씩 어떠한 행동(함수) 등이 필요할 때 println(result) val numbers = listOf("one", "two", "three", "four") val modifiedFirstItem = numbers.first().let { firstItem -> println("The first item of the list is '$firstItem'") if (firstItem.length >= 5 ) firstItem else "!" + firstItem + "!" }.uppercase() println("First item after modifications : '$modifiedFirstItem'") }

run
- 확장 함수로 수신 객체가 암시적으로 제공됨.
- 해당 객체는 this로 암시적으로 제공됨.
- 람다식의 결과가 반환
- 람다식에서 객체 초기화와 계산결과 반환을 동시에 할 때 유용
-
fun main() { val numbers = listOf("one", "two", "three", "four") val result = numbers.first().run { println("The first item of the list is '$this'") if (this.length >= 5 ) this else "!" + this + "!" }.uppercase() // run은 속성을 많이 쓸 때 편하다. println("First item after modifications : '$result'") }
let은 파라미터를 통째로 넘길 때 편함, run은 멤버 프로퍼티나 함수를 불러서 사용할 때 편함
with
- 확장 함수(Extension function)가 아님.
- 객체를 with 함수의 파라미터로 명시적으로 제공해야 한다.
- 해당 객체는 람다식에 this로 암시적으로 제공됨.
- 람다식의 결과가 반환됨

apply
- 확장 함수로 수신 객체가 암시적으로 제공됨.
- 해당 객체는 this로 암시적으로 제공됨.
- 객체 자체가 반환됨.
- 객체의 값 설정 외에 다른 반환값이 필요 없을 때 사용.
data class Student1(
var id:Int = 0,
) {
var name:String = ""
var email:String = ""
}
fun main() {
val student = Student1(1)
student.email = "@@@email.com"
student.name = "abc"
// 객체를 할당받고 세팅한 것
val student2 = Student1(2).apply {
name="abc"
email="this@@"
} // id만 있는 객체를 받아서 name, email 까지 받아서 return
}
also
- 확장 함수로 수신 객체가 암시적으로 제공됨.
- 해당 객체는 파라미터로 명시적으로 전달 됨 (default name - it).
- 람다식은 수신 객체를 반환함.
- 특정 객체의 속성(properties) 또는 함수 보다는 객체 자체의 참조가 필요할 때 사용.
fun main() {
val list = mutableListOf<Int>()
list
.also {println(it.size)}
.add(1)
println(list)
// 내가 어떤 동작(list.add(1))을 하기전에 수행을 할 수 있다.
}
Scope Func | Object reference | return value | is extension function |
---|---|---|---|
let | it | 람다식의 결과(새 값) | 객체를 다른 함수의 파라미터로 넘길 때 |
run | this | 람다식의 결과(새 값) | 객체의 속성에 접근할 때 |
also | it | 수신 객체 다시 반환 | 객체를 다른 함수의 파라미터로 넘길 때 |
apply | this | 수신객체 다시 반환 | 객체의 속성에 접근할 때 |
takeIf, takeUnless
- takeIf: 특정 조건을 만족하는 객체를 반환함. 만족하지 않을 경우 null을 반환.
- takeUnless: 특정 조건을 만족하지 않는 객체를 반환. 아니면 null을 반환.
- Call Chain이 있을 경우 null check가 필요함
Destructuring declarations
- 객체를 각각의 변수로 분해 할당 하는 것
Function
- fun name(parameters): return Type { body }
- 각 파라미터는 default 값을 가질 수 있으며
- 함수를 호출할 때 파라미터 이름을 명시하면 선언 순서와 상관없이 전달할 수 있다.
fun message(name:String, message:String="Hello", age:Int):String {
return "Age:$age, $message, $name"
}
fun message2(name:String, age:Int, message:String="Hello"):String {
return "Age:$name, $age, $message"
}
fun main() {
println(message(age=22, name="user"))
println(message2("B", 20))
}
// 디폴트 매개변수를 사용할 때 주의할 점
// 함수 중간 디폴트 매개변수가 들어갔는데 message("A", 20)를 사용하면
// 컴파일러가 어느 매개변수를 뜻하는지 모르기때문에 꼭 명시해주어야 한다.
// -> message(name="A", age=20)
→ default 매개변수는 왠만하면 끝에 모아두는걸 추천
- overriding 된 함수는 base 함수의 default 값을 동일하게 사용한다.
- default 값이 있는 파라미터와 없는 파라미터를 동시에 사용하는 경우 기본값 보다 뒤쪽에 있는 파라미터는 이름을 지정해주어야 한다.

- 람다식을 파라미터로 받을 수 있으며 람다식이 마지막 파라미터인 경우 괄호 밖에 적을 수 있다.
fun foo(name:String, ex:()->Unit) {
println(name)
ex()
}
fun bar(param:Int=1, ex:()->Unit){
println(param)
ex()
}
fun main(){
foo("abc") { println("Hello") }
bar(1) { println("World") }
bar { println("Kotlin") }
}
- varargs 키워드를 이용해 가변 개수의 파라미터를 받을 수 있다.
fun foo(vararg items:Int) {
for(i in items)
print("$i ")
}
fun foo2(vararg items:Int) {
for(i in items)
print("$i ")
}
fun main() {
foo()
foo(1)
foo(1, 2, 3)
// 원래는 foo2(list[0], list[1], list[2], list[3]) 이런식으로 호출을 해주어야 하는데
// 그걸 줄여주는 역할 intArrayOf
val arr = intArrayOf(1, 2, 3 , 4)
foo2(*arr)
}
- infix 함수 만들기
- Member 함수 또는 Extension은 Infix 형태로 정의 가능
- 파라미터는 하나만 받아야 하고 기본값이 없어야 함
- 상대방이 반드시 있어야 한다.
- 중위연산자 정의
- 우리가 프로그램에서 사용할 때도 보면 1 + 2 의 ‘+’도 어찌보면 String 이다.
- “이걸 우리가 정의 해보자”와 같은 느낌 1.plus(2)
- 중위연산자 정의
infix fun Int.diff(other:Int) = if(this > other) this-other else other-this fun main(){ var diff = 3 diff 2 // 3.diff(2) 과 같음 println(diff) diff = 10 diff 33 println(diff) }
- Local functions : 다른 함수 내부에 선언된 함수
- local 함수는 외부 함수의 지역 변수에 접근 가능- 자바에서는 안되는 기능, 이 이유 때문에 코틀린이 함수형 프로그래밍 언어 라고도 불림
fun foo(){ var count = 0 fun add(){ println(count) count++ if(count < 3 ) add() } add() } fun main(){ //add() // Error foo() }
- Tail recursive functions
- Tail call : 함수의 마지막 코드가 함수 호출인 것 - 최적화 대상
- Tail recursion : 함수의 마지막 코드로 재귀 호출을 하는 것
- 함수의 마지막 줄이 다른 함수 호출이라는 것은 이전 함수에서 더 이상 실행 할 코드가 없다는 뜻 → 콜 스택에 모든 정보를 남길 필요가 없다 → 성능을 높일 수 있다.
- 재귀 호출 함수를 tail recursion 으로 작성했다면 tailrec 키워드를 이용해 최적화를 할 수 있다.
val eps = 1E-10
tailrec fun findFixPoint(x: Double = 1.0) : Double = if (Math.abs(x - Math.cos(x)) < eps)
x else findFixPoint(Math.cos(x))

고차원 함수와 람다
- 코틀린의 함수들은 First - class → 함수를 다른 변수와 동일하게 다룰 수 있다.
- 함수를 파라미터로 받을 수 있다.
- 함수의 실행 결과로 함수를 반환할 수 있다.
- 함수를 변수나 자료구조에 저장할 수 있다.
- 고차원 함수
- 함수를 파라미터로 받을 수 있다.
- 함수의 실행결과로 함수를 반환할 수 있다.
- 함수의 타입 표기법
- ( parameter type , parameter type.. ) -> return type
- ( ) -> Unit
- (Int) -> Int 등으로 파라미터 정의 및 함수의 return type 정의 가능
- Top level 함수와 확장 함수는 :: 로 참조할 수 있다.
함수 return
fun getBody(type:Int):()->Unit {
return if(type%2==0){
fun(){
println("Hello")
}
} else {
fun(){
println("World")
}
}
}
fun main(){
val f1 = getBody(1)
f1()
val f2 = getBody(2)
f2()
}
함수를 변수에 할당하기, 함수를 파라미터로 받기
fun foo(i:Int, f:(Int)->Int):Int {
return f(i)
}
fun bar(i:Int):Int = -i
fun main(){
val f1 = ::bar // 타입 추론
val f2:(Int)->Int = ::bar // 타입 지정
f1(1)
f2(-1)
foo(1, fun(v:Int):Int{ return v*10 }) //익명 함수 전달
foo(1) { it * 100 } //람다식
foo(1, ::bar)
}
- 람다식
함수로 선언되지는 않지만 함수 파라미터로 전달 가능
람다식이 함수의 마지막 파라미터인 경우 파라미터 바깥에 선언할 수 있다.
람다식이 사용하는 파라미터가 하나밖에 없을 경우 it을 사용할 수 있다.
- 람다식 단독으로는 return을 사용할 수 없다.
- return은 함수 또는 익명 함수 안에서만 사용할 수 있다.
- 함수 안의 람다식을 의도대로 return 하기 위해서는 Qualified return을 사용할 수 있다.
- https://kotlinlang.org/docs/returns.html#return-to-labels
- 수신자가 있는 함수의 타입 표기
- ReceiverType.(parameter types) → return 의 형태
-
val foo: String.(Int)->String = { times -> this.repeat(times) } fun main(){ val result = "Hello".foo(3) println(result) }
- 해당 수신자는 함수 내에서 this로 접근 할 수 있다.
Inline functions
- 함수 파라미터로 넘어가는 람다식은 익명 객체를 만들게 되는 부하가 있다.

- inline 함수로 지정할 경우 객체 생성 + 함수 호출 대신 람다식을 포함한 해당 함수의 코드를 삽입한다.

Operator overloading
https://kotlinlang.org/docs/operator-overloading.html
- 기본 연산자를 overloading 해서 사용할 수 있다.
- 단항 연산자 예제

Array & Collections
- Array : 기본 타입
- 하나의 변수에 여러 값을 저장하기 위한 연속된 메모리 공간
- 생성할 때 크기가 정해진다.
- List : Collection
- 하나의 변수에 여러 값을 저장하기 위한 불연속 메모리 공간
- List - immutable list. 생성 후 수정할 수 없다.
- MutableList - mutable list. 수정할 수 있다.
Array
- Array
- 배열을 나타내는 데이터 타입
- get(index) 함수 또는 [index]를 이용해 값에 접근한다.
- 초기화 방법 1 : arrayOf( ) 함수를 이용해 값을 초기화
-
fun main() { val arrayOfInt = arrayOf(1, 2, 3) // Array<Int> val arrayOfAny = arrayOf(1, "2", false) // Array<*> println(arrayOfInt[0]) println(arrayOfAny[2]) }
-
- 초기화 방법 2 : Array의 생성자 사용
-
fun main() { val arrayOfInt = Array(3) { it } println(arrayOfInt[2]) }
- size + 초기화 람다식
- 람다식에는 Array의 index가 파라미터로 전달된다.
-
기본 타입
- Primitive types: xxxArrayOf( )함수를 이용해 값을 초기화
- 기본 타입들은 Array 생성 함수가 있다.
- charArrayOf, intArrayOf, longArrayof
- floatArrayOf, doubleArrayOf
- shortArrayOf, byteArrayOf, booleanArrayOf
-
val x: IntArray = intArrayOf(1, 2, 3) x[0] = x[1] + x[2] println(x[0])
-
- 커스텀 타입을 사용하고 싶을 때는 Array 사용
-
data class Test(val value:Int) val arr2 = Array(10) { Test(it) }
- Array의 속성과 주요 함수
- size:Int
- any:Boolean - 항목이 하나라도 있으면 true
- any(predicate:(T)->Boolean): Boolean - 조건을 만족하는 항목이 있는가
- filter(predicate:(T)->Boolean):List - 조건을 만족하는 항목만 골라서 반환
- find(predicate:(T)->Boolean):T? - 조건을 만족하는 첫번째 항목. 없을 수 있음
- forEach(action:(T)->Unit) - 모든 항목에 공통으로 처리할 행동을 지시
- isEmpty, isNotEmpty, isNullOrEmpty
-
fun main() { val arr = Array(5) {it * 2} println(arr.size) // 반환형 int print(arr.any()) // 항목이 하나라도 있으면 true 반환 val arr2 = arr.filter { it > 5 } // arr의 모든 값에 대해 { } 안에 있는 문을 실행하여보고 true를 반환하는 요소들만 // 새로운 리스트로 반환을 해준다. val result = arr.find { it > 10 } // 최초로 찾은 값만 return , null일 수도 있다. arr.forEach { print("$it") } // 모든 항목에 대해 { } 문 안의 코드를 공통으로 처리함 }
- find : 최초로 만족하는 항목을 찾고 싶을 때
- filter : 조건을 만족하는 항목만 모은 새 리스트가 필요할 때
- forEach : 모든 항목에 대해 하고 싶은 동작이 있을 때
- map : 원본 배열(리스트)를 이용해 새로운 데이터를 가진 배열(리스트) 가 필요할 때
- 이 중에서 원본 배열과 반환형이 다른 것은 : filter, map
- find는 만족하는 항목을 찾으면 루프를 끝까지 돌지 않지만, filter, forEach, map은 무조건 끝까지 루프를 돌린다.
fun main() { val users = arrayOf("Sam", "James", "Petter", "Jack") val usersLength = users.map {it.length} val longNames = users.filter {it.length > 4} users.forEach { println(it) } // 리스트가 끝날 때 까지 반복됨 val nameStartingWithJ = users.find { it.startsWith("J") } // James 만 찾고 루프가 멈춤 }
Collections
- 0개 이상의 다양한 수의 아이템들의 집합.
- List: 순서를 가지며 정수형의 index 로 접근할 수 있는 type.
- Set: 순서를 가지지 않고 중복을 허용하지 않는 type.
- Map(Dictionary): key-value 쌍을 가지는 타입. key는 중복을 허용하지 않으며 각 키는 하나의 값을 가진다. 값은 중복 가능하다.
- read-only interface vs mutable interface
- 항목에 접근 할 수만 있는가? 항목을 추가/삭제/업데이트 할 수 있는가?
- val 로 선언된 collection이라도 mutable 이면 항목의 추가/삭제는 가능하다
- List<T> : 정해진 순서에 따라 항목을 지정하고 index를 이용해 접근한다.
- 중복된 값을 저장할 수 있다.
- List(size) { } 와 같이 생성자로 초기화할 수 있다.
- MutableList<T> : 항목을 추가하거나 삭제할 수 있는 List
- MutableList(Size) { } 와 같이 생성자로 초기화할 수 있다.
- Set<T> : 순서가 정해지지 않고 중복을 허용하지 않는 데이터들의 집합
- null을 허용하는 경우, null도 한 개만 저장 가능
-
fun main() { val list1 = listOf(1, 2, 3) val list2 = listOf(3, 2, 1) val set2 = setOf(3, 2, 1) println(list1 == list2) // 리스트는 갯수가 같고 각 인덱스의 모든 값이 같아야 true println(list1 == set2) // set은 순서가 없기 때문에 순서 상관 없이 같은 데이터면 true }
- MutableSet<T> : 순서가 정해지지 않고 중복을 허용하지 않는 데이터들의 집합
자바의 JDBC를 이용해 DB의 결과값들의 받아 올때 사용하는 ResultSet ResultSet rs = stmt.executeQuery(); 도 결국 iterator

- Map<K, V> : 중복되지 않는 Key와 짝지어진 Value를 저장한다.
- MutableMap<K, V>
Iterators
- Collection의 항목들을 traverse
fun main() {
val set1= setOf(1, 2, 3)
val it = set1.iterator()
while(it.hasNext()) { // iterator() 함수로 iterator 객체를 얻음
println(it.next())
}
for(s in set1) { // for를 사용 traverse
println(s)
}
set1.forEach {// forEach를 사용 traverse
println(it)
}
}
- Mutable 타입은 iterator에서 add, remove, set이 가능

Scope Functions
- 특정 개게를 대상으로 하는 코드 블록
- 람다식 기반으로 일시적인 Scope를 적용함.
- let, run, with, apply, also, takeIf, takeUnless

let
- 확장 함수로 수신 객체가 암시적으로 제공됨.
- 해당 객체는 파라미터로 명시적으로 전달 됨 (default name - it)
- 람다식의 결과를 반환
- 객체를 파라미터로 사용하는 하나 이상의 함수를 연속으로 호출해야 할 때 사용.
-
fun main() { val str = readln() val result = str.let { if(it.length > 5) true else false } // str의 요소 전체에 대해 하나씩 어떠한 행동(함수) 등이 필요할 때 println(result) val numbers = listOf("one", "two", "three", "four") val modifiedFirstItem = numbers.first().let { firstItem -> println("The first item of the list is '$firstItem'") if (firstItem.length >= 5 ) firstItem else "!" + firstItem + "!" }.uppercase() println("First item after modifications : '$modifiedFirstItem'") }

run
- 확장 함수로 수신 객체가 암시적으로 제공됨.
- 해당 객체는 this로 암시적으로 제공됨.
- 람다식의 결과가 반환
- 람다식에서 객체 초기화와 계산결과 반환을 동시에 할 때 유용
-
fun main() { val numbers = listOf("one", "two", "three", "four") val result = numbers.first().run { println("The first item of the list is '$this'") if (this.length >= 5 ) this else "!" + this + "!" }.uppercase() // run은 속성을 많이 쓸 때 편하다. println("First item after modifications : '$result'") }
let은 파라미터를 통째로 넘길 때 편함, run은 멤버 프로퍼티나 함수를 불러서 사용할 때 편함
with
- 확장 함수(Extension function)가 아님.
- 객체를 with 함수의 파라미터로 명시적으로 제공해야 한다.
- 해당 객체는 람다식에 this로 암시적으로 제공됨.
- 람다식의 결과가 반환됨

apply
- 확장 함수로 수신 객체가 암시적으로 제공됨.
- 해당 객체는 this로 암시적으로 제공됨.
- 객체 자체가 반환됨.
- 객체의 값 설정 외에 다른 반환값이 필요 없을 때 사용.
data class Student1(
var id:Int = 0,
) {
var name:String = ""
var email:String = ""
}
fun main() {
val student = Student1(1)
student.email = "@@@email.com"
student.name = "abc"
// 객체를 할당받고 세팅한 것
val student2 = Student1(2).apply {
name="abc"
email="this@@"
} // id만 있는 객체를 받아서 name, email 까지 받아서 return
}
also
- 확장 함수로 수신 객체가 암시적으로 제공됨.
- 해당 객체는 파라미터로 명시적으로 전달 됨 (default name - it).
- 람다식은 수신 객체를 반환함.
- 특정 객체의 속성(properties) 또는 함수 보다는 객체 자체의 참조가 필요할 때 사용.
fun main() {
val list = mutableListOf<Int>()
list
.also {println(it.size)}
.add(1)
println(list)
// 내가 어떤 동작(list.add(1))을 하기전에 수행을 할 수 있다.
}
Scope Func | Object reference | return value | is extension function |
---|---|---|---|
let | it | 람다식의 결과(새 값) | 객체를 다른 함수의 파라미터로 넘길 때 |
run | this | 람다식의 결과(새 값) | 객체의 속성에 접근할 때 |
also | it | 수신 객체 다시 반환 | 객체를 다른 함수의 파라미터로 넘길 때 |
apply | this | 수신객체 다시 반환 | 객체의 속성에 접근할 때 |
takeIf, takeUnless
- takeIf: 특정 조건을 만족하는 객체를 반환함. 만족하지 않을 경우 null을 반환.
- takeUnless: 특정 조건을 만족하지 않는 객체를 반환. 아니면 null을 반환.
- Call Chain이 있을 경우 null check가 필요함
Destructuring declarations
- 객체를 각각의 변수로 분해 할당 하는 것