해당 글은 커니의 코틀린 책을 구매하여 공부하고 작성한 글입니다.

조건 확인 함수

특정 값의 일치 여부 확인

  1. check() : 인자로 받은 표현식이 참인지 확인하며 참이 아닌 경우 IllegalStateException 예외를 발생시킨다.
  2. require() : 인자로 받은 표현식이 참인지 확인하며 참이 아닌 경우 IllegalArgumentException 예외를 발생시킨다.

check(), require() 함수 모두 값을 확인하는 형태뿐만 아니라 조건이 일치하지 않았을 경우 수행할 작업을 함께 지정할 수 있는 형태의 함수를 지원한다.

1
2
3
4
5
6
7
fun showMessage(isPrepared: Boolean, message: String){
// isPrepared가 true가 아니면 IllegalStateException 발생.
check(isPrepared)

// message의 길이가 10 이상이 아니면 IllegalArgumentException 발생.
require(message.length>10)
}

checkNotNull(), requireNotNull() 함수를 사용해 특정 값의 널 여부를 확인하고 널이 아닌 값을 반환받을 수 있다. 이도 위의 함수처럼 단순히 값을 확인만 하는 형태와 함께 실행할 함수를 지정하는 형태를 지원한다.

1
2
3
4
5
6
fun showMessage(message: String){
// message 값이 널이 아닐 때에만 해당 변수에 값이 할당된다.
val msg = requireNotNull(message)

println(message)
}

명시적으로 실행 중단하기

프로그램이 실행될 때, 호출될 가능성이 없는 영역이 있다. 하지만, 예기치 못한 이유로 이 영역이 실행되면 프로그램에 부작용이 발생하게 된다. 따라서 이 같은 영역에 진입하게 되는 경우 임의로 예외를 발생시킬 수 있다. error() 함수를 이용하면 된다.

1
2
3
4
5
6
7
8
9
fun showMessage(isPrepared: Boolean, message: String){

// isPrepared가 fals일 경우
// IllegalArgumentException: Not prepared yet! 예외가 발생한다.
if(!isPrepared){
error("Not prepared yet!")
}
println(message)
}

다른 부분의 작업이 완료되어야 구현이 가능할 때, 보통 주석을 달아서 추가 작업이 필요하다고 표시하는 경우가 대부분이다. 하지만, 간혹 이런 주석을 확인하지 못하고 그냥 두면 버그가 발생하기도 한다. 이 문제를 해결하기 위해 코틀린에서는 TODO() 함수를 제공한다. 이를 통해서 NotImplementedError를 발생시켜 아직 이 부분이 완성되지 않았음을 알려준다.

1
2
3
4
5
6
7
8
9
class Car{
...

// 내부 구현이 아직 완료되지 않음.
// 이 함수 호출 시 NotImplementedError가 발생.
fun stop(){
TODO("Stop is not implemented")
}
}

컬렉션 생성 함수

1. 배열

특정 원소를 담고 있는 배열을 생성하기 위해서 arrayOf() 함수를 사용한다.
빈 배열을 생성하고 싶은 경우 emptyArray() 함수를 사용한다.
널 값을 포함할 수 있는 배열을 생성하고 싶은 경우, arrayOfNulls() 함수를 사용한다.

1
2
3
4
5
6
7
8
9
10
// 문자열을 포함하는 배열을 생성한다. 인자를 통해 타입 추론이 가능하다.
val cities = arrayOf("Seoul", "Tokyo")

// String 타입의 빈 배열을 생성한다.
// 전달되는 인자가 없어 타입 추론이 불가능하므로 타입을 지정해줘야 한다.
val emptyStringArray = emptyArray<String>()

// size가 3이고 널 값을 포함할 수 있는 배열을 생성한다.
// 전달되는 인자가 없어 타입 추론이 불가능하므로 타입을 지정해줘야 한다.
val nullOfArray = arrayOfNulls<String>(3)

