<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Rooted In Develop</title>
    <link>https://rooted.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 26 Jun 2026 16:17:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>RootedIn</managingEditor>
    <image>
      <title>Rooted In Develop</title>
      <url>https://tistory1.daumcdn.net/tistory/3216631/attach/1954b1285ae14079bb84433eaccecb50</url>
      <link>https://rooted.tistory.com</link>
    </image>
    <item>
      <title>Kotlin - DSL</title>
      <link>https://rooted.tistory.com/58</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;Kotlin 의 편의성 지원&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 188px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;Java&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;Kotlin&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;특성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;StringUtil.capitalize(s)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;s.capitalize()&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;확장 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;1.to(&quot;one&quot;)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;1 to &quot;one&quot;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;중위 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;set.add(2)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;set += 2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;연산자 오버로딩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;map.get(&quot;key&quot;)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;map[&quot;key&quot;]&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;get 메서드에 대한 관례&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;file.use({ f -&amp;gt; f.read() })&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;file.use { it.read() }&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;람다를 괄호 밖으로 빼내는 관례&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 68px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 68px;&quot;&gt;sb.append(&quot;yes&quot;)&lt;br /&gt;sb.append(&quot;no&quot;)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 68px;&quot;&gt;with (sb) {&lt;br /&gt;&amp;nbsp; append(&quot;yes&quot;)&lt;br /&gt;&amp;nbsp; append(&quot;no&quot;)&lt;br /&gt;}&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 68px; text-align: center;&quot;&gt;수신 객체 지정 람다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DSL&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;외부 DSL : SQL&lt;/p&gt;
&lt;pre id=&quot;code_1687593253671&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT Country.name, COUNT(Customer.id)
  FROM Country
  JOIN Customer ON Country.id = Customer.country_id
  GROUP BY Country.name
  ORDER BY COUNT(Customer.id) DESC
  LIMIT 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;내부 DSL : &lt;a href=&quot;https://github.com/JetBrains/Exposed&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Exposed&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1687593303314&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(Country join Customer)
  .slice(Country.name, jCount(Customer.id))
  .selectAll()
  .groupBy(Country.name)
  .orderBy(Count(Customer.id), isAsc = false)
  .limit(1)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수신 객체 지정 람다&lt;/p&gt;
&lt;pre id=&quot;code_1687593949324&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 람다를 인자로 받는 함수
fun buildString(builderAction: (StringBuilder) -&amp;gt; Unit) : String {
  val sb = StringBuilder()
  builderAction(sb)
  return sb.toString()
}
&amp;gt;&amp;gt;&amp;gt; val s = buildString {
  it.append(&quot;Hello, &quot;)
  it.append(&quot;World!&quot;)
}

