아래의 글은 드미트리 제메로프, 스베트라나 이사코바 저/오현석역,『Kotlin in Action』,에이콘출판사(2017)의 내용을 기반으로 작성하였습니다. 

 

자바 : 언어 기능을 타입에 의존하는 관례

코틀린 : 함수 이름에 의존하는 관례

 

자바 : + :  primative type에서 사용, String : String concat 연산

코틀린 : + : plus란 이름으로 된 연산자 + 로 대체됨, operator 키워드 붙이면 됨, 확장함수로도 정의 가능

*  관례로 쓰는 이름을 붙였는데, operator 연산자가 없으면 operator modifier is required 라고 에러

a + b - > a.plus(b) 가 됨

교환 법칙이 성립이 안됨 예를 들어 p * 1.5와 1.5 * p는 다름, p.times가 있냐와 Double.times가 있냐의 차이

 

오버로딩 가능한 이항 산술 연산자

expression operator convention
a * b times
a / b div
a % b mod (1.1 rem)
a + b plus
a - b minus
data class Point(val x: Int, val y: Int) {
	operator fun plus(other: Point): Point {
    	return Point(x + other.x, y + other.y)
    }
}

>>> val p1 = Point(1, 1)
>>> val p2 = Point(2, 3)
>>> println(p1 + p2)
Point(x = 3, y = 4)

operator fun Point.plus(other: Point): Point {
	return Point(x + other.x, y + other.y)
}

 

비트연산자 

operator convention 정의 자바
shl 왼쪽 시프트 <<
shr 오른쪽 시프트 >>
ushr 오른쪽 시프트 0 부호 비트 >>>
and &
or |
xor 배타 ^
inv 반전 ~

복합대입연산자

expression operator convention
+= plusAssign
-= minusAssign
*= timesAssign
/= remAssign

단항연산자오버로딩

expression operator convention
+a unaryPlus
-a unaryMinus
!a not
++a, a++ inc
--a, a-- dec
operator fun BigDecimal.inc() = this + BigDecimal.ONE

>>> val num = BigDecimal.ZERO

>>> println(num++)
0

>>> println(num)
1

>>> println(++num)
2

 

비교연산자

expression java
== equals
=== ==
!=  !equals
< p1.compareTo(p2) < 0
> p1.compareTo(p2) > 0
<= p1.compareTo(p2) <= 0
>= p1.compareTo(p2) >= 0

Comparable에 compareTo가 operator가 붙어 있어서 하위에서는 붙일 필요가 없다.

Comparable 인터페이스를 구현하는 모든 자바 클래스는 코틀린에서 간결한 연산자 구문으로  비교 가능

 

컬렉션

expression operator convention
val x = map[0] get
map[1] = 42 set
in contains
... rangeTo
for (x in list) { ... } iterator
val now = LocalDate.now()

val vacation = now...now.plusDays(10)

>>> println(now.plusWeeks(1) in vacation)
true



operator fun CharSequence.iterator(): CharInterator: Interator 
>> for(c in "abc") {}

operator fun ClosedRange<LocalDate>.iterator(): Interator<LocalDate> = 
	object : Iterator<LocalDate> {
    	val current = start
        override fun hasNext() = current <= endInclusive
        override fun next() = current.apply {
        	currnet = plusDays(1)
        }
    }
    
>>> val newYear = LocalDate.ofYearDay(2017, 1)
>>> val daysOff = newYear.minusDays(1)..newYear
>>> for (dayOff in dayOff) { println(dayOff) }
2016-12-31
2017-01-01

    

 

 구조분해선언 : componentN 함수

val (a, b) = p > val a = p.component1() val b = p.component2()

* data 클래스는 componentN  함수를 자동으로 만들어 준다. 코틀린 표준 라이브러리는 맨앞의 5개 원소에 대한 componentN을 제공

 

data class NameComponents(val name: String, val extention: String)

fun splitNameExt(filename: String): NameCompoents {
	val result = filename.split('.', limit = 2)
    return NameComponents(result[0], result[1])
}

>>> val (name, ext) = splitNameExt("file.txt")
>> println(name)
file

>>> println(ext)
txt

fun splitNameExt2(filename: String): Namecomponents {
	var (name, extention) = file.split('.', limit = 2)
    return NameComponents(name, extention)
}


for (entry in map.entries) {
	val key = entry.component1()
    val value = entry.compoent2()
}

 

위임프로퍼티 : 연산 위임

class Delegate {
	operator fun getValue(...) { ... }
    operator fun setValue(..., value: Type) { ... }
}

class Foo {
	var p: Type by Delegate()
}

>>> var foo = Foo()
>>> var oldValue = foo.p // delete.getValue 호출
>>> foo.p = newValue // delete.setValue 호출


backing 프로퍼티 : lazy지원, lazy다음에 로딩할 인자는 람다

class Person(val name: String) {
	val email by lazy { loadEmails(this) }
}

 

위임프로퍼티 실제 구현 : 연산 수행 값 get, set 만으로도 특정 메소드 get set이 되도록 위임가능하고 위임안에서 다른 작업도 수행 가능

open class PropertyChangeAware {
	protected val changeSupport = PropertyChangeSupport(this)
    
    fun addPropertyChangeListner(listener: PropertyChangeListenser) {
    	changeSupport.addPropertyChangeListener(listener)
    }
    
    fun removePropertyChangeListener(listener: PropertyChangeListener) {
    	changeSupport.removePropertyChangeLisner(listener)
    }
}

class ObservableProperty 
	(var propValue: Int, val changeSupport: PropertyChangeSupport) {
    
    operator fun getValue(p: Person, prop: KProperty<*>): Int = propVAlue
    operator fun setValue(p: Person, prop: KProperty<*>, newValue: Int) {
    	val oldValue = propValue
        propValue = newValue
        changeSupport.firePropertyChange(prop.name, oldValue, newValue)
    }
}

class Person
	(val name: String, age: Int salary: Int) {
} : PropertyChangeAware() {

	private val observer = {
    	prop: KProperty<*>, oldValue: Int, newValue: Int -> 
        changeSupport.firePropertyChange(prop.name, oldValue, newValue)
    }

	var age: Int by ObservableProperty(age, changeSupport)
    var salary: Int by ObservableProperty(salary, changeSupport)
}

val x = c.prop 
// val x = <delegate>.getValue(c, <property>)
c.prop = x
// <delegate>setValue(c, <property>, x)


'독서관련 > Kotlin in Action' 카테고리의 다른 글

CH09 코틀린 제네릭스  (0) 2021.01.29
CH08 코틀린 고차함수  (0) 2021.01.28
CH06 코틀린 컬렉션 및 배열  (0) 2021.01.17
CH06 코틀린 primative 타입  (0) 2021.01.11
CH06 코틀린 타입 시스템  (0) 2021.01.10

+ Recent posts