자바의 원시 타입을 포함하는 배열은 코틀린의 배열과 다른 타입으로 취급되므로, 위의 함수가 아닌 각 타입에 맞는 함수를 사용해야 한다. 아래에서 소개하는 것은 자바의 원시 타입을 포함하는 배열을 생성하는 함수들이다.

  • booleanArrayOf() : BooleanArray 를 반환하며 자바의 boolean[] 배열과 호환된다.
  • byteArrayOf()
  • charArrayOf()
  • doubleArrayOf()
  • floatArrayOf()
  • intArrayOf()
  • longArrayOf()
  • shortArrayOf()

결국 동일하기 때문에 나머지는 설명을 생략했다.

2. 리스트

  • listOf() : 포함하는 요소를 읽을 수만 있고 수정할 수 없는 읽기 전용 리스트를 생성할 수 있다. 다른 말로 immutable 하다고 한다.
  • listOfNotNull() : 널 값은 무시하고 널이 아닌 값으로만 리스트를 구성할 수 있다. 인자로 전달된 모든 값이 널이라면 빈 리스트를 반환한다.
1
2
3
4
5
// 인자가 null 값이므로 빈 리스트를 반환한다.
val countries = listOfNotNull(null)

// 널 값인 인자는 무시하므로 Seoul, Tokyo만을 요소로 갖는 리스트가 생성된다.
val citiest = listOfNotNull("Seoul", null, "Tokyo", null)

리스트에 포함된 요소를 수정할 수 있는 리스트는 mutableListOf() 함수를 사용하여 생성한다. 함수의 정의는 아래와 같다.

  • fun mutableListOf(vararg elements: T): MutableList
    • 인자로 받은 elements를 요소로 가지며 수정 가능한 리스트를 반환한다.
  • fun mutableListOf(): MutableList
    • 비어있는 수정 가능한 리스트를 반환한다.

또한, 자주 사용되는 ArrayList도 arrayListOf() 함수를 사용해 쉽게 생성할 수 있다.

이외에도 Map, Set(집합) 자료구조도 List와 비슷한 함수를 가지고 있다.
읽기만 가능한 함수와 수정도 가능한 함수까지 이름만 다르고 동일한 형태를 취하기 때문에 설명은 생략하도록 하겠다.

  • Map : Key, value 형태를 갖는다.
  • Set : 중복을 허용하지 않는 집합이며 순서가 없다.

스트림 함수

자바8 에서는 리스트나 맵과 같은 컬렉션에 포함된 자료를 쉽게 다룰 수 있도록 스트림 기능을 제공한다. 코틀린에서는 스트림 대신 유사한 역할을 하는 함수들을 표준 라이브러리에서 제공하며, 확장 함수 형태로 제공된다. 자바8의 스트림 기능을 사용하지 않지만, 편의상 스트림 함수라 칭하도록 하겠다.

변환

  • map() : 함수는 컬렉션 내 인자를 다른 값이나 타입으로 변환할 때 사용한다.
  • mapIndexed() : 함수는 컬렉션 내 포함된 인자의 인덱스 값을 변환 함수 내에서 사용할 수 있다.
  • mapNotNull() : 함수는 컬렉션 내 인자를 변환함과 동시에, 변환한 값이 널 값인 경우 이를 무시한다.
  • flatMap() : 함수는 map() 함수와 달리 반환형이 Iterable이다. 따라서 하나의 인자에서 여러 개의 인자로 매핑이 필요한 경우에 사용한다.
  • groupBy() : 함수는 컬렉션 내 인자들을 지정한 기준에 따라 분류하며, 각 인자들의 리스트를 포함하는 맵 형태로 결과를 반환한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
fun main(args: Array<String>) {
val cities = listOf("Seoul", "Russia", "Tokyo")

// 도시 이름을 대문자로 변환.
cities.map { it ->
it.toUpperCase()
}.forEach {
println(it)
}

// 도시의 이름을 받아서 길이로 변환.
cities.map { it ->
it.length
}.forEach {
println("length = $it")
}


// mapIndexed
cities.mapIndexed { index, s ->
"$index 번째 도시 = $s"
}.forEach {
println(it)
}

// mapNotNull 길이가 5이하인 도시만 반환.
// 아니면 null 반환해서 무시됨.
cities.mapNotNull { it ->
if (it.length <= 5) it else null
}.forEach {
println(it)
}


// flatMap
// flatMap 에서 각 인자를 끝으로 하는 새로운 범위를 반환하였으므로,
// 이 범위에 해당하는 정수들이 새롭게 스트림에 추가된다.
val numbers = 1..6

numbers.flatMap { number ->
1..number
}.forEach {
print("$it")
}

println()

// groupBy
cities.groupBy { city ->
if (city.length <= 5) "A" else "B"
}.forEach { key, cities ->
println("key= $key, cities= $cities")
}

}

