{"componentChunkName":"component---src-containers-post-index-tsx","path":"/backend/kotlin-in-action/6장-컬렉션과_시퀀스/","result":{"pageContext":{"next":{"id":"73ef80cc-f46a-58a8-bc78-d9a5c897fe4c","html":"<ul>\n<li>람다는 기본적으로 다른 함수에 넘길 수 있는 작은 코드 조각을 의미</li>\n</ul>\n<h2 id=\"-51-람다식과-멤버-참조\" style=\"position:relative;\"><a href=\"#-51-%EB%9E%8C%EB%8B%A4%EC%8B%9D%EA%B3%BC-%EB%A9%A4%EB%B2%84-%EC%B0%B8%EC%A1%B0\" aria-label=\" 51 람다식과 멤버 참조 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 5.1 람다식과 멤버 참조</h2>\n<h3 id=\"-511-람다-소개-코드-블록을-값으로-다루기\" style=\"position:relative;\"><a href=\"#-511-%EB%9E%8C%EB%8B%A4-%EC%86%8C%EA%B0%9C-%EC%BD%94%EB%93%9C-%EB%B8%94%EB%A1%9D%EC%9D%84-%EA%B0%92%EC%9C%BC%EB%A1%9C-%EB%8B%A4%EB%A3%A8%EA%B8%B0\" aria-label=\" 511 람다 소개 코드 블록을 값으로 다루기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.1.1 람다 소개: 코드 블록을 값으로 다루기</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">button.setOnClickListener(object: OnClickListener {\n    override fun onClick(v: View) {\n        println(&quot;I was clicked!&quot;)\n    }\n})</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">button.setOnClickListener {\n    println(&quot;I was clicked!&quot;)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>람다를 메서드가 하나뿐인 익명 객체 대신 사용할 수 있다.</li>\n</ul>\n<h3 id=\"-512-람다와-컬렉션\" style=\"position:relative;\"><a href=\"#-512-%EB%9E%8C%EB%8B%A4%EC%99%80-%EC%BB%AC%EB%A0%89%EC%85%98\" aria-label=\" 512 람다와 컬렉션 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.1.2 람다와 컬렉션</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun findTheOldest(people: List&lt;Person&gt;) {\n    var maxAge = 0\n    var theOldest: Person? = null\n    for (person in people) {\n        if (person.age &gt; maxAge) {\n            maxAge = person.age\n            theOldest = person\n        }\n    }\n    println(theOldest)\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    people.maxByOrNull { it.age }</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>maxByOrNull</code> 함수를 이용하면 편한다.</li>\n<li>람다가 인자를 하나만 받고 그 인자에 구체적인 이름을 붙이고 싶지 않기 때문에 it이라는 암시적 이름을 사용한다.</li>\n<li>멤버 참조 또한 사용할 수 있다.</li>\n</ul>\n<h3 id=\"-513-람다식의-문법\" style=\"position:relative;\"><a href=\"#-513-%EB%9E%8C%EB%8B%A4%EC%8B%9D%EC%9D%98-%EB%AC%B8%EB%B2%95\" aria-label=\" 513 람다식의 문법 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.1.3 람다식의 문법</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val sum = {x: Int, y: Int -&gt; x + y}\n    println(sum)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>코틀린 람다식은 중괄호로 둘러싸여 있다.</li>\n<li>화살표가 인자 목록과 람다 본문을 구분해준다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    { println(42) }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>람다식을 직접 호출해도 된다.</li>\n<li>별로 쓸모가 없어 직접 실행하는 편이 낫다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    run{ println(42) }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>run은 인자로 받은 람다를 실행해 주는 라이브러리 함수</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    people.maxByOrNull({p: Person -&gt; p.age })</code>\n        </deckgo-highlight-code>\n<ul>\n<li>구분자가 너무 많이 쓰여서 가독성이 덜어진다.</li>\n<li>컴파일러가 문맥으로부터 유추할 수 있는 인자 타입을 굳이 적을 필요가 없다.</li>\n<li>인자가 하나뿐인 경우 이름을 붙이지 않아도 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    people.maxByOrNull() {p: Person -&gt; p.age }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>코틀린에는 함수 호출 시 맨 뒤에 있는 인자가 람다식이라면 그 람다를 괄호 밖으로 빼낼 수 있다.\n<ul>\n<li>문법적 관습</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    people.maxByOrNull {p: Person -&gt; p.age }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>람다가 어떤 함수의 유일한 인자이고 괄호 뒤에 람다를 썼다면 호출시 빈 괄호를 없애도 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val people = listOf(Person(&quot;Dmitry&quot;, 4), Person(&quot;Eve&quot;, 4))\n    val names = people.joinToString(\n        separator = &quot; &quot;,\n        transform = { p: Person -&gt; p.name }\n    )\n    println(names)\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    people.joinToString(&quot; &quot;) { p: Person -&gt; p.name  }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>굉장히 간결하게 변한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    people.maxByOrNull { p: Person -&gt; p.age }\n    people.maxByOrNull { p -&gt; p.age } // 파라미터 타입을 컴파일러가 추론</code>\n        </deckgo-highlight-code>\n<ul>\n<li>로컬 변수처럼 컴파일러는 람다 파라미터의 타입도 추론할 수 있다.</li>\n<li>it을 너무 남용하는 것보다는 파라미터를 명시하는 편이 낫다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    val getAge = { p: Person -&gt; p.age }\n    people.maxByOrNull { getAge}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>람다를 변수에 저장할 때는 파라미터의 타입을 추론할 문백이 존재하지 않는다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val sum = { x: Int, y: Int -&gt; \n        println(&quot;Computing $x and $y&quot;)\n        x + y\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>본문이 여러 줄로 이뤄진 경우 본문의 맨 마지막에 있는 식이 람다의 결괏값이 된다.</li>\n<li>명시적인 return이 필요하지 않다.</li>\n</ul>\n<h3 id=\"-514-현재-영역에-있는-변수-접근\" style=\"position:relative;\"><a href=\"#-514-%ED%98%84%EC%9E%AC-%EC%98%81%EC%97%AD%EC%97%90-%EC%9E%88%EB%8A%94-%EB%B3%80%EC%88%98-%EC%A0%91%EA%B7%BC\" aria-label=\" 514 현재 영역에 있는 변수 접근 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.1.4 현재 영역에 있는 변수 접근</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun printMessagesWithPrefix(messages: Collection&lt;String&gt;, prefix: String) {\n    messages.forEach { \n        println(&quot;$prefix $it&quot;)\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>forEach</code> 람다는 자신을 둘러싼 영역에 정의된 prefix 변수와 다른 변수에 접근할 수 있다.\n<ul>\n<li>파일 영역에 이를 때까지 자신을 둘러싼 영역의 변수를 참조할 수 있다.</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun printProblemCounts(responses: Collection&lt;String&gt;) {\n    var clientErrors = 0\n    var serverErrors = 0\n    responses.forEach {\n        if (it.startsWith(&quot;4&quot;)) {\n            clientErrors++\n        } else if (it.startsWith(&quot;5&quot;)) {\n            serverErrors++\n        }\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>코틀린과 자바 람다의 다른 점 중 한가지는 코틀린 람다 안에서는 파이널 변수가 아닌 변수에 접근할 수 있다는 점이다.</li>\n<li>람다 안에서 접근할 수 있는 외부 변수를 <strong>람다가 캡처한 변수</strong>라고 부른다.</li>\n<li>기본적으로 함수 안에 정의된 로컬 변수의 생명주기는 함수가 반환되면 끝난다.</li>\n<li>파이널 변수 캡처 -> 람다 코드를 변수 값과 함께 저장</li>\n<li>파이널이 아닌 변수를 캡처 -> 변수를 특별한 래퍼로 감싸서 나중에 변경하거나 읽을 수 있게 한 다음, 래퍼에 대한 참조를 람다 코드와 함께 저장</li>\n</ul>\n<h3 id=\"-515-멤버-참조\" style=\"position:relative;\"><a href=\"#-515-%EB%A9%A4%EB%B2%84-%EC%B0%B8%EC%A1%B0\" aria-label=\" 515 멤버 참조 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.1.5 멤버 참조</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    val getAge = Person::age</code>\n        </deckgo-highlight-code>\n<ul>\n<li>::을 사용하는 식을 멤버 참조라고 부른다.\n<ul>\n<li>한 메서드를 호출하거나 한 프로퍼티에 접근하는 함수 값을 만들어준다.</li>\n</ul>\n</li>\n<li>참조 대상이 함수인지 프로퍼티인지와는 관계없이 멤버 참조 뒤에는 괄호를 넣으면 안 된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun salute() = println(&quot;Salute&quot;)\n\nfun main() {\n    run { ::salute }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>최상위에 선언된 함수나 프로퍼티를 참조할 수도 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val createPerson = ::Person\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>생성자 참조를 사용하면 클래스 생성 작업을 연기하거나 저장해둘 수 있다.</li>\n<li>확장 함수도 똑같은 방식으로 참조할 수 있다.</li>\n</ul>\n<h3 id=\"-516-값과-엮인-호출-가능-참조\" style=\"position:relative;\"><a href=\"#-516-%EA%B0%92%EA%B3%BC-%EC%97%AE%EC%9D%B8-%ED%98%B8%EC%B6%9C-%EA%B0%80%EB%8A%A5-%EC%B0%B8%EC%A1%B0\" aria-label=\" 516 값과 엮인 호출 가능 참조 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.1.6 값과 엮인 호출 가능 참조</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val seb = Person(&quot;Sebastian&quot;, 26)\n    val personsAgeFunction = Person::age // 사람이 주어지면 나이를 돌려주는 멤버 참조\n    println(personsAgeFunction(seb)) // 사람을 인자로 받음\n    \n    val sebsAgeFunction = seb::age // 특정 사람의 나이를 돌려주는, 값과 엮인 호출 가능 참조\n    println(sebsAgeFunction) // 파라미터 지정하지 않아도 됨\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>특정 객체 인스턴스에 대한 메서드 호출에 대한 참조를 만들 수 있다.</li>\n</ul>\n<h2 id=\"-52-자바의-함수형-인터페이스-사용-단일-추상-메서드\" style=\"position:relative;\"><a href=\"#-52-%EC%9E%90%EB%B0%94%EC%9D%98-%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%82%AC%EC%9A%A9-%EB%8B%A8%EC%9D%BC-%EC%B6%94%EC%83%81-%EB%A9%94%EC%84%9C%EB%93%9C\" aria-label=\" 52 자바의 함수형 인터페이스 사용 단일 추상 메서드 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 5.2 자바의 함수형 인터페이스 사용: 단일 추상 메서드</h2>\n<p>함수형 인터페이스 or 단일 추상 메서드 인터페이스</p>\n<ul>\n<li>인터페이스 안에 추상 메서드가 단 하나</li>\n</ul>\n<h3 id=\"-521-람다를-자바-메서드의-파라미터로-전달\" style=\"position:relative;\"><a href=\"#-521-%EB%9E%8C%EB%8B%A4%EB%A5%BC-%EC%9E%90%EB%B0%94-%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EB%A1%9C-%EC%A0%84%EB%8B%AC\" aria-label=\" 521 람다를 자바 메서드의 파라미터로 전달 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.2.1 람다를 자바 메서드의 파라미터로 전달</h3>\n<deckgo-highlight-code language=\"java\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    void postponeComputation(int delay, Runnable computation) {}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    postponeComputation(1000) { println(42) }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>컴파일러는 자동으로 Runnable의 인스턴스로 변환해준다.\n<ul>\n<li>익명 클래스의 인스턴스를 만들어줌</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">postponeComputation(1000, object : Runnable) {\n        override fun run() {\n            println(42)\n        }\n    }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>명시적으로 선언하면 호출할 때마다 새 인스턴스가 생기지만 람다를 사용하면 람다에 해당하는 익명 객체가 재사용된다.</li>\n<li>람다를 inline 표시가 돼 있는 코틀린 함수에 전달하면 익명 클래스가 생성되지 않는다.</li>\n</ul>\n<h3 id=\"-522-sam-변환-람다를-함수형-인터페이스로-명시적-변환\" style=\"position:relative;\"><a href=\"#-522-sam-%EB%B3%80%ED%99%98-%EB%9E%8C%EB%8B%A4%EB%A5%BC-%ED%95%A8%EC%88%98%ED%98%95-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EB%A1%9C-%EB%AA%85%EC%8B%9C%EC%A0%81-%EB%B3%80%ED%99%98\" aria-label=\" 522 sam 변환 람다를 함수형 인터페이스로 명시적 변환 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.2.2 SAM 변환: 람다를 함수형 인터페이스로 명시적 변환</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun createAllDoneRunnable(): Runnable {\n    return Runnable { println(&quot;All done!&quot;) }\n}\n\nfun main() {\n    createAllDoneRunnable().run()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>SAM 생성자는 컴파일러가 생성한 함수로 람다를 단일 추상 메서드 인터페이스의 인스턴스로 명시적으로 변환</li>\n<li>SAM 생성자의 이름은 사용하려는 함수형 인터페이스의 이름과 같다.</li>\n<li>SAM 생성자는 하나의 인자만을 받아 함수형 인터페이스를 구현하는 클래스의 인스턴스를 반환</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val listener = OnClickListener {view -&gt; // 람다를 사용해 SAM 생성자 호출\n    val text = when (view.id) {\n        button1.id -&gt; &quot;First button&quot;\n        button2.id -&gt; &quot;Second button&quot;\n        else -&gt; &quot;Unknown button&quot;\n    }\n    toast(text)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>값을 반환할 때 외에 람다로 생성한 함수형 인터페이스 인스턴스를 변수에 저장해야 하는 경우에도 SAM 생성자 사용</li>\n<li>람다에는 익명 객체와 달리 인스턴스 자신을 가리키는 <code>this</code>가 없다.\n<ul>\n<li>람다 안에서 <code>this</code>는 그 람다를 둘러싼 클래스의 인스턴스를 가리킨다.</li>\n</ul>\n</li>\n<li>SAM 변환을 컴파일로가 자동으로 수행할 수 있지만 가끔 오버로드한 메서드 중에서 어떤 타입의 메서드를 선택해 람다를 변환해 넘겨줘야 할지 모호한 때에는 명시적으로 SAM 생성자 적용하면 된다.</li>\n</ul>\n<h2 id=\"-53-코틀린에서-sam-인터페이스-정의-fun-interface\" style=\"position:relative;\"><a href=\"#-53-%EC%BD%94%ED%8B%80%EB%A6%B0%EC%97%90%EC%84%9C-sam-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-%EC%A0%95%EC%9D%98-fun-interface\" aria-label=\" 53 코틀린에서 sam 인터페이스 정의 fun interface permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 5.3 코틀린에서 SAM 인터페이스 정의: fun interface</h2>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun interface IntCondition {\n    fun check(i: Int): Boolean\n    fun checkString(s: String) = check(s.toInt())\n    fun checkChar(c: Char) = check(c.digitToInt())\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>fun interface</code>라고 정의된 타입의 파라미터를 받는 함수가 있을 때 람다 구현이나 람다에 대한 참조를 직접 넘길 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun checkCondition(i: Int, condition: IntCondition): Boolean {\n    return condition.check(i)\n}\n\nfun main() {\n    checkCondition(1) { it % 2 != 0} // 람다 직접 사용\n\n    val isOdd: (Int) -&gt; Boolean = { it % 2 != 0 }\n    checkCondition(1, isOdd) // 시그니처가 일치하는 람다에 대한 참조 사용\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>함수형 타입 시그니처로 표현할 수 없는 연산이나 더 복잡한 계약을 표현하려면 함수형 인터페이스가 좋은 선택</li>\n</ul>\n<h2 id=\"-54-수신-객체-지정-람다-with-apply-also\" style=\"position:relative;\"><a href=\"#-54-%EC%88%98%EC%8B%A0-%EA%B0%9D%EC%B2%B4-%EC%A7%80%EC%A0%95-%EB%9E%8C%EB%8B%A4-with-apply-also\" aria-label=\" 54 수신 객체 지정 람다 with apply also permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 5.4 수신 객체 지정 람다: with, apply, also</h2>\n<ul>\n<li>수신 객체를 명시하지 않고 람다의 본문 안에서 다른 객체의 메서드를 호출할 수 있게 하는 것</li>\n</ul>\n<h3 id=\"-541-with-함수\" style=\"position:relative;\"><a href=\"#-541-with-%ED%95%A8%EC%88%98\" aria-label=\" 541 with 함수 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.4.1 with 함수</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun alphabet(): String {\n    val result = StringBuilder()\n    for (letter in &#39;A&#39;..&#39;Z&#39;) {\n        result.append(letter)\n    }\n    result.append(&quot;\\nNow I know the alphabet!&quot;)\n    return result.toString()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>매번 result라는 이름을 반복 사용</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun alphabet(): String {\n    val stringBuilder = StringBuilder()\n    return with(stringBuilder) { // 메서드를 호출하려는 수신 객체를 지정\n        for (letter in &#39;A&#39;..&#39;Z&#39;) {\n            this.append(letter)\n        }\n        this.append(&quot;\\nNow I know the alphabet!&quot;)\n        this.toString()\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 예시의 파라미터는 두개다.\n<ul>\n<li>stringBuilder와 람다</li>\n</ul>\n</li>\n<li>with 함수는 첫 번째 인자로 받은 객체를 두 번째 인자로 받은 람다의 수신 객체로 만든다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun alphabet(): String {\n    val stringBuilder = StringBuilder()\n    return with(stringBuilder) { // 메서드를 호출하려는 수신 객체를 지정\n        for (letter in &#39;A&#39;..&#39;Z&#39;) {\n            append(letter)\n        }\n        append(&quot;\\nNow I know the alphabet!&quot;)\n        toString()\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>람다 안에서는 명시적인 this 참조를 사용해 그 수신 객체에 접근할 수 있다.\n<ul>\n<li>this를 없애고 메서드나 프로퍼티 이름만 사용해 접근 가능</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun alphabet() = with(StringBuilder()) {\n        for (letter in &#39;A&#39;..&#39;Z&#39;) {\n            append(letter)\n        }\n        append(&quot;\\nNow I know the alphabet!&quot;)\n        toString()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>식을 바로 반환</li>\n</ul>\n<h3 id=\"-542-apply-함수\" style=\"position:relative;\"><a href=\"#-542-apply-%ED%95%A8%EC%88%98\" aria-label=\" 542 apply 함수 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.4.2 apply 함수</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun alphabet() = StringBuilder().apply {\n        for (letter in &#39;A&#39;..&#39;Z&#39;) {\n            append(letter)\n        }\n        append(&quot;\\nNow I know the alphabet!&quot;)\n}.toString()</code>\n        </deckgo-highlight-code>\n<ul>\n<li>apply는 항상 자신에 전달된 객체(수신 객체)를 반환한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun createViewWithCustomAttributes(context: Context) =\n    TextView(context).apply {\n        text = &quot;Sample Text&quot;\n        textSize = 20.0\n        setPadding(10, 0, 0, 0)\n    }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>apply를 객체 초기화에 활용할 수 있다.</li>\n<li>java의 builder와 비슷하다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun alphabet() = buildString {\n        for (letter in &#39;A&#39;..&#39;Z&#39;) {\n            append(letter)\n        }\n        append(&quot;\\nNow I know the alphabet!&quot;)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>buildString</code> 함수는 <code>StringBuilder</code>를 활용해 <code>String</code>을 만드는 경우 사용할 수 있는 우아한 해법</li>\n<li><code>buildList</code>, <code>buildSet</code>, <code>buildMap</code></li>\n</ul>\n<h3 id=\"-543-객체에-추가-작업-수행-also\" style=\"position:relative;\"><a href=\"#-543-%EA%B0%9D%EC%B2%B4%EC%97%90-%EC%B6%94%EA%B0%80-%EC%9E%91%EC%97%85-%EC%88%98%ED%96%89-also\" aria-label=\" 543 객체에 추가 작업 수행 also permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 5.4.3 객체에 추가 작업 수행: also</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val fruits = listOf(&quot;Apple&quot;, &quot;Banana&quot;, &quot;Cherry&quot;)\n    val uppercaseFruits = mutableListOf&lt;String&gt;()\n    val reversedLongFruits = fruits\n        .map { it.uppercase() }\n        .also { uppercaseFruits.addAll(it) }\n        .filter { it.length &gt; 5 }\n        .also { println(it) }\n        .reversed()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>수신 객체에 대해 어떤 동작을 수행한 후 수신 객체 반환</li>\n<li>also의 람다 안에서는 수신 객체를 인자로 참조\n<ul>\n<li>디폴트로 it</li>\n</ul>\n</li>\n<li>원래의 수신 객체를 인자로 받는 동작을 실행할 때 also가 유용하다.</li>\n</ul>","excerpt":"람다는 기본적으로 다른 함수에 넘길 수 있는 작은 코드 조각을 의미 📖 5.1 람다식과 멤버 참조 🔖 5.1.1 람다 소개: 코드 블록을 값으로 다루기 람다를 메서드가 하나뿐인 익명 객체 대신 사용할 수 있다. 🔖 5.1.2 람다와 컬렉션 maxByOrNull 함수를 이용하면 편한다. 람다가 인자를 하나만 받고 그 인자에 구체적인 이름을 붙이고 싶지 않기 때문에 it이라는 암시적 이름을 사용한다. 멤버 참조 또한 사용할 수 있다. 🔖 5.1.…","fields":{"slug":"/backend/kotlin-in-action/5장-람다를_사용한_프로그래밍/"},"frontmatter":{"title":"Kotlin in Action - 5장 람다를 사용한 프로그래밍","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/f7f7ddfa31d1614405dc5af1487b9ec4/9c94d/kotlin-in-action.png"}}},"draft":false,"category":"Back-End","tags":["Kotlin"],"date":"March 30, 2025"}},"previous":{"id":"e6422292-3901-5f36-bb54-df3880644ca6","html":"<h2 id=\"-71-nullpointerexception을-피하고-값이-없는-경우-처리-널-가능성\" style=\"position:relative;\"><a href=\"#-71-nullpointerexception%EC%9D%84-%ED%94%BC%ED%95%98%EA%B3%A0-%EA%B0%92%EC%9D%B4-%EC%97%86%EB%8A%94-%EA%B2%BD%EC%9A%B0-%EC%B2%98%EB%A6%AC-%EB%84%90-%EA%B0%80%EB%8A%A5%EC%84%B1\" aria-label=\" 71 nullpointerexception을 피하고 값이 없는 경우 처리 널 가능성 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.1 NullPointerException을 피하고 값이 없는 경우 처리: 널 가능성</h2>\n<ul>\n<li>코틀린을 포함한 최신 언어에서 null에 대한 접근 방법은 가능한 이 문제를 실행 시점에서 컴파일 시점으로 옮기는 것</li>\n<li>널이 될 수 있는지 여부를 타입 시스템에 추가하으로써 컴파일러가 여러 가지 오류를 컴파일 시 미리 감지해서 실행 시점에 발생할 수 있는 예외의 가능성을 줄일 수 있다.</li>\n</ul>\n<h2 id=\"-72-널이-될-수-있는-타입으로-널이-될-수-있는-변수-명시\" style=\"position:relative;\"><a href=\"#-72-%EB%84%90%EC%9D%B4-%EB%90%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%ED%83%80%EC%9E%85%EC%9C%BC%EB%A1%9C-%EB%84%90%EC%9D%B4-%EB%90%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%EB%B3%80%EC%88%98-%EB%AA%85%EC%8B%9C\" aria-label=\" 72 널이 될 수 있는 타입으로 널이 될 수 있는 변수 명시 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.2 널이 될 수 있는 타입으로 널이 될 수 있는 변수 명시</h2>\n<ul>\n<li>코틀린과 자바의 첫 번째이자 가장 중요한 차이는 코틀린 타입 시스템이 널이 될 수 있는 타입을 명시적으로 지원한다는 점이다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun strLen(s: String) = s.length</code>\n        </deckgo-highlight-code>\n<ul>\n<li>null이 인자로 들어올 수 없다면 위와 같이 정의 가능</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    strLen(null) // error\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>컴파일 시, 오류가 발생한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun strLenSafe(s: String?) = s.length() // error</code>\n        </deckgo-highlight-code>\n<ul>\n<li>타입 이름 뒤에 물음표를 붙이면 그 타입의 변수나 프로퍼티에 null 참조를 저장할 수 있다.</li>\n<li>널이 될 수 있는 타입 값의 메서드를 직접 호출할 수는 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val x: String? = null\n    var y: String = x // error\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>널이 될 수 있는 값을 널이 될 수 없는 타입의 변수에 대입할 수 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val x: String? = null\n    strLen(x) // error\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>널이 될 수 있는 타입의 값을 null이 아닌 타입의 파라미터를 받는 함수에 전달할 수 없다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun strLenSafe(s: String?): Int = if (s != null) s.length else 0</code>\n        </deckgo-highlight-code>\n<ul>\n<li>null과 비교하고 나면 컴파일러는 그 사실을 기억하고 null이 아님이 확실한 영역에서는 해당 값을 null이 아닌 타입의 값처럼 사용할 수 있다.</li>\n</ul>\n<h2 id=\"-73-타입의-의미-자세히-살펴보기\" style=\"position:relative;\"><a href=\"#-73-%ED%83%80%EC%9E%85%EC%9D%98-%EC%9D%98%EB%AF%B8-%EC%9E%90%EC%84%B8%ED%9E%88-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0\" aria-label=\" 73 타입의 의미 자세히 살펴보기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.3 타입의 의미 자세히 살펴보기</h2>\n<ul>\n<li>타입\n<ul>\n<li>가능한 값의 집합과 그런 값들에 대해 수행할 수 있는 연산의 집합</li>\n</ul>\n</li>\n<li>자바의 타입 시스템은 null을 제대로 다루지 못한다.\n<ul>\n<li>ex. String 타입의 변수에는 null, String 모두 들어갈 수 있지만 완전히 다르다. 심지어, instanceof 연산자도 null이 String이 아니라고 답한다.</li>\n</ul>\n</li>\n<li>코틀린의 널이 될 수 있는 타입은 이런 문제에 대해 종합적인 해법을 제공한다.</li>\n</ul>\n<h2 id=\"-74-안전한-호출-연산자로-null-검사와-메서드-호출-합치기-\" style=\"position:relative;\"><a href=\"#-74-%EC%95%88%EC%A0%84%ED%95%9C-%ED%98%B8%EC%B6%9C-%EC%97%B0%EC%82%B0%EC%9E%90%EB%A1%9C-null-%EA%B2%80%EC%82%AC%EC%99%80-%EB%A9%94%EC%84%9C%EB%93%9C-%ED%98%B8%EC%B6%9C-%ED%95%A9%EC%B9%98%EA%B8%B0-\" aria-label=\" 74 안전한 호출 연산자로 null 검사와 메서드 호출 합치기  permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.4 안전한 호출 연산자로 null 검사와 메서드 호출 합치기: ?.</h2>\n<ul>\n<li><code>?.</code>는 null 검사와 메서드 호출을 한 연산으로 수행</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Employee(val name: String, val manager: Employee?)\n\nfun managerName(employee: Employee): String? = employee.manager?.name\n\nfun main() {\n    val ceo = Employee(&quot;Da Boss&quot;, null)\n    val developer = Employee(&quot;Bob Smith&quot;, ceo)\n    println(managerName(developer))\n    println(managerName(ceo))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>Employee로 프로퍼티 접근 시 안전한 호출을 사용하는 방법</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Address(val streetAddress: String, val zipCode: Int, val city: String, val country: String)\n\nclass Company(val name: String, val address: Address?)\n\nclass Person(val name: String, val company: Company?)\n\nfun Person.countryName(): String {\n    val country = this.company?.address?.country\n    return if (country != null) country else &quot;Unknown&quot;\n}\n\nfun main() {\n    val person = Person(&quot;Dmitry&quot;, null)\n    println(person.countryName())\n    // Unknown\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>null 검사를 한줄로 연쇄적으로 할 수 있다!</li>\n</ul>\n<h2 id=\"-75-엘비스-연산자로-null에-대한-기본값-제공-\" style=\"position:relative;\"><a href=\"#-75-%EC%97%98%EB%B9%84%EC%8A%A4-%EC%97%B0%EC%82%B0%EC%9E%90%EB%A1%9C-null%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B8%B0%EB%B3%B8%EA%B0%92-%EC%A0%9C%EA%B3%B5-\" aria-label=\" 75 엘비스 연산자로 null에 대한 기본값 제공  permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.5 엘비스 연산자로 null에 대한 기본값 제공: ?:</h2>\n<ul>\n<li>엘비스 연산자\n<ul>\n<li>null 대신 사용할 기본값을 지정할 때 편리하게 사용할 수 있는 연산자</li>\n<li>null 복합 연산자라고도 부름</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun greet(name: String?) {\n    val recipient: String = name ?: &quot;unnamed&quot;\n    println(&quot;Hello, $recipient&quot;)\n}</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun strLenSafe(s: String?): Int = s?.length ?: 0</code>\n        </deckgo-highlight-code>\n<ul>\n<li>한줄로 줄여쓸 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Address(val streetAddress: String, val zipCode: Int, val city: String, val country: String)\n\nclass Company(val name: String, val address: Address?)\n\nclass Person(val name: String, val company: Company?)\n\nfun printShippingLabel(person: Person) {\n    val address = person.company?.address\n        ?: throw IllegalArgumentException(&quot;No address&quot;)\n    with(address) {\n        println(streetAddress)\n        println(&quot;$zipCode $city, $country&quot;)\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>코드가 매우 간결해진다!</li>\n</ul>\n<h2 id=\"-76-예외를-발생시키지-않고-안전하게-타입을-캐스트하기-as\" style=\"position:relative;\"><a href=\"#-76-%EC%98%88%EC%99%B8%EB%A5%BC-%EB%B0%9C%EC%83%9D%EC%8B%9C%ED%82%A4%EC%A7%80-%EC%95%8A%EA%B3%A0-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%ED%83%80%EC%9E%85%EC%9D%84-%EC%BA%90%EC%8A%A4%ED%8A%B8%ED%95%98%EA%B8%B0-as\" aria-label=\" 76 예외를 발생시키지 않고 안전하게 타입을 캐스트하기 as permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.6 예외를 발생시키지 않고 안전하게 타입을 캐스트하기: as?</h2>\n<ul>\n<li>코틀린에서 대상 값을 as로 지정한 타입으로 바꿀 수 없으면 <code>ClassCastException</code>이 발생</li>\n<li>as를 사용할 때마다 is로 변환 가능한 타입인지 검사할 수 있지만 너무 귀찮다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Person(val firstName: String, val lastName: String) {\n    override fun equals(o: Any?): Boolean {\n        val otherPerson = o as? Person ?: return false\n\n        return otherPerson.firstName == firstName &amp;&amp; otherPerson.lastName == lastName\n    }\n\n    override fun hashCode(): Int = firstName.hashCode() * 37 + lastName.hashCode()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>as? 연산자는 어떤 값을 지정한 타입으로 변환한다. 변활할 수 없으면 null을 반환한다.</li>\n<li>하나의 식으로 해결 가능해진다.</li>\n</ul>\n<h2 id=\"-77-널-아님-단언-\" style=\"position:relative;\"><a href=\"#-77-%EB%84%90-%EC%95%84%EB%8B%98-%EB%8B%A8%EC%96%B8-\" aria-label=\" 77 널 아님 단언  permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.7 널 아님 단언: !!</h2>\n<ul>\n<li>널 아님 단언은 코틀린에서 널이 될 수 있는 타입의 값을 다룰 때 사용할 수 있는 도구 중에서 가장 단순하면서도 무딘 도구다.</li>\n<li><code>!!</code>을 사용하면 어떤 값이든 널이 아닌 타입으로 바꿀 수 있다.</li>\n<li>null에 대해 <code>!!</code>를 사용하면 NPE 발생</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun ignoreNulls(str: String?) {\n    val strNotNull: String = str!! // 예외는 이 지점을 가리킨다.\n    println(strNotNull.length)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>예외가 가리키는 지점은 단언문이 위치한 곳을 가리킨다.</li>\n<li>결국 <code>!!</code>는 컴파일러에게 null이 아님을 알고 있으며, 예외가 발생해도 감수하겠다는 것을 말하는 것이다.</li>\n<li>굳이 느낌표 두개를 선택한 것은 더 나은 방법을 찾아보라는 코틀린 설계자들의 의도이다.\n<ul>\n<li>기호가 못생기고 무례함</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class SelectableTextList(\n    val contents: List&lt;String&gt;,\n    var selectedIndex: Int? = null\n)\n\nclass CopyRowAction(val list: SelectableTextList) {\n    fun isActionEnabled(): Boolean = list.selectedIndex != null\n    fun executeCopyRow() {\n        val index = list.selectedIndex!!\n        val value = list.contents[index]\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>!!</code>를 사용하여 발생하는 에러 스택 트레이스에는 몇번째 줄인지에 대한 정보가 들어있지 않다.\n<ul>\n<li>여러 <code>!!</code> 단언문을 한 줄에 함께 쓰는 일을 피하는 것이 좋다.</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"-78-let-함수\" style=\"position:relative;\"><a href=\"#-78-let-%ED%95%A8%EC%88%98\" aria-label=\" 78 let 함수 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.8 let 함수</h2>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun sendEmailTo(email: String) {\n    println(&quot;Sending email to $email&quot;)\n}\n\nfun main() {\n    var email: String? = &quot;yole@gmail.com&quot;\n    email.let { sendEmailTo(it) }\n    email = null\n    email?.let { sendEmailTo(it) }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>let을 사용하는 가장 흔한 용례는 널이 될 수 있는 값을 널이 아닌 값만 인자로 받는 함수에 넘기는 경우이다.</li>\n<li>let 함수는 자신의 수신 객체를 인자로 전달받은 람다에 넘긴다.</li>\n<li>아주 긴 식이 있고 그 값이 null이 아닐 때 수행해야 하는 로직이 있을 때 let을 쓰면 훨씬 더 편하다.</li>\n</ul>\n<h2 id=\"-79-직접-초기화하지-않는-널이-아닌-타입-지연-초기화-프로퍼티\" style=\"position:relative;\"><a href=\"#-79-%EC%A7%81%EC%A0%91-%EC%B4%88%EA%B8%B0%ED%99%94%ED%95%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EB%84%90%EC%9D%B4-%EC%95%84%EB%8B%8C-%ED%83%80%EC%9E%85-%EC%A7%80%EC%97%B0-%EC%B4%88%EA%B8%B0%ED%99%94-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0\" aria-label=\" 79 직접 초기화하지 않는 널이 아닌 타입 지연 초기화 프로퍼티 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.9 직접 초기화하지 않는 널이 아닌 타입: 지연 초기화 프로퍼티</h2>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class MyService {\n    fun performAction(): String = &quot;Action Done!&quot;\n}\n\nclass MyTest {\n    private var myService: MyService? = null\n    \n    @BeforeAll fun setUp() {\n        myService = MyService()\n    }\n    \n    @Test fun testAction() {\n        assertEquals(&quot;Action Done!&quot;, myService!!.performAction())\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이 코드는 보기 나쁘다.</li>\n<li>코틀린에서는 클래스 안의 널이 아닌 프로퍼티를 생성자 안에서 초기화하지 않고 특별한 메서드 안에서 초기화할 수는 없다. 일반적으로 생성자에서 모든 프로퍼티를 초기화해야 한다.</li>\n<li>프로퍼티 타입이 널이 될 수 없는 타입이라면 반드시 널이 아닌 값으로 초기화해야 한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class MyTest {\n    private lateinit var myService: MyService\n\n    @BeforeAll fun setUp() {\n        myService = MyService()\n    }\n\n    @Test fun testAction() {\n        assertEquals(&quot;Action Done!&quot;, myService.performAction())\n    }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>lateinit</code> 변경자를 붙이면 프로퍼티를 나중에 초기화할 수 있다.</li>\n<li>지연 초기화 프로퍼티는 항상 var여야한다.</li>\n</ul>\n<h2 id=\"-710-안전한-호출-연산자-없이-타입-확장-널이-될-수-있는-타입에-대한-확장\" style=\"position:relative;\"><a href=\"#-710-%EC%95%88%EC%A0%84%ED%95%9C-%ED%98%B8%EC%B6%9C-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%97%86%EC%9D%B4-%ED%83%80%EC%9E%85-%ED%99%95%EC%9E%A5-%EB%84%90%EC%9D%B4-%EB%90%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%ED%83%80%EC%9E%85%EC%97%90-%EB%8C%80%ED%95%9C-%ED%99%95%EC%9E%A5\" aria-label=\" 710 안전한 호출 연산자 없이 타입 확장 널이 될 수 있는 타입에 대한 확장 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.10 안전한 호출 연산자 없이 타입 확장: 널이 될 수 있는 타입에 대한 확장</h2>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun verifyUserInput(input: String?) {\n    if (input.isNullOrBlank()) {\n        println(&quot;Please fill in the required fields&quot;)\n    }\n}\n\nfun main() {\n    verifyUserInput(&quot; &quot;)\n    verifyUserInput(null) // 예외 발생하지 않음.\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>메서드 호출이 null을 수신 객체로 받고 내부에서 null을 처리하게 할 수 있다.\n<ul>\n<li>확장 함수에서만 가능</li>\n<li>일반 멤버 호출은 객체 인스턴스를 통해 디스패치되므로 그 인스턴스가 null인지 여부를 검사하지 않는다.</li>\n</ul>\n</li>\n<li>널이 될 수 있는 타입의 확장 함수는 자신의 수신 객체가 null일 때 어떻게 해야 하는지 스스로 안다.\n<ul>\n<li>안전한 호출 없이도 호출 가능</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun sendEmailTo(email: String) {\n    println(&quot;Sending email to $email&quot;)\n}\n\nfun main() {\n    val recipient: String? = null\n    recipient.let { sendEmailTo(it) } // 안전한 호출을 사용하지 않아 널이 될 수 있는 타입으로 취금\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>let은 this가 null인지 검사하지 않는다.</li>\n<li>let을 사용할 때 수신 객체가 null이 아닌지 검사하고 싶다면 안전한 호출 연산인 <code>?.</code>를 사용해야 한다.</li>\n</ul>\n<h2 id=\"-711-타입-파라미터의-널-가능성\" style=\"position:relative;\"><a href=\"#-711-%ED%83%80%EC%9E%85-%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EC%9D%98-%EB%84%90-%EA%B0%80%EB%8A%A5%EC%84%B1\" aria-label=\" 711 타입 파라미터의 널 가능성 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.11 타입 파라미터의 널 가능성</h2>\n<ul>\n<li>타입 파라미터 T를 클래스나 함수 안에서 타입 이름으로 사용하면 이름 끝에 물음표가 없더라도 T가 널이 될 수 있는 타입이다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T&gt; printHashCode(t: T) {\n    println(t?.hashCode()) // 안전한 호출 사용\n}\n\nfun main() {\n    printHashCode(null)\n    // null\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>printHashCode</code> 호출에서 타입 파라미터 T에 대해 추론한 타입은 널이 될 수 있는 Any? 타입이다.</li>\n<li>타입 파라미터가 널이 아님을 확실히 하려면 널이 될 수 없는 타입 상계를 지정해야 한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun &lt;T: Any&gt; printHashCode(t: T) {\n    println(t.hashCode()) // 안전한 호출 사용\n}\n\nfun main() {\n    printHashCode(null) // error\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>타입 파라미터는 널이 될 수 있는 타입을 표시하려면 반드시 물음표를 타입 이름 뒤에 붙여야 한다는 규칙의 유일한 예외이다.</li>\n</ul>\n<h2 id=\"-712-널-가능성과-자바\" style=\"position:relative;\"><a href=\"#-712-%EB%84%90-%EA%B0%80%EB%8A%A5%EC%84%B1%EA%B3%BC-%EC%9E%90%EB%B0%94\" aria-label=\" 712 널 가능성과 자바 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 7.12 널 가능성과 자바</h2>\n<h3 id=\"-7121-플랫폼-타입\" style=\"position:relative;\"><a href=\"#-7121-%ED%94%8C%EB%9E%AB%ED%8F%BC-%ED%83%80%EC%9E%85\" aria-label=\" 7121 플랫폼 타입 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.12.1 플랫폼 타입</h3>\n<ul>\n<li>플랫폼 타입은 코틀린이 널 관련 정보를 알 수 없는 타입\n<ul>\n<li>널이 될 수 있는 타입 or 널이 될 수 없는 타입으로 처리해도 된다.</li>\n<li>컴파일러는 모든 연산을 허용</li>\n</ul>\n</li>\n<li>자바 API를 다룰 때는 조심해야 한다.\n<ul>\n<li>대부분의 라이브러리는 널 관련 어노테이션을 쓰지 않는다.</li>\n</ul>\n</li>\n<li>코틀린에서 플랫폼 타입을 선언할 수는 없다.</li>\n<li>자바에서 가져온 널 값을 널이 될 수 없는 코틀린 변수에 대입하면 실행 시점에 대입이 이뤄질 때 예외가 발생</li>\n</ul>\n<h3 id=\"-7122-상속\" style=\"position:relative;\"><a href=\"#-7122-%EC%83%81%EC%86%8D\" aria-label=\" 7122 상속 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 7.12.2 상속</h3>\n<ul>\n<li>코틀린에서 자바 메서드를 오버라이드할 때 그 메서드의 파라미터와 반환 타입을 널이 될 수 있는 타입으로 선언할지 널이 될 수 없는 타입으로 선언할지 결정해야 한다.</li>\n<li>자바 클래스나 인터페이스를 코틀린에서 구현할 경우 널 가능성을 제대로 처리하는 것이 중요\n<ul>\n<li>코틀린 컴파일러는 널이 될 수 없는 타입으로 선언한 모든 파라미터에 대해 널이 아님을 검사하는 단언문을 만들어준다.</li>\n</ul>\n</li>\n</ul>","excerpt":"📖 7.1 NullPointerException을 피하고 값이 없는 경우 처리: 널 가능성 코틀린을 포함한 최신 언어에서 null에 대한 접근 방법은 가능한 이 문제를 실행 시점에서 컴파일 시점으로 옮기는 것 널이 될 수 있는지 여부를 타입 시스템에 추가하으로써 컴파일러가 여러 가지 오류를 컴파일 시 미리 감지해서 실행 시점에 발생할 수 있는 예외의 가능성을 줄일 수 있다. 📖 7.…","fields":{"slug":"/backend/kotlin-in-action/7장-널이_될_수_있는_값/"},"frontmatter":{"title":"Kotlin in Action - 7장 널이 될 수 있는 값","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/f7f7ddfa31d1614405dc5af1487b9ec4/9c94d/kotlin-in-action.png"}}},"draft":false,"category":"Back-End","tags":["Kotlin"],"date":"April 13, 2025"}},"node":{"id":"e580a327-c0c8-5aed-9e7e-6cff312d6912","html":"<h2 id=\"-61-컬렉션에-대한-함수형-api\" style=\"position:relative;\"><a href=\"#-61-%EC%BB%AC%EB%A0%89%EC%85%98%EC%97%90-%EB%8C%80%ED%95%9C-%ED%95%A8%EC%88%98%ED%98%95-api\" aria-label=\" 61 컬렉션에 대한 함수형 api permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 6.1 컬렉션에 대한 함수형 API</h2>\n<h3 id=\"-611-원소-제거와-변환-filter와-map\" style=\"position:relative;\"><a href=\"#-611-%EC%9B%90%EC%86%8C-%EC%A0%9C%EA%B1%B0%EC%99%80-%EB%B3%80%ED%99%98-filter%EC%99%80-map\" aria-label=\" 611 원소 제거와 변환 filter와 map permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.1 원소 제거와 변환: filter와 map</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">data class Person(val name: String, val age: Int)</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val list = listOf(1, 2, 3, 4)\n    println(list.filter { it % 2 == 0 })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>filter 함수는 컬렉션을 순회하면서 주어진 람다가 true를 반환하는 원소들만 모은다.</li>\n<li>filter 함수는 주어진 술어와 일치하는 원소들로 이뤄진 새 컬렉션을 만들 수 있지만 그 과정에서 원소를 변환하지는 않는다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val list = listOf(1, 2, 3, 4)\n    println(list.map { it * it })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>map은 입력 컬렉션의 원소를 변환할 수 있게 해준다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val numbers = listOf(1, 2, 3, 4, 5, 6, 7)\n    val filtered = numbers.filterIndexed { index, element -&gt; index % 2 == 0 &amp;&amp; element &gt; 3 }\n\n    println(filtered)\n\n    val mapped = numbers.mapIndexed { index, element -&gt; index + element }\n    println(mapped)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>index와 원소를 함께 제공</li>\n</ul>\n<h3 id=\"-612-컬렉션-값-누적-reduce와-fold\" style=\"position:relative;\"><a href=\"#-612-%EC%BB%AC%EB%A0%89%EC%85%98-%EA%B0%92-%EB%88%84%EC%A0%81-reduce%EC%99%80-fold\" aria-label=\" 612 컬렉션 값 누적 reduce와 fold permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.2 컬렉션 값 누적: reduce와 fold</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val list = listOf(1, 2, 3, 4, 5, 6, 7)\n    println(list.reduce { acc, element -&gt; acc + element })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>reduce를 사용하면 컬렉션의 첫 번째 값을 누적기에 넣는다.\n<ul>\n<li>빈 컬렉션에 호출하면 안 된다.</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val people = listOf(\n        Person(&quot;Alice&quot;, 29),\n        Person(&quot;Bob&quot;, 31),\n    )\n    val folded = people.fold(&quot;&quot;) { acc, person -&gt; acc + person.name }\n    println(folded)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>fold 함수는 reduce와 비슷하지만 첫 번째 원소를 누적 값으로 시작하는 대신, 임의의 시작 값을 선택할 수 있다.</li>\n<li><code>runningReduce</code>, <code>runningFold</code>를 사용하면 중간 단계의 모든 누적 값을 뽑아낼 수 있다.\n<ul>\n<li>반환객체는 리스트다.</li>\n</ul>\n</li>\n</ul>\n<h3 id=\"-613-컬렉션에-술어-적용-all-any-none-count-find\" style=\"position:relative;\"><a href=\"#-613-%EC%BB%AC%EB%A0%89%EC%85%98%EC%97%90-%EC%88%A0%EC%96%B4-%EC%A0%81%EC%9A%A9-all-any-none-count-find\" aria-label=\" 613 컬렉션에 술어 적용 all any none count find permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.3 컬렉션에 술어 적용: all, any, none, count, find</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val canBeInClub27 = { p: Person -&gt; p.age &lt;= 27 }\n\nfun main() {\n    val people = listOf(\n        Person(&quot;Alice&quot;, 27),\n        Person(&quot;Bob&quot;, 31),\n    )\n    println(people.all(canBeInClub27))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>all은 모든 원소가 술어를 만족시키는지 판단한다.</li>\n<li>any는 술어를 만족하는 원소가 하나라도 있는지 판단한다.</li>\n<li>none은 술어를 만족하는 원소가 없는지를 판단한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val canBeInClub27 = { p: Person -&gt; p.age &lt;= 27 }\n\nfun main() {\n    val people = listOf(\n        Person(&quot;Alice&quot;, 27),\n        Person(&quot;Bob&quot;, 31),\n    )\n    println(people.count(canBeInClub27))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>술어를 만족하는 원소의 개수를 알고 싶다면 count를 사용한다.</li>\n<li>size보다는 count가 효율적이다.\n<ul>\n<li>count는 개수만 추적할 뿐 객체 생성하지 않음</li>\n</ul>\n</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val canBeInClub27 = { p: Person -&gt; p.age &lt;= 27 }\n\nfun main() {\n    val people = listOf(\n        Person(&quot;Alice&quot;, 27),\n        Person(&quot;Bob&quot;, 31),\n    )\n    println(people.find(canBeInClub27))\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>술어를 만족하는 원소를 하나 찾고 싶으면 find 함수 사용</li>\n<li>원소가 전혀 없는 경우 null 반환</li>\n</ul>\n<h3 id=\"-614-리스트를-분할해-리스트의-쌍으로-만들기-partition\" style=\"position:relative;\"><a href=\"#-614-%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EB%B6%84%ED%95%A0%ED%95%B4-%EB%A6%AC%EC%8A%A4%ED%8A%B8%EC%9D%98-%EC%8C%8D%EC%9C%BC%EB%A1%9C-%EB%A7%8C%EB%93%A4%EA%B8%B0-partition\" aria-label=\" 614 리스트를 분할해 리스트의 쌍으로 만들기 partition permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.4 리스트를 분할해 리스트의 쌍으로 만들기: partition</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val people = listOf(\n        Person(&quot;Alice&quot;, 26),\n        Person(&quot;Bob&quot;, 29),\n        Person(&quot;Carol&quot;, 31),\n    )\n    val comeIn = people.filter(canBeInClub27)\n    val stayOut = people.filterNot(canBeInClub27)\n    println(comeIn)\n    println(stayOut)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 로직을 더 간결하게 처리할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">    val (comeIn, stayOut) = people.partition(canBeInClub27)\n    println(comeIn)\n    println(stayOut)</code>\n        </deckgo-highlight-code>\n<ul>\n<li>partition 함수는 컬렉션을 술어를 만족하는 그룹과 만족하지 않는 그룹으로 나눈다.</li>\n</ul>\n<h3 id=\"-615-리스트를-여러-그룹으로-이뤄진-맵으로-바꾸기-groupby\" style=\"position:relative;\"><a href=\"#-615-%EB%A6%AC%EC%8A%A4%ED%8A%B8%EB%A5%BC-%EC%97%AC%EB%9F%AC-%EA%B7%B8%EB%A3%B9%EC%9C%BC%EB%A1%9C-%EC%9D%B4%EB%A4%84%EC%A7%84-%EB%A7%B5%EC%9C%BC%EB%A1%9C-%EB%B0%94%EA%BE%B8%EA%B8%B0-groupby\" aria-label=\" 615 리스트를 여러 그룹으로 이뤄진 맵으로 바꾸기 groupby permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.5 리스트를 여러 그룹으로 이뤄진 맵으로 바꾸기: groupBy</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val people = listOf(\n        Person(&quot;Alice&quot;, 31),\n        Person(&quot;Bob&quot;, 29),\n        Person(&quot;Carol&quot;, 31),\n    )\n    println(people.groupBy { it.age })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>원소를 구분하는 특성이 키이고, 키 값에 따른 그룹을 생성한다.</li>\n</ul>\n<h3 id=\"-616-컬렉션을-맵으로-변환-associate-associatewith-associateby\" style=\"position:relative;\"><a href=\"#-616-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%84-%EB%A7%B5%EC%9C%BC%EB%A1%9C-%EB%B3%80%ED%99%98-associate-associatewith-associateby\" aria-label=\" 616 컬렉션을 맵으로 변환 associate associatewith associateby permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.6 컬렉션을 맵으로 변환: associate, associateWith, associateBy</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val people = listOf(\n        Person(&quot;Joe&quot;, 22),\n        Person(&quot;Mary&quot;, 31),\n    )\n    val nameToAge = people.associate { it.name to it.age }\n    println(nameToAge)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>원소를 그룹화하지 않으면서 컬렉션으로부터 맵을 만들어내고 싶다면 <code>associate</code> 함수를 사용</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val people = listOf(\n        Person(&quot;Joe&quot;, 22),\n        Person(&quot;Mary&quot;, 31),\n        Person(&quot;Jamie&quot;, 22)\n    )\n    val personToAge = people.associateWith { it.age }\n    println(personToAge)\n    val ageToPerson = people.associateBy { it.age }\n    println(ageToPerson)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>associateWith</code>는 컬렉션의 원래 원소를 키로 사용</li>\n<li><code>associateBy</code>는 컬렉션의 원래 원소를 맵의 값으로 하고, 람다가 만들어내는 값을 맵의 키로 사용</li>\n</ul>\n<h3 id=\"-617-가변-컬렉션의-원소-변경-replaceall-fill\" style=\"position:relative;\"><a href=\"#-617-%EA%B0%80%EB%B3%80-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%98-%EC%9B%90%EC%86%8C-%EB%B3%80%EA%B2%BD-replaceall-fill\" aria-label=\" 617 가변 컬렉션의 원소 변경 replaceall fill permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.7 가변 컬렉션의 원소 변경: replaceAll, fill</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val names = mutableListOf(&quot;Martin&quot;, &quot;Samuel&quot;)\n    println(names)\n\n    names.replaceAll { it.uppercase() }\n    println(names)\n\n    names.fill(&quot;(redacted)&quot;)\n    println(names)\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>replaceAll</code>함수를 가변 컬렉션에 적용하면 지정한 람다로 모든 원소를 변경한다.</li>\n<li>가변 리스트의 모든 원소를 똑같은 값으로 바꾸는 경우에는 <code>fill</code>함수를 쓸 수 있다.</li>\n</ul>\n<h3 id=\"-618-컬렉션의-특별한-경우-처리-ifempty\" style=\"position:relative;\"><a href=\"#-618-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%98-%ED%8A%B9%EB%B3%84%ED%95%9C-%EA%B2%BD%EC%9A%B0-%EC%B2%98%EB%A6%AC-ifempty\" aria-label=\" 618 컬렉션의 특별한 경우 처리 ifempty permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.8 컬렉션의 특별한 경우 처리: ifEmpty</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val empty = emptyList&lt;String&gt;()\n    val full = listOf(&quot;apple&quot;, &quot;orange&quot;, &quot;banana&quot;)\n    \n    println(empty.ifEmpty { listOf(&quot;no&quot;, &quot;values&quot;, &quot;here&quot;) })\n    println(full.ifEmpty { listOf(&quot;no&quot;, &quot;values&quot;, &quot;here&quot;) })\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>ifEmpty</code> 함수를 사용화면 아무 원소도 없을 때 기본값을 생성하는 람다를 제공할 수 있다.</li>\n<li><code>ifBlank</code> 함수는 공백만 들어있는 문자열을 다룰 수 있다.</li>\n</ul>\n<h3 id=\"-619-컬렉션-나누기-chunked와-windowed\" style=\"position:relative;\"><a href=\"#-619-%EC%BB%AC%EB%A0%89%EC%85%98-%EB%82%98%EB%88%84%EA%B8%B0-chunked%EC%99%80-windowed\" aria-label=\" 619 컬렉션 나누기 chunked와 windowed permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.9 컬렉션 나누기: chunked와 windowed</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">val temperatures = listOf(27.7, 29.8, 22.0, 35.5, 19.1)</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    println(temperatures.windowed(3))\n    //[[27.7, 29.8, 22.0], [29.8, 22.0, 35.5], [22.0, 35.5, 19.1]]\n    \n    println(temperatures.windowed(3) { it.sum() / it.size })\n    //[26.5, 29.099999999999998, 25.53333333333333]\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>슬라이딩 윈도우를 생성하고자 <code>windowed</code> 함수를 사용할 수 있다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    println(temperatures.chunked(2))\n    // [[27.7, 29.8], [22.0, 35.5], [19.1]]\n    \n    println(temperatures.chunked(2) { it.sum() })\n    // [57.5, 57.5, 19.1]\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>컬렉션을 어떤 주어진 크기의 서로 겹치지 않는(서로소) 부분으로 나누고 싶을 때는 <code>chunked</code> 함수를 사용</li>\n</ul>\n<h3 id=\"-6110-컬렉션-합치기-zip\" style=\"position:relative;\"><a href=\"#-6110-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%95%A9%EC%B9%98%EA%B8%B0-zip\" aria-label=\" 6110 컬렉션 합치기 zip permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.10 컬렉션 합치기: zip</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val names = listOf(&quot;Joe&quot;, &quot;Mary&quot;, &quot;Jamie&quot;)\n    val ages = listOf(22, 31, 22, 44, 0)\n    println(names.zip(ages))\n    // [(Joe, 22), (Mary, 31), (Jamie, 22)]\n    \n    println(names.zip(ages) { name, age -&gt; Person(name, age) })\n    // [Person(name=Joe, age=22), Person(name=Mary, age=31), Person(name=Jamie, age=22)]\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>zip</code> 함수를 사용해 두 컬렉션에서 같은 인덱스에 있는 원소들의 쌍으로 이뤄진 리스트를 만들 수 있다.</li>\n<li>결과 컬렉션의 길이는 더 짧은 쪽의 길이와 같다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val countries = listOf(&quot;DE&quot;, &quot;NL&quot;, &quot;US&quot;)\n    println(names zip ages zip countries)\n    // [((Joe, 22), DE), ((Mary, 31), NL), ((Jamie, 22), US)]\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>중위 표기법을 쓸 수 있다.</li>\n<li>연쇄 호출이 가능하고, 리스트의 리스트가 되지는 않는다.</li>\n</ul>\n<h3 id=\"-6111-내포된-컬렉션의-원소-처리-flatmap과-flatten\" style=\"position:relative;\"><a href=\"#-6111-%EB%82%B4%ED%8F%AC%EB%90%9C-%EC%BB%AC%EB%A0%89%EC%85%98%EC%9D%98-%EC%9B%90%EC%86%8C-%EC%B2%98%EB%A6%AC-flatmap%EA%B3%BC-flatten\" aria-label=\" 6111 내포된 컬렉션의 원소 처리 flatmap과 flatten permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.1.11 내포된 컬렉션의 원소 처리: flatMap과 flatten</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">class Book(val title: String, val authors: List&lt;String&gt;)\n\nval library = listOf(\n    Book(&quot;Kotlin in Action&quot;, listOf(&quot;Isakova&quot;, &quot;Elizarov&quot;, &quot;Aigner&quot;, &quot;Jemerov&quot;)),\n    Book(&quot;Atomic Kotlin&quot;, listOf(&quot;Eckel&quot;, &quot;Isakova&quot;)),\n    Book(&quot;The Three-Body Problem&quot;, listOf(&quot;Liu&quot;))\n)</code>\n        </deckgo-highlight-code>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val authors = library.map { it.authors }\n    println(authors)\n    // [[Isakova, Elizarov, Aigner, Jemerov], [Eckel, Isakova], [Liu]]\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>내포된 컬렉션으로 반환된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val authors = library.flatMap { it.authors }\n    println(authors)\n    // [Isakova, Elizarov, Aigner, Jemerov, Eckel, Isakova, Liu]\n    println(authors.toSet())\n    // [Isakova, Elizarov, Aigner, Jemerov, Eckel, Liu]\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>flatMap</code> 함수는 컬렉션의 각 원소를 파라미터로 주어진 함수를 사용해 변환한다.</li>\n<li>변환한 결과를 하나의 리스트로 합친다.</li>\n<li>변환할 것이 없고 내포된 컬렉션을 평평한 컬렉션으로 만들고 싶다면 <code>flatten</code> 함수를 사용</li>\n</ul>\n<h2 id=\"-62-지연-계산-컬렉션-연산-시퀀스\" style=\"position:relative;\"><a href=\"#-62-%EC%A7%80%EC%97%B0-%EA%B3%84%EC%82%B0-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%97%B0%EC%82%B0-%EC%8B%9C%ED%80%80%EC%8A%A4\" aria-label=\" 62 지연 계산 컬렉션 연산 시퀀스 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>📖 6.2 지연 계산 컬렉션 연산: 시퀀스</h2>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">people.map(Person::name).filter { it.startsWith(&quot;A&quot;) }</code>\n        </deckgo-highlight-code>\n<ul>\n<li>위 함수는 리스트를 결국 2개를 만든다.</li>\n<li>원소가 수백만 개가 되면 효율이 떨어진다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">people\n    .asSequence()\n    .map(Person::name)\n    .filter { it.startsWith(&quot;A&quot;) }\n    .toList()</code>\n        </deckgo-highlight-code>\n<ul>\n<li>중간 결과를 저장하는 컬렉션이 생기지 않기 때문에 원소가 많은 경우 성능이 눈에 띄게 좋아진다.</li>\n<li>시퀀스의 원소는 필요할 때 lazy 계산이 된다.</li>\n</ul>\n<h3 id=\"-621-시퀀스-연산-실행-중간-연산과-최종-연산\" style=\"position:relative;\"><a href=\"#-621-%EC%8B%9C%ED%80%80%EC%8A%A4-%EC%97%B0%EC%82%B0-%EC%8B%A4%ED%96%89-%EC%A4%91%EA%B0%84-%EC%97%B0%EC%82%B0%EA%B3%BC-%EC%B5%9C%EC%A2%85-%EC%97%B0%EC%82%B0\" aria-label=\" 621 시퀀스 연산 실행 중간 연산과 최종 연산 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.2.1 시퀀스 연산 실행: 중간 연산과 최종 연산</h3>\n<ul>\n<li>중간 연산은 다른 시퀀스를 반환하고, 지연 계산된다.</li>\n<li>최종 연산은 결과를 반환한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    listOf(1, 2, 3, 4)\n        .asSequence()\n        .map {\n            print(&quot;map($it) &quot;)\n            it * it\n        }\n        .filter {\n            print(&quot;filter($it) &quot;)\n            it % 2 == 0\n        }\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>이 코드는 아무 내용도 출력되지 않는다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    listOf(1, 2, 3, 4)\n        .asSequence()\n        .map {\n            print(&quot;map($it) &quot;)\n            it * it\n        }\n        .filter {\n            print(&quot;filter($it) &quot;)\n            it % 2 == 0\n        }.toList()\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>최종 연산을 호출하면 연기됐던 모든 계산이 수행된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    println(\n        listOf(1, 2, 3, 4)\n            .asSequence()\n            .map { it * it }\n            .find { it &gt; 3 }\n    )\n    // 4\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>시퀀스에서 연산순서는 <strong>각 원소에 대해 순차적으로 적용</strong>된다.\n<ul>\n<li>원소에 연산을 차례대로 적용하다가 결과가 얻어지면 그 이후의 원소에 대해서는 변환이 이뤄지지 않을 수도 있다는 것</li>\n</ul>\n</li>\n<li>즉시 계산은 전체 컬렉션에 연산을 적용시키지만 지연 계산은 원소를 한번에 하나씩 처리한다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val people = listOf(\n        Person(&quot;Alice&quot;, 29), Person(&quot;Bob&quot;, 31),\n        Person(&quot;Charles&quot;, 31), Person(&quot;Dan&quot;, 21)\n    )\n    println(\n        people\n            .asSequence()\n            .map(Person::name)\n            .filter { it.length &lt; 4 }\n            .toList()\n    )\n    // [Bob, Dan]\n    println(\n        people\n            .asSequence()\n            .filter { it.name.length &lt; 4 }\n            .map(Person::name)\n            .toList())\n    // [Bob, Dan]\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li>연쇄적인 연산에서 더 빨리 원소들을 제거하면 할수록 코드의 성능이 좋아진다.</li>\n</ul>\n<h3 id=\"-622-시퀀스-만들기\" style=\"position:relative;\"><a href=\"#-622-%EC%8B%9C%ED%80%80%EC%8A%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0\" aria-label=\" 622 시퀀스 만들기 permalink\" class=\"post-anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>🔖 6.2.2 시퀀스 만들기</h3>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">fun main() {\n    val naturalNumbers = generateSequence(0) { it + 1 }\n    val numbersTo100 = naturalNumbers.takeWhile { it &lt;= 100 }\n    println(numbersTo100.sum())\n    // 5050\n}</code>\n        </deckgo-highlight-code>\n<ul>\n<li><code>generateSequence</code> 함수는 이전의 원소를 인자로 받아 다음 원소를 계산한다.</li>\n<li>위 변수는 모두 지연 계산된다.</li>\n</ul>\n<deckgo-highlight-code language=\"kotlin\" terminal=\"carbon\" theme=\"one-dark\"  >\n          <code slot=\"code\">import java.io.File\n\nfun File.isInsideHiddenDirectory() =\n    generateSequence(this) { it.parentFile }.any { it.isHidden }\n\nval file = File(&quot;/Users/svtk/.HiddenDir/a.txt&quot;)\nprintln(file.isInsideHiddenDirectory())\n// true\n</code>\n        </deckgo-highlight-code>\n<ul>\n<li>객체의 조상들로 이뤄진 시퀀스를 만드는 것도 시퀀스를 사용하는 방법이다.</li>\n</ul>","excerpt":"📖 6.1 컬렉션에 대한 함수형 API 🔖 6.1.1 원소 제거와 변환: filter와 map filter 함수는 컬렉션을 순회하면서 주어진 람다가 true를 반환하는 원소들만 모은다. filter 함수는 주어진 술어와 일치하는 원소들로 이뤄진 새 컬렉션을 만들 수 있지만 그 과정에서 원소를 변환하지는 않는다. map은 입력 컬렉션의 원소를 변환할 수 있게 해준다. index와 원소를 함께 제공 🔖 6.1.2 컬렉션 값 누적: reduce와 fold reduce…","fields":{"slug":"/backend/kotlin-in-action/6장-컬렉션과_시퀀스/"},"frontmatter":{"title":"Kotlin in Action - 6장 컬렉션과 시퀀스","thumbnail":{"childImageSharp":{"fluid":{"src":"/static/f7f7ddfa31d1614405dc5af1487b9ec4/9c94d/kotlin-in-action.png"}}},"draft":false,"category":"Back-End","tags":["Kotlin"],"date":"April 06, 2025"}}}},"staticQueryHashes":["2374173507","2996537568","3691437124"]}