// 수신 객체 지정 람다를 사용해 재정의
fun buildString(builderAction: StringBuilder.() -&amp;gt; Unit) : String {
  val sb = StringBuilder()
  sb.builderAction()
  return sb.toString()
}
&amp;gt;&amp;gt;&amp;gt; val s = buildString {
  this.append(&quot;Hello, &quot;)
  append(&quot;World!&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1687594064616&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val appendExcl : StringBuilder.() -&amp;gt; Unit = { this.append(&quot;!&quot;) }
&amp;gt;&amp;gt;&amp;gt; val stringBuilder = StringBuilder(&quot;Hi&quot;)
&amp;gt;&amp;gt;&amp;gt; stringBuilder.appendExcl() // appendExcl 를 확장 함수처럼 사용 가능
&amp;gt;&amp;gt;&amp;gt; println(stringBuilder)
Hi!
&amp;gt;&amp;gt;&amp;gt; println(buildString(appendExcl)) // appendExcl 를 인자로 넘길 수 있음
!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;HTML 빌더 구현&lt;/p&gt;
&lt;pre id=&quot;code_1687612976127&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;open class Tag(val name: String) {
  private val children = mutableListOf&amp;lt;Tag&amp;gt;()
  protected fun &amp;lt;T : Tag&amp;gt; doInit(child: T, init: T.() -&amp;gt; Unit) {
    child.init()
    childrene.add(child)
  }
  override fun toString() = &quot;&amp;lt;$name&amp;gt;${children.joinToString(&quot;&quot;)}&amp;lt;/$name&amp;gt;&quot;
}
fun table(init: TABLE.() -&amp;gt; Unit) = TABLE().apply(init)
class TABLE : Tag(&quot;table&quot;) {
  fun tr(init: TR.() -&amp;gt; Unit) = doInit(TR(), init)
}
class TR : Tag(&quot;tr&quot;) {
  fun td(init: TD.() -&amp;gt; Unit) = doInit(TD(), init)
}
class TD : Tag(&quot;td&quot;)
fun createTable() =
  table {
    tr {
      td {
      }
    }
  }
&amp;gt;&amp;gt;&amp;gt; println(createTable())
&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;invoke 관례 활용&lt;/p&gt;
&lt;pre id=&quot;code_1687613111605&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Greeter(val greeting: String) {
  operator fun invoke(name: String) {
    println(&quot;$greeting, $name!&quot;)
  }
}
&amp;gt;&amp;gt;&amp;gt; val bavarianGreeter = Greeter(&quot;Servus&quot;)
&amp;gt;&amp;gt;&amp;gt; bavarianGreeter(&quot;Dmitry&quot;) // bavarianGreeter.invoke(&quot;Dmitry&quot;)
Servus, Dmitry!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/58</guid>
      <comments>https://rooted.tistory.com/58#entry58comment</comments>
      <pubDate>Sat, 24 Jun 2023 22:27:36 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - annotation, reflection</title>
      <link>https://rooted.tistory.com/57</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;애노테이션 사용 지점 대상 지정&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;대상&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;property&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;프로퍼티 전체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;field&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;프로퍼티에 생성되는 필드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;get&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;프로퍼티 게터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;set&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;프로퍼티 세터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;receiver&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;확장 함수, 프로퍼티의 수신 객체 파라미터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;param&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;생성자 파라미터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;setparam&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;세터 파라미터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;delegate&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;위임 프로퍼티의 위임 인스턴스를 담아둔 필드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;file&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;파일 안에 선언된 최상위 함수와 프로퍼티를 담아두는 클래스&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1686990285288&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class HasTempFolder {
  @get:Rule
  val folder = TemporaryFolder()
  
  @Test
  fun testUsingTempFolder() {
    val createdFile = folder.newFile(&quot;myFile.txt&quot;)
    val createdFolder = folder.newFolder(&quot;subfolder&quot;)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;애노테이션 정의&lt;/h4&gt;
&lt;pre id=&quot;code_1686990370655&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;annotation class JsonName(val name: String)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;메타애노테이션 : 애노테이션 클래스에 적용할 수 있는 애노테이션&lt;/h4&gt;
&lt;pre id=&quot;code_1686990616053&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Target(AnnotationTarget.PROPERTY)
annotation classJsonExclude

@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class BindingAnnotation

@BindingAnnotation
annotation class MyBinding&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- AnnotationTarget.PROPERTY : 자바에서 사용 불가&lt;br /&gt;- AnnotationTarget.FIELD : 자바에서 사용 가능&lt;/p&gt;
&lt;pre id=&quot;code_1686991013488&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;annotation class DeserializeInterface(val targetClass: KClass&amp;lt;out Any&amp;gt;)

interface ValueSerializer&amp;lt;T&amp;gt; {
  fun toJsonValue(value: T) : Any?
  fun fromJsonValue(jsonVluae: Any?) : T
}

annotation class CustomSerializer(val serializerClass: KClass&amp;lt;out ValueSerializer&amp;lt;*&amp;gt;&amp;gt;)

data class Person(
  val name: String,
  @CustomSerializer(DateSerializer::class) val birthDate: Date
)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리플렉션 : KClass, KCallable, KFunction, KProperty&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- KFunction, KProperty 는 모두 KCallable 확장&lt;br /&gt;- KCallable은 제네릭 call 메서드 제공&lt;br /&gt;- KCallable.callBy 메서드 호출하면 디폴트 파라미터 값 사용 가능&lt;br /&gt;- KFunction는 invoke 메서드로 함수 호출 가능&lt;br /&gt;- Kproperty0은 최상위 프로퍼티나 변수, KProperty1은 수신 객체가 있는 프로퍼티에 접근&lt;br /&gt;- KMutableProperty0은 KProperty0을 확장, set 메서드로 값 변경 가능&lt;/p&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/57</guid>
      <comments>https://rooted.tistory.com/57#entry57comment</comments>
      <pubDate>Sat, 17 Jun 2023 18:15:43 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - 제네릭스</title>
      <link>https://rooted.tistory.com/56</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;제네릭 함수와 프로퍼티&lt;/h4&gt;
&lt;pre id=&quot;code_1686398233884&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt;.slice(indices: IntRange): List&amp;lt;T&amp;gt;
&amp;gt;&amp;gt;&amp;gt; println(letters.slice&amp;lt;Char&amp;gt;(0..2))
[a, b, c]
&amp;gt;&amp;gt;&amp;gt; println(letters.slice(10..13))
[k, l, m, n]

val authors = listOf(&quot;Dmitry&quot;, &quot;Svetlana&quot;)
val readers = mutableListOf&amp;lt;String&amp;gt;(/* ... */)
fun &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt;.filter(predicate: (t) -&amp;gt; Boolean): List&amp;lt;T&amp;gt;
&amp;gt;&amp;gt;&amp;gt; readers.filter { it !in authors }

val &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt;.penultimate: T get() = this[size-2]
&amp;gt;&amp;gt;&amp;gt; println(listOf(1, 2, 3, 4).penultimate)
3&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;제네릭 클래스&lt;/h4&gt;
&lt;pre id=&quot;code_1686398520314&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface List&amp;lt;T&amp;gt; {
  operator fun get(index: Int) : T
}
class StringList: List&amp;lt;String&amp;gt; {
  override fun get(index: Int) : String = /* ... */
}
class ArrayList&amp;lt;T&amp;gt;: List&amp;lt;T&amp;gt; {
  override fun get(index: Int) : T = /* ... */
}

interface Comparable&amp;lt;T&amp;gt; {
  fun compareTo(other: T) : Int
}
class String : Comparable&amp;lt;String&amp;gt; {
  override fun compareTo(other: String) : Int = /* ... */
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;타입 파라미터 제약&lt;/h4&gt;
&lt;pre id=&quot;code_1686399242548&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun &amp;lt;T : Number&amp;gt; List&amp;lt;T&amp;gt;.sum() : T
fun &amp;lt;T : Number&amp;gt; oneHalf(value: T) : Double {
  return value.toDouble() / 2.0
}
fun &amp;lt;T: Comparable&amp;lt;T&amp;gt;&amp;gt; max(first: T, second: T) : T {
  return if (first &amp;gt; second) first else second
}
fun &amp;lt;T&amp;gt; ensureTrailingPeriod(seq: T)
  where T : charSequence, T : Appendable {
  if (!seq.endsWith('.') {
    seq.append('.')
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;타입 파라미터를 널이 될 수 없는 타입으로 제한&lt;/h4&gt;
&lt;pre id=&quot;code_1686399930614&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Processor&amp;lt;T : Any&amp;gt; {
  fun process(value: T) {
    value.hashCode()
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;제네릭스 동작&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실행 시점 : 타입 검사, 캐스트&lt;/h4&gt;
&lt;pre id=&quot;code_1686401134007&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (value is List&amp;lt;String&amp;gt;) { ... } // ERROR
if (value is List&amp;lt;*&amp;gt;) { ... }

fun printSum(c: Collection&amp;lt;*&amp;gt;) {
  val intList = c as? List&amp;lt;Int&amp;gt; // Int가 아닌 경우 ClassCastExcpetion
    ?: throw IllegalArgumentException(&quot;List is expected&quot;)
  println(intList.sum())
}
fun printSum(c: Collection&amp;lt;Int&amp;gt;) {
  if (c is List&amp;lt;Int&amp;gt;) {
    println(c.sum())
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;실제화한 타입 파라미터를 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 인라인 함수로 만들고 타입 파라미터를 reified로 지정&lt;/p&gt;
&lt;pre id=&quot;code_1686401262208&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;inline fun &amp;lt;reified T&amp;gt; isA(value: Any) = value is T
&amp;gt;&amp;gt;&amp;gt; println(isA&amp;lt;String&amp;gt;(&quot;abc&quot;))
true
&amp;gt;&amp;gt;&amp;gt; println(isA(String&amp;gt;(123))
false

&amp;gt;&amp;gt;&amp;gt; val items = listOf(&quot;one&quot;, 2, &quot;three&quot;)
&amp;gt;&amp;gt;&amp;gt; println(items.filterIsInstance&amp;lt;String&amp;gt;()) // 표준 라이브러리 함수 filterIsInstance
[one, three]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;하위 타입 / 상위 타입&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 타입 A의 값이 필요한 모든 장소에 어떤 타입 B의 값을 넣어도 문제가 없는 경우 타입 B는 타입 A의 하위 타입&lt;br /&gt;- A는 A?의 하위 타입이지만 A?는 A의 하위 타입이 아님&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;공변성 : 하위 타입 관계를 유지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- A가 B의 하위 타입일때 Producer&amp;lt;A&amp;gt;가 Producer&amp;lt;B&amp;gt;의 하위 타입이면 Producer는 공변적(하위 타입 관계가 유지된다)&lt;br /&gt;- 제네릭 클래스가 타입 파라미터에 대해 공변적임으로 표시하려면 타입 파라미터 이름 앞에 out을 붙임&lt;/p&gt;
&lt;pre id=&quot;code_1686401931463&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Producer&amp;lt;out T&amp;gt; {
  fun produce() : T
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1686402020888&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;open class Animal {
  fun feed() { ... }
}
class Herd&amp;lt;T : Animal&amp;gt; {
  val size: Int get() = ...
  operator fun get(i: Int) : T { ... }
}
fun feedAll(animals: Herd&amp;lt;Animal&amp;gt;) {
  for (i in 0 until animals.size) {
    animals[i].feed()
  }
}
class Cat : Animal() {
  fun cleanLitter() { ... }
}
fun takeCareOfCats(cats: Herd&amp;lt;Cat&amp;gt;) {
  for (i in 0 until cats.size) {
    cats[i].cleanLitter()
  }
  // feedAll(cats) // Herd&amp;lt;Cat&amp;gt; &amp;lt;-&amp;gt; Herd&amp;lt;Animal&amp;gt; 간의 에러 발생
}

// 공변적 컬렉션 역할로 변경
class Herd&amp;lt;out T : Animal&amp;gt; {
}
fun takeCareOfCats(cats: Herd&amp;lt;Cat&amp;gt;) {
  for (i in 0 until cats.size) {
    cats[i].cleanLitter()
  }
  feedAll(cats)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 공변적이기 위해서는 out 위치에만 T가 존재해야함&lt;/p&gt;
&lt;pre id=&quot;code_1686402860925&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface List&amp;lt;out T&amp;gt; : Collection&amp;lt;T&amp;gt; {
  operator fun get(index: Int) : T // out 위치
}

interface List&amp;lt;out T&amp;gt; : Collection&amp;lt;T&amp;gt; {
  fun subList(fromIndex: Int, toIndex: Int) : List&amp;lt;T&amp;gt; // out 위치
}

interface MutableList&amp;lt;T&amp;gt; : List&amp;lt;T&amp;gt;, MutableCollection&amp;lt;T&amp;gt; {
  override fun add(element: T) : Boolean // in 위치이므로 MutableList는 T에 대해 공변적일 수 없음
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 읽기 전용 프로퍼티 : out&lt;br /&gt;- 변경 가능 프로퍼티 : out, in&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;반공변성 : 뒤집힌 하위 타입 관계&lt;/h4&gt;
&lt;pre id=&quot;code_1686402956856&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Comparator&amp;lt;in T&amp;gt; {
  fun compare(e1: T, e2: T) : Int { ... } // in 위치
}&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;공변성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;반공변성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&lt;b&gt;무공변성&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;Producer&amp;lt;out T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;Producer&amp;lt;in T&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;MutableLisit&amp;lt;T&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;타입 인자의 하위 타입 관계가 유지됨&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;타입 인자의 하위 타입 관계가 뒤집힘&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;하위 타입 관계가 성립하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;Producer&amp;lt;C&amp;gt;은 Producer&amp;lt;A&amp;gt;의 하위 타입&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;Consumer&amp;lt;A&amp;gt;은 Consumer&amp;lt;C&amp;gt;의 하위 타입&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;T를 out 위치에서만 사용&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;T를 in 위치에서만 사용&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center;&quot;&gt;T를 아무 위치에서나 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;사용 지점 변성 : 타입이 언급되는 지점에서 변성 지정&lt;/h4&gt;
&lt;pre id=&quot;code_1686403425365&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// out-projection 타입 파라미터
fun &amp;lt;T&amp;gt; copyData(source: MutableList&amp;lt;out T&amp;gt;, destination: MutableList&amp;lt;T&amp;gt;) {
  for (item in source) {
    destination.add(item)
  }
}
&amp;gt;&amp;gt;&amp;gt; val list: MutableList&amp;lt;out Number&amp;gt; = ...
&amp;gt;&amp;gt;&amp;gt; list.add(42)
ERROR

// in-projection 타입 파라미터
fun &amp;lt;T&amp;gt; copyData(source: MutableList&amp;lt;T&amp;gt;, destination: MutableList&amp;lt;in T&amp;gt;) {
  for (item in source) {
    destination.add(item)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Kotlin의 MutableList&amp;lt;out T&amp;gt; 는 Java의 MutableList&amp;lt;? extends T&amp;gt; 와 같음&lt;br /&gt;- Kotlin의 MutableList&amp;lt;in T&amp;gt; 는 Java의 MutableList&amp;lt;? super T&amp;gt;와 같음&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스타 프로젝션 : 타입 인자 대신 * 사용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- MutableList&amp;lt;*&amp;gt;는 MutableList&amp;lt;Any?&amp;gt;와 같지 않음&lt;br /&gt;- MutableList&amp;lt;*&amp;gt;는 구체적인 특정 타입의 원소만 담을 수 있다는 의미&lt;br /&gt;- 스타 프로젝션을 위한 검증기 구현&lt;/p&gt;
&lt;pre id=&quot;code_1686403972495&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;object Validators {
  private val validators = mutableMapOf&amp;lt;KClass&amp;lt;*&amp;gt;, FieldValidator&amp;lt;*&amp;gt;&amp;gt;()
  fun &amp;lt;T: Any&amp;gt; registerValidator(kClass: KClass&amp;lt;T&amp;gt;, fieldValidator: FieldValidator&amp;lt;T&amp;gt;) {
    validators[kClass] = fieldValidator
  }
  @Suppress(&quot;UNCHECKED_CAST&quot;)
  operator fun &amp;lt;T: Any&amp;gt; get(kClass: KClass&amp;lt;T&amp;gt;) : FieldValidator&amp;lt;T&amp;gt; =
    validators[kClass] as? FieldValidator&amp;lt;T&amp;gt;
      ?: throw IllegalArgumentException(&quot;No validator for ${kClass.simpleName}&quot;)
}

&amp;gt;&amp;gt;&amp;gt; Validators.registerValidator(String::class, DefaultStringValidator)
&amp;gt;&amp;gt;&amp;gt; Validators.registerValidator(Int::calss, DefaultIntValidator)
&amp;gt;&amp;gt;&amp;gt; println(Validators[String::class].validate(&quot;Kotlin&quot;))
true
&amp;gt;&amp;gt;&amp;gt; println(Validators[Int::class].validate(42))
true&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/56</guid>
      <comments>https://rooted.tistory.com/56#entry56comment</comments>
      <pubDate>Sat, 10 Jun 2023 22:34:40 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - 고차 함수</title>
      <link>https://rooted.tistory.com/55</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;고차 함수 : 다른 함수를 인자로 받거나 함수를 반환하는 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 타입&lt;/p&gt;
&lt;pre id=&quot;code_1685691339199&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val sum: (Int, Int) -&amp;gt; Int = ( x, y -&amp;gt; x + y }
val action: () -&amp;gt; Unit = { println(1) }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문법 : 파라미터 타입 -&amp;gt; 반환 타입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인자로 받은 함수 호출&lt;/p&gt;
&lt;pre id=&quot;code_1685692170608&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun twoAndThree(operation: (Int, Int) -&amp;gt; Int) {
  val result = operation(2, 3)
  println(&quot;result = $result&quot;)
}
&amp;gt;&amp;gt;&amp;gt; twoAndThree { a, b -&amp;gt; a + b }
result = 5
&amp;gt;&amp;gt;&amp;gt; twoAndThree { a, b -&amp;gt; a * b }
result = 6&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서 코틀린 함수 타입 사용&lt;/p&gt;
&lt;pre id=&quot;code_1685692569061&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Kotlin
fun processTheAnswer(f: (Int) -&amp;gt; Int) {
  println(f(42))
}

// Java
&amp;gt;&amp;gt;&amp;gt; processTheAnswer(number -&amp;gt; number + 1);
43&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디폴트 값을 지정한 함수 타입 파라미터나 널이 될 수 있는 함수 타입 파라미터&lt;/p&gt;
&lt;pre id=&quot;code_1685694480613&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt;.joinToString(
  separator: String = &quot;, &quot;,
  prefix: String = &quot;&quot;,
  postfix: String = &quot;&quot;,
  transform: (T) -&amp;gt; String = { it.toString() }
): String {
  val result = StringBuilder(prefix)
  for ((index, element) in this.withIndex()) {
    if (index &amp;gt; 0) result.append(separator)
    result.append(element)
  }
  result.append(postfix)
  return result.toString()
}
&amp;gt;&amp;gt;&amp;gt; val letters = listOf(&quot;Alpha&quot;, &quot;Beta&quot;)
&amp;gt;&amp;gt;&amp;gt; println(letters.joinToString())
Alpha, Beta
&amp;gt;&amp;gt;&amp;gt; println(letters.joinToString { it.toLowerCase() }
alpha, beta
&amp;gt;&amp;gt;&amp;gt; println(letters.joinToString(separator = &quot;! &quot;, postfix = &quot;! &quot;, transform = { it.toUpperCase() }))
ALPHA! BETA!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수에서 함수를 반환&lt;/p&gt;
&lt;pre id=&quot;code_1685787450068&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum class Delivery { STANDARD, EXPEDITED }
class Order(val itemCount: Int)
fun getShippingCostCalculator(delivery: Delivery): (Order) -&amp;gt; Double {
  if (delivery == Delivery.EXPEDITED) {
    return { order -&amp;gt; 6 + 2.1 * order.itemCount }
  }
  return { order -&amp;gt; 1.2 * order.itemCount }
}
&amp;gt;&amp;gt;&amp;gt; val calculator = getShippingCostCalculator(Delivery.EXPEDITED)
&amp;gt;&amp;gt;&amp;gt; println(calculator(Order(3)))
12.3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다를 활용한 중복 제거&lt;/p&gt;
&lt;pre id=&quot;code_1685789286229&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class SiteVisit(val path: String, val duration: Double, val os: OS)
eunm class OS { WINDOWS, LINUX, MAC, IOS, ANDROID }
val log = listOf(
  SiteVisit(&quot;/&quot;, 34.0, OS.WINDOWS),
  SiteVisit(&quot;/&quot;, 22.0, OS.MAC),
  SiteVisit(&quot;/login&quot;, 12.0, OS.WINDOWS),
  SiteVisit(&quot;/signup&quot;, 8.0, OS.IOS),
  SiteVisit(&quot;/&quot;, 16.3, OS.ANDROID)
)

val averageWindowsDuration = log.filter { it.os == OS.WINDOWS }
  .map(SiteVisit::duration)
  .average()
&amp;gt;&amp;gt;&amp;gt; println(averageWindowsDuration)
23.0
// 일반 함수
fun List&amp;lt;SiteVisit&amp;gt;.averageDurationFor(os: OS) = filter { it.os == os }.map(SiteVisit:duration).average()
// 고차 함수
fun List&amp;lt;SiteVisit&amp;gt;.averageDurationFor(predicate: (SiteVisit) -&amp;gt; Boolean) = filter(predicate).map(SiteVisit::duration).average()
&amp;gt;&amp;gt;&amp;gt; println(log.averageDurationFor { it.os in setOf(OS.ANDROID, OS.IOS) })
12.15
&amp;gt;&amp;gt;&amp;gt; println(log.averageDurationFor { it.os == OS.IOS &amp;amp;&amp;amp; it.path == &quot;/signup&quot; })
8.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인라인 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 함수를 호출하는 바이트코드 대신에 함수 본문을 번역한 바이트코드로 컴파일함&lt;/p&gt;
&lt;pre id=&quot;code_1685790081806&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;inline fun &amp;lt;T&amp;gt; synchronized(lock: Lock, action: () -&amp;gt; T) : T {
  lock.lock()
  try {
    return action()
  }
  finally {
    lock.unlock()
  }
}

fun foo(l: Lock) {
  println(&quot;Before Sync&quot;)
  synchronized(l) {
    println(&quot;Action&quot;)
  }
  println(&quot;After Sync&quot;)
}
// 컴파일
fun __foo__(l: Lock) {
  println(&quot;Before Sync&quot;)
  l.lock()
  try {
    println(&quot;Action&quot;)
  } finally {
    l.unlock()
  }
  println(&quot;After Sync&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;filter, map : 인라인 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다를 인자로 받는 함수를 인라이닝할 때 이익이 많다.&lt;/p&gt;
&lt;pre id=&quot;code_1685790658812&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun readFirstLineFromFile(path: String): String {
  BufferedReader(FileReader(path)).use { br -&amp;gt;
    return br.readLine() // non-local return
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다 안의 return&lt;/p&gt;
&lt;pre id=&quot;code_1685790853351&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class Person(val name: String, val age: Int)
val people = listOf(Person(&quot;Alice&quot;, 29), Person(&quot;Bob&quot;, 31))
fun lookForAlice(people: List&amp;lt;Person&amp;gt;) {
  for (person in people) {
    if (person.name == &quot;Alice&quot;) {
      println(&quot;Found&quot;)
      return
    }
  }
  println(&quot;Not Found&quot;)
}

fun lookForAlice(people: List&amp;lt;Person&amp;gt;) {
  people.forEach {
    if (it.name == &quot;Alice&quot;) {
      println(&quot;Found&quot;)
      return // non-local return
    }
  }
  println(&quot;Not Found&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;non-local return문 : 더 바깥에 있는 다른 블록을 반환하게 하는 return문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다로부터 반환: 레이블을 사용한 return&lt;/p&gt;
&lt;pre id=&quot;code_1685791044985&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun lookForAlice(people: List&amp;lt;Person&amp;gt;) {
  people.forEach label@{ // 레이블 추가
    if (it.name == &quot;Alice&quot;) return@label // 앞에서 정의한 레이블 참조
  }
  println(&quot;Alice might be somewhere&quot;) // 항상 출력
}

fun lookForAlice(people: List&amp;lt;Person&amp;gt;) {
  people.forEach {
    if (it.name == &quot;Alice&quot;) return@forEach
  }
  println(&quot;Alice might be somewhere&quot;) // 항상 출력
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무명 함수: 기본적으로 로컬 return&lt;/p&gt;
&lt;pre id=&quot;code_1685791146085&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun lookForAlice(people: List&amp;lt;Person&amp;gt;) {
  people.forEach(fun (person) {
    if (it.name == &quot;Alice&quot;) return
    println(&quot;${person.name} is not Alice&quot;)
  })
}

people.filter(fun (person): Boolean {
  return person.age &amp;lt; 30
})

people.filter(fun (person) = person.age &amp;lt; 30)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 무명 함수 본문의 return은 무명 함수를 반환시키고, 함수 밖의 다른 함수를 반환시키지 못한다.&lt;/p&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/55</guid>
      <comments>https://rooted.tistory.com/55#entry55comment</comments>
      <pubDate>Sat, 3 Jun 2023 20:20:17 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - 연산자 오버로딩</title>
      <link>https://rooted.tistory.com/54</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;산술&lt;span&gt; &lt;/span&gt;연산자&lt;span&gt; &lt;/span&gt;오버로딩&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이항&lt;span&gt; &lt;/span&gt;산술&lt;span&gt; &lt;/span&gt;연산&lt;span&gt; &lt;/span&gt;오버로딩&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;연산자&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;키워드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;a * b&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;times&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;a / b&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;div&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;a % b&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;mod&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;a + b&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;plus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;a - b&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;minus&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1685016649189&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class Point(val x: Int, val y: Int) {
  operator fun plus(other: Point) : Point {
    return Point(x + other.x, y + other.y)
  }
}
&amp;gt;&amp;gt;&amp;gt; val p1 = Point(10, 20)
&amp;gt;&amp;gt;&amp;gt; val p2 = Point(30, 40)
&amp;gt;&amp;gt;&amp;gt; println(p1 + p2)
Point(x=40, y=60)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피연산자 타입이 다른 경우&lt;/p&gt;
&lt;pre id=&quot;code_1685016763398&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;operator fun Point.times(scale: Double) : Point {
  return Point((x * scale).toInt(), (y * scale).toInt())
}
&amp;gt;&amp;gt;&amp;gt; val p = Point(10, 20)
&amp;gt;&amp;gt;&amp;gt; println(p * 1.5)
Point(x=15, y=30)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자동으로 교환 법칙을 지원하지 않음&lt;br /&gt;- 1.5 * p 를 오버로딩하려면 operator fun Double.times(p: Point) : Point 를 정의해야함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 타입이 다른 경우&lt;/p&gt;
&lt;pre id=&quot;code_1685016858441&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;operator fun Char.times(count: Int) : String {
  return toString().repeat(count)
}
&amp;gt;&amp;gt;&amp;gt; println('a' * 3)
aaa&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;복합 대입 연산자 오버로딩&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;연산자&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;키워드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;+=&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;plusAssign&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;-=&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;minusAssign&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;*=&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;timesAssign&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ex) a += b 는 a = a.plus(b) 또는 a.plusAssign(b)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션&lt;br /&gt;- +=, -= : 새로운 컬렉션 반환&lt;br /&gt;- +, - : &lt;span&gt;객체&lt;/span&gt; &lt;span&gt;상태&lt;/span&gt; &lt;span&gt;변화&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;단항 연산자 오버로딩&lt;/span&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;연산자&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;키워드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;+a&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;unaryPlus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;-a&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;unaryMinus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;!a&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;not&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;++a, a++&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;inc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;--a, a--&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;dec&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1685017147824&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;operator fun Point.unaryMinus() : Point {
  return Point(-x, -y)
}
&amp;gt;&amp;gt;&amp;gt; val p = Point(10, 20)
&amp;gt;&amp;gt;&amp;gt; println(-p)
Point(x=-10, y=-20)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비교 연산자 오버로딩&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;동등성 연산자 : equals&lt;/h4&gt;
&lt;pre id=&quot;code_1685017262158&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Point(val x: Int, val y: Int) {
  override fun equals(obj: Any?) : Boolean {
    if (obj === this) return true
    if (obj !is Point) return false
    return obj.x == x &amp;amp;&amp;amp; obj.y == y
  }
}
&amp;gt;&amp;gt;&amp;gt; println(Point(10, 20) == Point(10, 20))
true
&amp;gt;&amp;gt;&amp;gt; println(Point(10, 20) != Point(5, 5))
true
&amp;gt;&amp;gt;&amp;gt; println(null == Point(1, 2))
false&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;순서 연산자 : compareTo&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a &amp;gt;= b : a.compareTo(b)&lt;/p&gt;
&lt;pre id=&quot;code_1685017362959&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person(val firstName: String, val lastName: String) : Comparable&amp;lt;Person&amp;gt; {
  override fun compareTo(other: Person) : Int {
    return compareValuesBy(this, other, Person::lastName, Person::firstName)
  }
}
&amp;gt;&amp;gt;&amp;gt; val p1 = Person(&quot;Alice&quot;, &quot;Smith&quot;)
&amp;gt;&amp;gt;&amp;gt; val p2 = Person(&quot;Bob&quot;, &quot;Johnson&quot;)
&amp;gt;&amp;gt;&amp;gt; println(p1 &amp;lt; p2)
false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컬렉션과 범위에 대해 쓸 수 있는 관례&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인덱스로 원소에 접근 : get, set&lt;/h4&gt;
&lt;pre id=&quot;code_1685017931104&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;operator fun Point.get(index: Int) : Int {
  return when(index) {
    0 -&amp;gt; x
    1 -&amp;gt; y
    else -&amp;gt; throw IndexOutOfBoundsException(&quot;Invalid coordinate $index&quot;)
  }
}
&amp;gt;&amp;gt;&amp;gt; val p = Point(10, 20)
&amp;gt;&amp;gt;&amp;gt; println(p[1])
20&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1685018022710&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class MutablePoint(var x: Int, var y: Int)
operator fun MutablePoint.set(index: Int, value: Int) {
  when(index) {
    0 -&amp;gt; x = value
    1 -&amp;gt; y = value
    else -&amp;gt; throw IndexOutOfBoundsException(&quot;Invalid coordinate $index&quot;)
  }
}
&amp;gt;&amp;gt;&amp;gt; val p = MutablePoint(10, 20)
&amp;gt;&amp;gt;&amp;gt; p[1] = 42
&amp;gt;&amp;gt;&amp;gt; println(p)
MutablePoint(x=10, y=42)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;in 관례&lt;/p&gt;
&lt;pre id=&quot;code_1685018121954&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class Rectangle(val upperLeft: Point, val lowerRight: Point)
operator fun Rectangle.contains(p: Point) : Boolean {
  return p.x in upperLeft.x until lowerRight.x &amp;amp;&amp;amp; p.y in upperLeft.y until lowerRight.y
}
&amp;gt;&amp;gt;&amp;gt; val rect = Rectangle(Point(10, 20), Point(50, 50))
&amp;gt;&amp;gt;&amp;gt; println(Point(20, 30) in rect)
true
&amp;gt;&amp;gt;&amp;gt; println(Point(5, 5) in rect)
false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rangeTo 관례&lt;/p&gt;
&lt;pre id=&quot;code_1685018887542&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; val now = LocalDate.now()
&amp;gt;&amp;gt;&amp;gt; val vacation = now..now.plusDays(10)
&amp;gt;&amp;gt;&amp;gt; println(now.plusWeeks(1) in vacation)
true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for 루프를 위한 iterator 관례&lt;/p&gt;
&lt;pre id=&quot;code_1685020504973&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;operator fun ClosedRange&amp;lt;LocalDate&amp;gt;.iterator() : Iterator&amp;lt;LocalDate&amp;gt; = object : Iterator&amp;lt;LocalDate&amp;gt; {
  val current = start
  override fun hasNext() = current &amp;lt;= endInclusive
  override fun next() = current.apply {
    current = plusDays(1)
  }
}

&amp;gt;&amp;gt;&amp;gt; val newYear = LocalDate.ofYearDay(2017, 1)
&amp;gt;&amp;gt;&amp;gt; val daysOff = newYear.minusDays(1)..newYear
&amp;gt;&amp;gt;&amp;gt; for (dayOff in daysOff) { println(dayOff) }
2016-12-31
2017-01-01&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조 분해 선언과 component 함수&lt;/p&gt;
&lt;pre id=&quot;code_1685023074917&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; val p = Point(10, 20)
&amp;gt;&amp;gt;&amp;gt; val (x, y) = p
&amp;gt;&amp;gt;&amp;gt; println(x)
10
&amp;gt;&amp;gt;&amp;gt; println(y)
20&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;val (a, b) = p&lt;br /&gt;&amp;nbsp;- val a = p.component1()&lt;br /&gt;&amp;nbsp;- val b = p.component2()&lt;br /&gt;&amp;nbsp;- componentN 함수 호출로 변환됨&lt;/p&gt;
&lt;pre id=&quot;code_1685024307023&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class NameComponents(val name: String, val extension: String)
fun splitFilename(fullName: String) : NameComponents {
  val result = fullName.split('.', limit = 2)
  return NameComponents(result[0], result[1])
}
&amp;gt;&amp;gt;&amp;gt; val (name, ext) = splitFilename(&quot;example.txt&quot;)
&amp;gt;&amp;gt;&amp;gt; println(name)
example
&amp;gt;&amp;gt;&amp;gt; println(ext)
txt&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1685024571633&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class NameComponents(val name: String, val extension: String)
fun splitFilename(fullName: String) : NameComponents {
  val (name, extension) = fullName.split('.', limit = 2)
  return NameComponents(name, extension)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1685024675019&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun printEntries(map: Map&amp;lt;String, String&amp;gt;) {
  for ((key, value) in map) {
    println(&quot;$key -&amp;gt; $value&quot;)
  }
}
&amp;gt;&amp;gt;&amp;gt; val map = mapOf(&quot;Oracle&quot; to &quot;Java&quot;, &quot;JetBrains&quot; to &quot;Kotlin&quot;)
&amp;gt;&amp;gt;&amp;gt; printEntries(map)
Oracle -&amp;gt; Java
JetBrains -&amp;gt; Kotlin&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로퍼티 접근자 로직 재활용 : 위임 프로퍼티&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위임 프로퍼티&lt;/p&gt;
&lt;pre id=&quot;code_1685024712449&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Delegate {
  operator fun getValue() {}
  operator fun setValue() {}
}
class Foo {
  var p: Type by Delegate()
}
&amp;gt;&amp;gt;&amp;gt; val foo = Foo()
&amp;gt;&amp;gt;&amp;gt; val oldValue = foo.p
&amp;gt;&amp;gt;&amp;gt; foo.p = newValue&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로퍼티 초기화 지연 : by lazy()&lt;/p&gt;
&lt;pre id=&quot;code_1685033280103&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Email {}
fun loadEmails(person: Person) : List&amp;lt;Email&amp;gt; {
  println(&quot;${person.name}&quot;)
  return listOf(/*...*/)
}
class Person(val name: String) {
  private var _emails: List&amp;lt;Email&amp;gt;? = null
  val emails: List&amp;lt;Email&amp;gt;
    get() {
      if (_emails == null) {
        _emails = loadEmails(this)
      }
      return _emails!!  // 저장해 둔 데이터가 있으면 그 데이터를 반환
    }
}

class Person(val name: String) {
  val emails by lazy ( loadEmails(this) )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위임 프로퍼티 구현&lt;/p&gt;
&lt;pre id=&quot;code_1685175743540&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;open class PropertyChangeAware {
  protected val changeSupport = PropertyChangeSupport(this)
  fun addPropertyChangeListener(listener: PropertyChangeListener) {
    changeSupport.addPropertyChangeListener(listener)
  }
  fun removePropertyChangeListener(listener: PropertyChangeListener) {
    changeSupport.removePropertyChangeListener(listener)
  }
}
// 프로퍼티 변경 통지 직접 구현
class Person(val name: String, age: Int, salary: Int) : PropertyChangeAware() {
  var age: Int = age
    set(newValue) {
      val oldValue = field
      field = newValue
      changeSupport.firePropertyChange(&quot;age&quot;, oldValue, newValue)
    }
  var salary: Int = salary
    set(newValue) {
      val oldValue = field
      field = newValue
      changeSupport.firePropertyChange(&quot;salary&quot;, oldValue, newValue)
    }
}
// 도우미 클래스로 프로퍼티 변경 통지 구현
class ObsservableProperty(val propName: String, var propValue: Int, val changeSupport: PropertyChangeSupport ) {
  fun getValue() : Int = propValue
  fun setValue(newValue: Int) {
    val oldValue = propValue
    propValue = newValue
    changeSupport.firePropertyChange(propName, oldValue, newValue)
  }
}
class Person(val name: String, age: Int, salary: Int) : PropertyChangeAware() {
  val _age = ObservableProperty(&quot;age&quot;, age, changeSupport)
  var age: Int
    get() = _age.getValue()
    set(value) { _age.setValue(value) }
    val _salary = ObservableProperty(&quot;salary&quot;, salary, changeSupport)
    var salary: Int
      get() = _salary.getValue()
      set(value) { _salary.setValue(value) }
}
// ObservableProperty를 프로퍼티 위임에 사용할 수 있도록 변경
class ObservableProperty(var propValue: Int, val changeSupport: PropertyChangeSupport) {
  operator fun getValue(p: Person, prop: KProperty&amp;lt;*&amp;gt;): Int = propValue
  operator fun setValue(p: Person, prop: KProperty&amp;lt;*&amp;gt;, newValue: Int) {
    val oldValue = propValue
    propValue = newValue
    changeSupport.firePropertyChange(prop.name, oldValue, newValue)
  }
}
// 위임 프로퍼티를 통해 프로퍼티 변경 통지 받기
class Person(val name: String, age: Int, salary: Int) : PropertyChangeAware() {
  var age: Int by ObservableProperty(age, changeSupport)
  var salary: Int by ObservableProperty(salary, changeSupport)
}
// Delegates.observable 사용해서 프로퍼티 변경 통지 구현
class Person(val name: String, age: Int, salary: Int) : PropertyChangeAware() {
  private val observer = {
    prop: KProperty&amp;lt;*&amp;gt;, oldValue: Int, newValue: Int -&amp;gt; changeSupport.firePropertyChange(prop.name, oldValue, newValue)
    var age: Int by Delegates.observable(age, observer)
    var salary: Int by Delegates.observable(salary, observer)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위임 프로퍼티 컴파일 규칙&lt;/p&gt;
&lt;pre id=&quot;code_1685189490932&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val x = c.prop / val x = &amp;lt;delegate&amp;gt;.getValue(c, &amp;lt;property&amp;gt;)
c.prop = x / &amp;lt;delegate&amp;gt;.setValue(c, &amp;lt;property&amp;gt;, x)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로퍼티 값을 맵에 저장&lt;/p&gt;
&lt;pre id=&quot;code_1685190548095&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
  // 추가 정보
  private val _attributes = hashMapOf&amp;lt;String, String&amp;gt;()
  fun setAttribute(attrName: String, value: String) {
    _attributes[attrName] = value
  }
  // 필수 정보
  val name: String
  get() = _attributes[&quot;name&quot;]!!
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위임 프로퍼티로 맵에 저장&lt;/p&gt;
&lt;pre id=&quot;code_1685190578104&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
  private val _attributes = hashMapOf&amp;lt;String, String&amp;gt;()
  fun setAttribute(attrName: String, value: String) {
    _attributes[attrName] = value
  }
  val name: String by _attributes
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프레임워크에서 위임 프로퍼티 활용&lt;/p&gt;
&lt;pre id=&quot;code_1685191531991&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;object Users : IdTable() {
  val name = varchar(&quot;name&quot;, length = 50).index()
  val age = integer(&quot;age&quot;)
}

class User(id: EntityID) : Entity(id) {
  var name: String by Users.name
  var age: Int by Users.age
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/54</guid>
      <comments>https://rooted.tistory.com/54#entry54comment</comments>
      <pubDate>Sat, 27 May 2023 21:45:35 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - 타입 시스템</title>
      <link>https://rooted.tistory.com/53</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;널 가능성&lt;/h4&gt;
&lt;pre id=&quot;code_1683361700227&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun strLen(s: String) = s.length // null 전달 불가
fun strLen(s: String?) : Int = if (s != null) s.length else 0 // null 전달 가능&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 널이 될 수 있는 값을 널이 될 수 없는 타입의 변수에 대입 불가&lt;br /&gt;- 널이 될 수 있는 타입의 값을 널이 될 수 없는 타입의 파라미터를 받는 함수에 전달 불가&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;안전한 호출 연산자 : ?.&lt;/h4&gt;
&lt;pre id=&quot;code_1683363214575&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun managerName(employee: Employee): String? = employee.manager?.name&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;엘비스 연산자 : ?:&lt;/h4&gt;
&lt;pre id=&quot;code_1683363290817&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun foo(s: String) {
    val t: String = s ?: &quot;&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- null 대신 디폴트 값을 지정할 때 사용&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;안전한 캐스트 : as?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- as : 대상 타입으로 캐스팅하는 연산자&lt;br /&gt;- as? : 대상 타입으로 캐스팅 불가시 null 반환&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;널 아님 단언 : !!&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어떤 값이든 널이 될 수 없는 값으로 변경&lt;br /&gt;- null 인경우 NullPointException 발생&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;let 함수&lt;/h4&gt;
&lt;pre id=&quot;code_1683363801349&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;email?.let { email -&amp;gt; sendEmailTo(email) }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- null 이 아닌 경우만 람다식 호출하도록 활용&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;지연 초기화 (late-initialized)&lt;/h4&gt;
&lt;pre id=&quot;code_1683364088800&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyService {
    fun preformAction(): String = &quot;foo&quot;
}
class MyTest {
    private lateinit var myService: MyService // lateinit 선언
    @Before fun setUp() {
        myService = MyService() // 메서드에서 프로퍼티 초기화
    }
    @Test fun testAction() {
        Assert.assertEquals(&quot;foo&quot;, myService.performAction()) // null 검사 없이 수행
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;nullable 객체의 확장 함수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- String? 타입에는 isNullOrEmpty, isNullOrBlank 메서드 존재, 안전한 호출하지 않아도 가능&lt;/p&gt;
&lt;pre id=&quot;code_1683364311501&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun String?.isNullOrBlank(): Boolean = this == null || this.isBlank()&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;타입 파라미터의 널 가능성&lt;/h4&gt;
&lt;pre id=&quot;code_1683364909869&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun &amp;lt;T&amp;gt; printHashCode(t: T) {
    println(t?.hashCode()) // 안전한 호출
}
fun &amp;lt;T: Any&amp;gt; printhashCode(t: T) { // null이 될 수 없는 타입
    println(t.hashCode())
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;원시 타입&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 정수 타입 : Byte, Short, Int, Long&lt;br /&gt;- 부동소수점 수 타입 : Float, Double&lt;br /&gt;- 문자 타입 : Char&lt;br /&gt;- 불리언 타입 : Boolean&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;숫자 변환&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자동 변환 불가&lt;br /&gt;- toByte(), toShort(), toChar() 등의 메소드로 변환 함수가 제공&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;최상위 타입&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Java의 최상위 타입 : Object&lt;br /&gt;- Kotlin의 최상위 타입 : Any&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Unit 타입&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 아무것도 반환하지 않는 타입&lt;br /&gt;- Java의 Void 타입은 null도 포함하기 때문에 항상 return null이 필요함&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Nothinig 타입&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 테스트 코드 등에서 예외를 던지는 케이스처럼 정상적으로 종료되지 않을 경우에 명시적으로 선언&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;컬렉션&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 표준 라이브러리에서 null인 값을 필터링하는 filterNotNull 함수 제공&lt;br /&gt;- kotlin.collections.Collection : 읽기 전용 / size, iterator(), contains()&lt;br /&gt;- kotlin.collections.MutableCollection : 변경 가능 / add(), remove(), clear()&lt;br /&gt;- 컬렉션 생성 함수&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 68px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;컬렉션 타입&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;읽기 전용 타입&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;변경 가능 타입&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;List&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;listOf&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;mutableListOf, arrayListOf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Set&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;setOf&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;mutableSetOf, hashSetOf, linkedSetOf, sortedSetOf&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;Map&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;mapOf&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;mutableMapOf, hashMapOf, linkedMapOf, sortedMapOf&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1683369610141&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Java
interface DataParser&amp;lt;T&amp;gt; {
    void parseDate(String input, List&amp;lt;T&amp;gt; output, List&amp;lt;String&amp;gt; errors);
}
// Kotlin
class PersonParser : DataParser&amp;lt;Person&amp;gt; {
    override fun parseDate(input: String, output: MutableList&amp;lt;Person&amp;gt;, errors: MutableList&amp;lt;String?&amp;gt;) {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;배열&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- arrayOf : 입력한 원소를 기준으로 배열 생성&lt;br /&gt;- arrayOfNulls : 입력한 정수 값 기준으로 모든 원소가 null이고 입력한 값의 크기로 배열 생성&lt;br /&gt;- Array 생성자 : 각 원소가 null이 아닌 배열을 만들어야 하는 경우 사용&lt;/p&gt;
&lt;pre id=&quot;code_1683369826084&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val letters = Array&amp;lt;String&amp;gt;(26) { i -&amp;gt; ('a'+i).toString() }
val zeros = IntArray(5) // 기본값 0
val zeros = intArrayOf(0,0,0,0,0)
val squares = IntArray(5) { i -&amp;gt; (i+1) * (i+1) }
&amp;gt;&amp;gt;&amp;gt; println(squares.joinToString()) // 1, 4, 9, 16, 25&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 컬렉션을 배열로 변경 : toTypedArray()&lt;/p&gt;
&lt;pre id=&quot;code_1683369878517&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val strings = listOf(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;)
println(&quot;%s/%s/%s&quot;.format(*strings.toTypedArray())) // 스프레드 연산자(*)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/53</guid>
      <comments>https://rooted.tistory.com/53#entry53comment</comments>
      <pubDate>Sat, 6 May 2023 19:48:22 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - 클래스, 객체, 인터페이스</title>
      <link>https://rooted.tistory.com/52</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;인터페이스&lt;/h4&gt;
&lt;pre id=&quot;code_1682149959100&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Clickable {
    fun click()
    fun showOff() = println(&quot;clickable&quot;)
}

interface Focusable {
    fun setFocus(b: Boolean) = println(&quot;${if (b) &quot;got&quot; else &quot;lost&quot;} focus&quot;)
    fun showOff() = println(&quot;focusable&quot;)
}

class Button : Clickable, Focusable {
    override fun click() = println(&quot;click&quot;)
    override fun showOff() {
        super&amp;lt;Clickable&amp;gt;.showOff()
        super&amp;lt;Focusable&amp;gt;.showOff()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클래스&lt;/h4&gt;
&lt;pre id=&quot;code_1682150074622&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;open class RichButton : Clickable {
    fun disable() {} // final
    open fun animate() {} // open
    override fun click() {} // open(default)
    final override fun click() {} // final
}

abstract class Animated {
    abstract fun animate()
    open fun stopAnimating() {} // open
    fun animateTwice() {} // final
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- final : override 불가&lt;br /&gt;- open : override 가능&lt;br /&gt;- abstract : override 필수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- public : 모든 곳&lt;br /&gt;- internal : 같은 모듈&lt;br /&gt;- protected : 하위 클래스&lt;br /&gt;- private : 같은 클래스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;내부 클래스에서 외부 클래스 참조에 접근하려면 this@Outer&lt;/h4&gt;
&lt;pre id=&quot;code_1682150496295&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Outer {
    inner class Inner {
        fun getOuterReference(): Outer = this@Outer
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;sealed class&lt;/h4&gt;
&lt;pre id=&quot;code_1682150759329&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
fun eval(e: Expr): Int =
    when (e) {
        is Num -&amp;gt; e.value
        is Sum -&amp;gt; eval(e.right) + eval(e.left)
        else -&amp;gt; throw Exception() // else 분기 필수
    }
}

sealed class Expr {
    class Num(val value: Int) : Expr()
    class Sum(val left: Expr, val right: Expr) : Expr()
}
fun eval(e: Expr): Int =
    when (e) {
        is Expr.Num -&amp;gt; e.value
        is Expr.Sum -&amp;gt; eval(e.right) + eval(e.left)
        // else 없어도됌
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;데이터 클래스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- equals, hashCode, toString 메소드 포함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/52</guid>
      <comments>https://rooted.tistory.com/52#entry52comment</comments>
      <pubDate>Mon, 1 May 2023 11:13:13 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - 람다 프로그래밍</title>
      <link>https://rooted.tistory.com/51</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;람다 기본 문법&lt;/h4&gt;
&lt;pre id=&quot;code_1682905454655&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val peoples = listOf(Person(&quot;alice&quot;, 29), Person(&quot;bob&quot;, 31))
println(peoples.maxBy { it.age }) // Persion(name=bob, age=31)

peoples.maxBy(persion::age)

val = sum { x: Int, y: Int -&amp;gt; x + y }
sum(1, 2)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;run : 인자로 받은 람다를 실행해주는 라이브러리 함수&lt;/h4&gt;
&lt;pre id=&quot;code_1682905474076&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;run { println(42) }

peoples.maxBy({ p: Person -&amp;gt; p.age })
peoples.maxBy() { p: Person -&amp;gt; p.age })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;인자에 람다 넘기기&lt;/h4&gt;
&lt;pre id=&quot;code_1682905481383&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;peoples.joinToString(seperator = &quot; &quot;, transform = { p: Person -&amp;gt; p.name })

peoples.joinToString(&quot; &quot;) { p: Person -&amp;gt; p.name }

peoples.maxBy { p: Person -&amp;gt; p.age }
peoples.maxBy { p -&amp;gt; p.age }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;it : 디폴트 파라미터 이름&lt;/h4&gt;
&lt;pre id=&quot;code_1682905488501&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;peoples.maxBy { it.age }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;람다를 변수에 저장할 때는 파라미터 타입 추론이 불가하여 반드시 명시&lt;/h4&gt;
&lt;pre id=&quot;code_1682905493660&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val getAge = { p: Person -&amp;gt; p.age }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;여러&amp;nbsp;줄로&amp;nbsp;이뤄진&amp;nbsp;람다는&amp;nbsp;마지막&amp;nbsp;식이&amp;nbsp;람다의&amp;nbsp;결과&amp;nbsp;값&lt;/h4&gt;
&lt;pre id=&quot;code_1682905499904&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val sum = { x: Int, y: Int -&amp;gt;
    println(&quot;$x plus $y&quot;)
    x + y
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;현재&amp;nbsp;영역에&amp;nbsp;있는&amp;nbsp;변수에&amp;nbsp;접근&lt;/h4&gt;
&lt;pre id=&quot;code_1682905504418&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun printMessagesWithPrefix(messages: Collection&amp;lt;String&amp;gt;, prefix: String) {
    messages.forEach {
        println(&quot;$prefix $it&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;람다 안에서 바깥 함수의 로컬 변수 변경하기&lt;/h4&gt;
&lt;pre id=&quot;code_1682905509577&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun printProblemCounts(responses: Collection&amp;lt;String&amp;gt;) {
    var clientErrors = 0
    var serverErrors = 0
    responses.forEach {
        if (it.startsWith(&quot;4&quot;)) {
             clientErrors++
        } else if (it.startsWith(&quot;5&quot;)) {
             serverErrors++
        }
    }
    println(&quot;$clientErros client errors, $serverErrors server errors&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;멤버 참조, 함수 참조&lt;/h4&gt;
&lt;pre id=&quot;code_1682905542588&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;멤버 참조
val getAge = Person::age

최상위 함수 참조
fun salute() = println(&quot;salute&quot;)
run(::salute)

val nextAction = ::sendEmail

val createPerson = ::Person
val p = createPerson(&quot;alice&quot;, 29)

확장 함수도 참조 가능
fun Person.isAdult() = age &amp;gt;= 21
val predicate = Person::isAdult&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;컬렉션 함수형 API&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- filter&lt;br /&gt;- map &lt;br /&gt;- 맵의 경우 filterKeys, mapKeys, filterValues, mapValues 함수 존재&lt;br /&gt;- all&lt;br /&gt;- any&lt;br /&gt;- count&lt;br /&gt;- find&lt;/p&gt;
&lt;pre id=&quot;code_1682906793411&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val isAdult = { p: Person -&amp;gt; p.age &amp;gt;= 21 }

peoples.all(isAdult) // 모두 만족
peoples.any(isAdult) // 하나라도 만족
peoples.count(isAdult) // 만족하는 갯수
peoples.find(isAdult) // 만족하는 원소 한개 찾기, 없는 경우 null&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- groupBy : 컬렉션을 맵으로 변환&lt;br /&gt;- flatMap : 중첩된 컬렉션 안의 원소 처리&lt;/p&gt;
&lt;pre id=&quot;code_1682906840455&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;books.flatMap { it.authors }.toSet()
val strs = listOf(&quot;abc&quot;, &quot;def&quot;)
str.flatmap { it.toList() } &amp;gt;&amp;gt; a, b, c, d, e, f&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;지연 컬렉션 연산&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시퀀스 연산 실행 : 중간 연산과 최종 연산&lt;/p&gt;
&lt;pre id=&quot;code_1682906962139&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sequence.map { }.filter { }.toList()
- 중간 연산 : map, filter
- 최종 연산 : toList&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 자바 8 이후 스트림 = 시퀀스는 동일 / 이전 자바 버전 사용할 경우 시퀀스 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;시퀀스 생성&lt;/h4&gt;
&lt;pre id=&quot;code_1682905677067&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val naturalNumbers = generateSequence(0) { it + 1 }
val numbersTo100 = naturalNumbers.takeWhile { it &amp;lt;= 100 }
numbersTo100.sum()

fun File.isInsideHiddenDirectory() = generateSequence(this) { it.parentFile }.any { it.ishidden }
val file = File(&quot;/Users/user/.HiddenDir/a.txt&quot;)
file.isInsideHiddenDirectory()

자바 메소드에 람다를 인자로 전달
void postponeComputation(int delay, Runnable computation);
postponecomputation(1000) { println(42) }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SAM 생성자 : 람다를 함수형 인터페이스로 명시적으로 변경&lt;/h4&gt;
&lt;pre id=&quot;code_1682905871497&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun createAllDonerunnable() : Runnable {
    return Runnable { println(&quot;done&quot;) }
}

&amp;gt;&amp;gt;&amp;gt; createAllDoneRunnable().run()

val listener = OnClickListener { view -&amp;gt;
    val text = when (view.id) {
        R.id.button1 -&amp;gt; &quot;first&quot;
        R.id.button2 -&amp;gt; &quot;second&quot;
        else -&amp;gt; &quot;unknown&quot;
    }
    toast(text)
}
button1.setOnClickListener(listener)
button2.setOnClickListener(listener)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;수신 객체 지정 람다 : with, apply&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;with&lt;/h4&gt;
&lt;pre id=&quot;code_1682906156985&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun alphabet() : String {
    val result = StringBuilder()
    for (letter in 'A'..'Z') {
        result.append(letter)
    }
    result.append(&quot;\nDone&quot;)
    return result.toString()
}

// with 사용
fun alphabet() : String {
    val stringBuilder = StringBuilder()
    return with(stringBuilder) {
        for (letter in 'A'..'Z') {
            this.append(letter)
        }
        this.append(&quot;\nDone&quot;)
        this.toString()
    }
}

// with 사용
fun alphabet() = with(StringBuilder()) {
    for (letter in 'A'..'Z') {
        this.append(letter)
    }
    this.append(&quot;\nDone&quot;)
    this.toString()
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;apply&lt;/h4&gt;
&lt;pre id=&quot;code_1682906317304&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun alphabet() = StringBuilder().apply {
    for (letter in 'A'..'Z') {
        append(letter)
    }
    append(&quot;\nDone&quot;)
}.toString()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/51</guid>
      <comments>https://rooted.tistory.com/51#entry51comment</comments>
      <pubDate>Mon, 1 May 2023 11:10:56 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - 함수 정의와 호출</title>
      <link>https://rooted.tistory.com/50</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;컬렉션&lt;/h4&gt;
&lt;pre id=&quot;code_1681566161220&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val rank = listOf(&quot;1st&quot;, &quot;2nd&quot;, &quot;3rd&quot;)
val ints = setOf(1, 2, 3)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수 정의&lt;/h4&gt;
&lt;pre id=&quot;code_1681566448727&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun &amp;lt;T&amp;gt; joinToString(
  collection: Colletion&amp;lt;T&amp;gt;,
  separator: String = &quot;,&quot;,
  prefix: String = &quot;(&quot;,
  postfix: String = &quot;)&quot;
) : String {
  val result = StringBuilder(prefix)
  for ((index, element) in collection.withIndex()) {
    if (index &amp;gt; 0) result.append(separator)
    result.append(element)
  }
  result.append(postfix)
  return result.toStrinig()
}

joinToString(collection, &quot;,&quot;, &quot;(&quot;, &quot;)&quot;)
joinToString(collection)
joinToString(collection, separator = &quot;/&quot;, prefix = &quot;[&quot;, postfix = &quot;]&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;확장 함수&lt;/h4&gt;
&lt;pre id=&quot;code_1681566964559&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun String.lastChar(): Char = get(length - 1)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;확장 프로퍼티&lt;/h4&gt;
&lt;pre id=&quot;code_1681566989720&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val String.lastChar: Char
  get() = get(length - 1)
  set(value: Char) {
    this.setCharAt(length - 1, value)
  }
  
&quot;Kotlin&quot;.lastChar = 'x'&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;가변 인자 함수&lt;/h4&gt;
&lt;pre id=&quot;code_1681567167369&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun listOf&amp;lt;T&amp;gt;(vararg values: T): List&amp;lt;T&amp;gt; { }&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;중위 호출&lt;/h4&gt;
&lt;pre id=&quot;code_1681567450835&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1.to(&quot;one&quot;) // 일반적인 방식
1 to &quot;one&quot; // 중위 호출 방식&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;구조 분해 선언&lt;/h4&gt;
&lt;pre id=&quot;code_1681567484460&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val (number,name) = 1 to &quot;one&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;로컬 함수&lt;/h4&gt;
&lt;pre id=&quot;code_1681567995980&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 로컬 함수로 추가하기
fun saveUser(user: User) {
  fun validate(value: String) {
    if (value.isEmpty()) {
      throw IllegalArgumentException(&quot;${user.id}&quot;)
    }
  }
  validate(user.name)
  validate(user.address)
}

// 확장 함수로 추출하기
fun User.validateBeforeSave() {
  fun validate(value: String) {
    if (value.isEmpty()) {
      throw IllegalArgumentException(&quot;${user.id}&quot;)
    }
  }
  validate(user.name)
  validate(user.address)
}

fun saveUser(user: User) {
  user.validateBeforeSave()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/50</guid>
      <comments>https://rooted.tistory.com/50#entry50comment</comments>
      <pubDate>Sat, 15 Apr 2023 23:16:27 +0900</pubDate>
    </item>
    <item>
      <title>Kotlin - 기초</title>
      <link>https://rooted.tistory.com/49</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;함수&lt;/h4&gt;
&lt;pre id=&quot;code_1681562707223&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun sum(a: Int, b: int) : Int {
    return a + b
}
fun sum(a: Int, b: Int) = a + b&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;변수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;val = value, 변경 불가&lt;br /&gt;var = variable, 변경 가능&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;문자열 템플릿&lt;/h4&gt;
&lt;pre id=&quot;code_1681562862675&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun main(args: Array&amp;lt;String&amp;gt;) {
    println(&quot;${if (args.size &amp;gt; 0) args[0] else &quot;&quot;}&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클래스&lt;/h4&gt;
&lt;pre id=&quot;code_1681563030536&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Database(val name: String)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프로퍼티&lt;/h4&gt;
&lt;pre id=&quot;code_1681563085542&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Database(
    val name: String,
    var isOpenSource: Boolean
)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;커스텀 접근자&lt;/h4&gt;
&lt;pre id=&quot;code_1681563452609&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Database(
    val name: String,
    var isOpenSource: Boolean
) {
    val isFree: Boolean
      get() {
        return isOpenSource
      }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;enum&lt;/h4&gt;
&lt;pre id=&quot;code_1681563500005&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum class DatabaseType {
  MYSQL, MARIADB, POSTGRESQL, ORACLE
}

enum class DatabaseType(
  val tp: String
) {
  MYSQL(&quot;RDBMS&quot;), MARIADB(&quot;RDBMS&quot;), MONGODB(&quot;NoSQL&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;when&lt;/h4&gt;
&lt;pre id=&quot;code_1681564534755&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(e: Expr) : Int =
  when (e) {
    is Num -&amp;gt;
      e.value
    is Sum -&amp;gt;
      eval(e.right) + eval(e.left)
    else -&amp;gt;
      throw IllegalArgumentException(&quot;Unknown expression&quot;)
  }&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;while&lt;/h4&gt;
&lt;pre id=&quot;code_1681564611251&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while (condition) {

}

do {

} while (condition)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;for&lt;/h4&gt;
&lt;pre id=&quot;code_1681564723615&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (i in 1..100) {
  // 1 ~ 100
}

for (i in 100 downTo 1 step 2) {
  // 100, 98, ..., 4, 2
}

for (c in 'A'...'Z') {
  // A, B, ..., Z
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;in&lt;/h4&gt;
&lt;pre id=&quot;code_1681565390890&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun isDigit(c: Char) = c in '0'..'9'
fun isNotDigit(c: Char) = c !in '0'..'9'
fun categorize(c: Char) = when (c) {
  in '0'..'9' -&amp;gt; &quot;digit&quot;
  in 'a'..'z', in 'A'..'Z' -&amp;gt; &quot;letter&quot;
  else -&amp;gt; &quot;?&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;try catch finally&lt;/h4&gt;
&lt;pre id=&quot;code_1681565514943&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun readNumber(reader: BufferedReader) {
  val number = try {
    Integer.parseInt(reader.readLine())
  } catch (e: NumberFormatException) {
    null
  }
  println(number)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Back End/Kotlin</category>
      <author>RootedIn</author>
      <guid isPermaLink="true">https://rooted.tistory.com/49</guid>
      <comments>https://rooted.tistory.com/49#entry49comment</comments>
      <pubDate>Sat, 15 Apr 2023 22:33:49 +0900</pubDate>
    </item>
  </channel>
</rss>