내 생각에 자주 사용할 함수들은 map(), flatMap() 이라고 생각한다. 까먹더라도 이 두 함수는 꼭 기억하자!

필터

  • filter() : 컬렉션 내 인자들 중 주어진 조건과 일치하는 인자만 걸러주는 역할
  • take() : 함수의 인자로 받은 개수만큼만을 인자로 갖는 리스트를 반환한다.
  • takeLast() : take() 함수와 반대로 뒤에서부터 이 함수의 인자로 받은 개수만큼만을 인자로 갖는 리스트를 반환한다.
  • takeWhile() : 첫 번째 인자부터 시작하여 주어진 조건을 만족하는 인자까지를 포함하는 리스트를 반환한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package Chap04

/**
* created by victory_woo on 28/05/2019
* */
fun main(args: Array<String>) {
val cities = listOf("Seoul", "Tokyo", "NewYork", "Singapore", "Mountain View","spain")

// 1. filter
cities.filter { city ->
city.length <= 5
}.forEach {
println(it)
}

println()
// 2. take
cities.take(1)
.forEach {
println(it)
}

println()
// 3. takeLast
cities.takeLast(3)
.forEach {
println(it)
}

println()
// 4. takeWhile
// spain도 문자열의 길이가 5이하지만, NewYork이 조건을 만족하지 않으므로
// 이후의 인자들을 모두 무시한다.
cities.takeWhile { city ->
city.length <= 5
}.forEach {
println(it)
}

println()
// takeLastWhile
// 리스트의 뒤에서부터 접근한다. 컬렉션 내 항목의 순서는 유지된다.
cities.takeLastWhile { city ->
city.length < 13
}.forEach {
println(it)
}
}
// 결과
// filter
Seoul
Tokyo
spain

// take
Seoul

// takeLast
Singapore
Mountain View
spain

// takeWhile
Seoul
Tokyo

// takeLastWhile
spain

drop() 함수라는 것이 존재하는데, 이는 take() 함수의 반대 역할을 한다. 조건을 만족하는 항목을 컬렉션에서 제외한 결과를 반환한다. take() 함수와 유사하게 dropLast(), dropWhile(), dropLastWhile() 함수를 지원한다. 사용 예제는 책을 참고하길 바란다.

다른 종류의 함수

  • first() : 컬렉션 내 첫 번째 인자를 반환한다. 뿐만 아니라 조건을 만족하는 첫번째 인자를 반환할 수도 있다. 조건을 만족하는 인자가 없는 경우 NoSuchElementException 예외를 발생시킨다.
  • firstOrNull() : 예외 대신 널 값을 반환하도록 할 수 있다.
  • last() : 함수는 first() 함수와 반대 역할을 한다.
  • lastOfNull() : 함수도 지원한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fun main(args: Array<String>) {
val cities = listOf("Seoul", "Tokyo", "NewYork", "Singapore", "Mountain View", "spain")

// 첫 번째와 마지막 인자를 반환한다.
println("first: ${cities.first()}")
println("last: ${cities.last()}")

// 조건에 맞는 첫 번째, 마지막 인자를 반환한다.
println("first 조건: ${cities.first { city -> city.length > 5 }}")
println("first 조건: ${cities.last { city -> city.length > 5 }}")

// 없을 경우 예외가 아닌 널 값을 반환한다.
// 비어있는 도시가 있으면 찾은 첫 번째 도시를 반환하지만, 없기 때문에 예외 대신 널을 반환한다.
println(cities.firstOrNull { city ->
city.isEmpty()
})
println(cities.lastOrNull { city ->
city.isEmpty()
})
}
  • distinct() : 함수는 컬렉션 내 포함된 항목 중 중복된 항목을 걸러낸 결과를 반환한다. 이때 항목의 중복 여부는 equals()로 판단하며, distinctBy() 함수를 사용하면 비교에 사용할 키 값을 직접 설정할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
fun main(args: Array<String>) {
val cities = listOf("Seoul", "Tokyo", "NewYork", "Singapore", "Mountain View", "Seoul", "Tokyo")

// 도시 목록 중 중복된 항목을 제거한다.
cities.distinct()
.forEach {
println(it)
}

println()
// 중복된 항목을 판단할 때, 도시 이름의 길이를 판단 기준으로 사용한다.
// 즉, 문자열의 길이가 같은 경우 같은 항목으로 판단.
cities.distinctBy { city ->
city.length
}.forEach {
println(it)
}
}
// 결과
// distinct
Seoul
Tokyo
NewYork
Singapore
Mountain View

// distincBy
Seoul
NewYork
Singapore
Mountain View

조합 및 합계

  • zip() : 두 컬렉션 내의 자료들을 조합하여 새로운 자료를 만들 때 사용한다. 두 컬렉션 간 자료의 개수가 달라도 사용할 수 있으며, 이 경우에 반환되는 컬렉션의 자료 수는 조합에 사용하는 컬렉션 중 자료의 수가 더 적은 쪽을 따라간다.

기본값으로는 조합된 결과를 Pair로 만들어주며, 원하는 경우 조합 규칙을 사용자가 정의하여 사용할 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
fun main(args: Array<String>) {
val cityCodes = listOf("SEO", "TOK", "MTV", "NYC")
val cityNames = listOf("Seoul", "Tokyo", "Mountain View")

// 단순히 zip 함수를 호출.
cityCodes.zip(cityNames)
.forEach { pair ->
println("${pair.first} : ${pair.second}")
}

println()
// 조합할 자료의 타입을 zip 함수를 통해 지정하면 해당 형태로 바꿔준다.
cityCodes.zip(cityNames) { code, name -> "$code($name)" }
.forEach {
println(it)
}
}
// 결과
SEO : Seoul
TOK : Tokyo
MTV : Mountain View

SEO(Seoul)
TOK(Tokyo)
MTV(Mountain View)
  • joinToString() : 함수는 컬렉션 내 자료를 문자열 형태로 변환함과 동시에, 이를 조합하여 하나의 문자열로 생성한다. 이는 컬렉션 내 자료를 직렬화할 때 매우 유용하다.

인자 없이 함수를 호출하는 경우 기본 설정을 바탕으로 컬렉션 내 자료를 문자열로 변환하며, 몇 가지 인자를 함께 전달하면 자신이 원하는 형태로 출력 문자열을 구성할 수도 있다.

  • count() : 함수는 컬렉션 내 포함된 자료의 개수를 반환하며, 별도의 조건식을 추가하면 해당 조건을 만족하는 자료의 개수를 반환하도록 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun main(args: Array<String>) {
val cities = listOf("Seoul", "Tokyo", "Mountain View", "NYC", "Singapore")

println("기본 joinToString = ${cities.joinToString()}")
println("인자 포함 joinToString = ${cities.joinToString(separator = " | ")}")

println("기본 count = ${cities.count()}")
println("인자 포함 count = ${cities.count { cities ->
cities.length <= 5
}}")
}
// 결과
기본 joinToString = Seoul, Tokyo, Mountain View, NYC, Singapore
인자 포함 joinToString = Seoul | Tokyo | Mountain View | NYC | Singapore
기본 count = 5
인자 포함 count = 3
  • reduce() : 함수는 컬렉션 내 자료들을 모두 합쳐 하나의 값으로 만들어주는 역할을 한다. joinToString() 함수는 reduce() 함수의 일종이라고 볼 수 있다. 첫 번째 자료부터 조합을 시작하며, reduceRight() 함수는 동일한 작업을 컬렉션 내 마지막 자료부터 시작한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun main(args: Array<String>) {
val cities = listOf("Seoul", "Tokyo", "Mountain View", "NYC", "Singapore")

// acc 에는 지금까지 조합된 결과가, s 에는 새로 조합할 자료가 들어간다.
println("reduce 결과 = ${cities.reduce { acc, s ->
"$acc, $s"
}}")

// 마지막 인자부터 조합한다.
println("reduceRight 결과 = ${cities.reduceRight { s, acc ->
"$s, $acc"
}}")
}
// 결과
reduce 결과 = Seoul, Tokyo, Mountain View, NYC, Singapore
reduceRight 결과 = Singapore, NYC, Mountain View, Tokyo, Seoul
  • fold() : 함수는 reduce() 함수와 거의 동일한 역할을 하나, 초기값을 지정할 수 있다. fold()도 컬렉션 내 마지막 인자부터 작업을 수행하는 foldRight() 함수를 지원한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
*
* acc - 지금까지 조합된 결과가 들어간다.
* s - 새로 조합할 자료가 들어간다.
* */
fun main(args: Array<String>) {
val cities = listOf("Seoul", "Tokyo", "Mountain View", "NYC", "Singapore")

println(cities.fold("초기값 지정") { acc, s ->
"$acc, $s"
})

println(cities.foldRight("마지막부터 간다."){ s, acc ->
"$acc, $s"
})
}
// 결과
초기값 지정, Seoul, Tokyo, Mountain View, NYC, Singapore
마지막부터 간다., Singapore, NYC, Mountain View, Tokyo, Seoul

기타 함수

  • any() : 함수는 컬렉션 내 단 하나의 자료라도 존재한다면 true를, 그렇지 않으면 false를 반환한다. 조건식을 전달할 경우, 해당 조건식을 만족하는 자료의 유무 여부를 반환한다.
  • none() : 함수는 any() 함수와 반대 작업을 수행하며, 컬렉션이 비어있는지 여부를 반환한다. 마찬가지로 조건식을 전달할 경우, 해당 조건식을 만족하는 자료가 하나도 존재하지 않는지 여부를 반환한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fun main(args: Array<String>) {
val cities = listOf("Seoul", "Tokyo", "Mountain View", "NYC", "Singapore")

println(cities.any())
println(cities.any { city ->
city.length <= 1
})

println(cities.none())
println(cities.none { city ->
city.isEmpty()
})
// 빈 문자열을 가진 도시가 존재하지 않는지 확인한다.
// 존재하지 않으므로 true 반환.
}
// 결과
true
false
false
true
  • max(), min() : 함수는 숫자 타입의 자료를 갖는 컬렉션 내에서 각각 최대값 및 최소값을 찾아 반환한다.
  • average() : 함수는 숫자 타입의 자료를 갖는 컬렉션 내 자료들의 평균을 반환한다.
1
2
3
4
5
6
7
8
9
10
11
12
fun main(args: Array<String>) {
val cities = listOf(4, 2, 5, 3, 2, 0, 8)

println("max => ${cities.max()}")
println("min => ${cities.min()}")

println("average => ${cities.average().toInt()}")
}
// 결과
max => 8
min => 0
average => 3

범위 지정 함수

개발을 하다 보면 특정 객체에 있는 함수를 연속해서 사용하거나 다른 함수의 인자로 전달하기 위해 변수를 선언하고 이를 다른 곳에서는 사용하지 않는 경우가 있다. 코틀린에서는 이런 경우 유용하게 사용할 수 있는 함수를 표준 라이브러리를 통해 제공한다.

let() 함수

let() 함수는 이 함수를 호출한 객체를 이어지는 함수 블록의 인자로 전달한다.

  • 정의 => fun <T, R> T.let(block: (T) -> R): R
    • 이 함수를 호출하는 객체를 이어지는 함수형 인자 block의 인자로 전달하며, block 함수의 결과를 반환한다.
  • 불필요한 변수 선언을 방지할 수 있다.
  • 널 값이 아닌 경우를 체크한 후 특정 작업을 수행할 때 사용할 수 있다.
  • Nullable 객체를 다른 Nullable 객체로 변환하는 경우
  • 단일 지역 변수의 범위를 제한하는 경우
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 이를 통해 불필요한 변수 선언을 방지할 수 있다.
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16f, resources.displayMetrics).toInt().let{
// 계산된 값을 인자로 받아서 함수에 바로 대입한다.
setPadding(it,0,it,0)
}

// message가 null이 아닐 때만 블록 안의 문장을 실행한다.
fun do(message: String?){
message?.let{
println(message)
}
}

// nullable personal 객체를 nullable driversLicence 객체로 변경한다.
val driversLicence: Licence? = getNullablePerson?.let{
licenceService.getDriversLicence(it)
}

// 단일 지역 변수의 범위를 제한한다.
val person: Person = getPerson()
getPersonDao().let{ dao ->
// 변수 dao의 범위는 이 블록 안으로 제한된다.
dao.insert(person)
}

apply() 함수

이 함수를 호출하는 객체를 이어지는 함수 블록의 리시버(receiver)로 전달한다.

  • 정의 => fun T.apply(block: T.() -> Unit): T
    • 이 함수를 호출하는 객체를 이어지는 함수형 인자 block의 리시버로 전달하며, 함수를 호출한 객체를 반환한다.
  • 함수를 호출한 객체를 함수형 인자 block의 리시버로 전달하므로, 이 블록 내에서는 해당 객체 내의 프로퍼티나 함수를 직접 호출할 수 있다.
  • 따라서 객체 이름을 명시하지 않아도 되므로 코드를 간략하게 만들 수 있다.
1
2
3
4
5
val perter = Person().apply{
// apply의 블록에서는 오직 프로퍼티만 사용한다.
name = "Perter"
age = 26
}

with() 함수

인자로 받은 객체를 이어지는 함수 블록의 리시버로 전달한다.

  • 정의 => fun <T,R> with(receiver: T, block: T.() -> R): R
    • 인자로 받은 객체 receiver를 이어지는 함수형 인자 block의 리시버로 전달하며, block 결과를 반환한다.
  • 함수에서 사용할 객체를 매개변수를 통해서 받는다.
  • Non-nullable(Null이 될 수 없는) 객체에 이 함수를 사용한다.
  • 그리고 결과가 필요하지 않은 경우에 사용한다.
1
2
3
4
5
6
7
8
9
10
11
val person: Person = getPerson()
with(person){
println(name)
println(age)
}
fun manipulateView(messageView: TextView){
with(messageView){
text = "Hello"
gravity = Gravity.CENTER
}
}

run() 함수

인자가 없는 익명 함수처럼 사용하는 형태와 객체에서 호출하는 형태를 제공한다.

  • 정의 => fun run(block: () -> R): R
    • 함수형 인자 block을 호출하고 그 결과를 반환한다.
  • 정의 => fun<T,R> run(block: T(). -> R): R
    • 이 함수를 호출한 객체를 함수형 인자 block의 리시버로 전달하고 그 결과를 반환한다.

run() 함수를 인자가 없는 익명 함수처럼 사용하는 경우, 복잡한 계산을 위해 여러 임시 변수가 필요할 때 유용하게 사용할 수 있다. run() 함수 내부에서 선언되는 변수들은 블록 외부에 노출되지 않으므로 변수 선언 영역을 확실히 분리할 수 있다.

1
2
3
4
5
6
7
8
9
val padding = run{
// 이 블록 내부에서 선언하는 값들은 외부에 노출되지 않는다.
val defaultPadding = TypedValue.applyDimension(...)
val extraPadding = TypedValue.applyDimension(...)

// 계산된 값을 반환한다.
defaultPadding+extraPadding

}

객체에서 run() 함수를 호출하는 경우 with() 함수와 유사한 목적으로 사용할 수 있다. 단, run() 함수는 안전한 호출을 사용할 수 있으므로 널 값일 수 있는 객체의 속성이나 함수에 연속적으로 접근해야 할 때 유용하다.

1
2
3
4
5
6
fun printAge(person: Person?){
// person을 수신 객체로 변환하여 age 값을 사용.
person?.run{
println(age)
}
}

참고