Kotlin
-
41장 - hashCode의 규약을 지켜라Kotlin/Effective Kotlin 요약 2023. 4. 4. 00:01
해시 테이블 해시 테이블은 각 요소에 숫자를 할당하는 함수가 필요합니다. 이 함수를 해시 함수라고 부릅니다. 같은 요소라면 항상 같은 숫자를 리턴합니다. 해시 함수가 다음과 같은 특성을 가지는 것이 좋습니다. 빠르다. 충돌이 적다 해시 함수는 각각의 요소에 특정한 숫자를 할당하고, 이를 기반으로 요소를 다른 버킷에 넣습니다. 해시 함수의 기본조건인 같은 요소라면 항상 같은 숫자를 리턴한다에 의해 같은 요소는 항상 동일한 버킷에 넣게 됩니다. 가변성과 관련된 문제 요소를 추가할 때만 해시 코드를 계산합니다. 즉, 요소가 변경되어도 해시 코드는 계산되지 않으며 버킷의 재배치로 이루어지지 않습니다. Set과 Map의 키로 mutable 요소를 사용하면 안 되며, 사용하더라도 요소를 변경하면 안 됩니다. has..
-
40장 - equals 규약을 지켜라Kotlin/Effective Kotlin 요약 2023. 3. 29. 00:01
Any의 규약 equals hashCode toString 주석과 문서에 잘 설명되어 있는 규약들입니다. 자바에서부터 정의되어 있던 메서드라서 코틀린에서 중요한 위치를 차지하고 있습니다. 위의 규약을 위반하면 일부 객체 또는 기능이 제대로 동작하지 않을 수 있습니다. 동등성 코틀린에는 두 가지 종류의 동등성이 있습니다. 구조적 동등성(equals 메서드를 기반으로 비교) , 사용하는 연산자 == 레퍼런스적 동등성(가리키는 주소를 비교) , 사용하는 연산자 === equals가 필요한 이유 Any 클래스에 구현되어 있는 equals는 디폴트로 ===처럼 두 인스턴스가 완전히 같은 객체인지 비교합니다. class Name(val name: String) fun main() { val name1 = Name(..
-
39장 - 태그 클래스보다는 클래스 계층을 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 28. 00:01
태그 클래스 class ValueMatcher private constructor( private val value: T? =null, private val matcher: Matcher ){ fun match(value: T?) = when(matcher){ Matcher.EQUAL -> value == this.value Matcher.LIST_EMPTY -> value is List && value.isEmpty() } enum class Matcher{ EQUAL, LIST_EMPTY, } companion object{ fun equal(value: T) = ValueMatcher(value = value, matcher = Matcher.EQUAL) fun emptyList() = ValueM..
-
38장 - 연산 또는 액션을 전달할 때는 인터페이스 대신 함수 타입을 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 27. 00:01
대부분의 프로그래밍 언어에는 함수 타입이란 개념이 없습니다. 보통 Single-Abstract-Method이라 불리는 메서드가 하나만 있는 인터페이스를 활용합니다. interface OnClick{ fun clicked(view: View) } //함수가 SAM을 받음 fun setOnClickListener(listener: OnClick){ //... } //함수 타입을 사용하는 코드로 변경 fun setOnClickListener(listener: (View) -> Unit){ //... } 함수 타입을 사용하는 코드를 활용한다면 많은 자유를 얻을 수 있습니다. 람다 표현식 또는 익명 함수로 전달 함수 레퍼런스 또는 제한된 함수 레퍼런스로 전달 선언된 함수 타입을 구현한 객체로 전달 SAM의 장점은..
-
37장 - 데이터 집합 표현에 data 한정자를 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 26. 00:01
데이터들을 전달해야 할 때 일반적으로 data 한정자를 활용합니다. 다음과 같은 몇 가지 함수가 자동으로 생성됩니다. toString equals와 hashCode copy componentN 생소한 componentN에 대해서만 알아보면 다음과 같이 가능합니다. data class Player( val id: Int, val name: String, val pts: Int, ) fun main() { val player = Player(0, "jun", 1) val (id, name, pts) = player println(pts) //1 출력 } 튜플 대신 데이터 클래스 활용하기 여기서 튜플이란 Pair, Triple으로 코틀린에서 지원합니다. 하지만 튜플을 사용하면 가독성이 매우 떨어지게 됩니다. ..
-
36장 - 상속보다는 컴포지션을 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 25. 00:01
개요 상속은 is-a 관계의 객체 계층 구조를 만들기 위해 설계되었습니다. 코드의 재사용성을 위해 상속을 사용할 때 관계가 명확하지 않을 때 신중하게 고려해야 합니다. 간단한 행위 재사용 class ProfileLoader{ fun load(){ //프로그래스 바 노출 //프로필 읽기 //프로그래스 바 숨김 } } class ImageLoader{ fun load(){ //프로그래스 바 노출 //이미지 읽기 //프로그래스 바 숨김 } } 이런 경우 보통 슈퍼클래스를 만들어 공통되는 행위를 뽑아냅니다. 하지만 몇 가지 단점이 존재합니다. 상속을 사용해서 행위를 추출하다 보면, 많은 함수를 갖는 거대한 BaseXXX 클래스가 만들어지며 깊고 복잡한 계층 구조가 만들어집니다. 불필요한 함수를 갖는 클래스가 만..
-
35장 - 복잡한 객체를 생성하기 위한 DSL을 정의하라Kotlin/Effective Kotlin 요약 2023. 3. 21. 00:01
코틀린을 활용하면 DSL을 직접 만들 수 있습니다. DSL을 만드는 것은 수고스러우나, 한 번 만들고 나면 보일러플레이트와 복잡성을 숨기면서 개발자의 의도를 명확하게 표현할 수 있습니다. Spring Kotlin개발자에게는 다음과 같은 DSL이 친숙할 수 있습니다. Kotest를 활용하여 테스트 케이스를 정의할 때 Gradle의 설정을 정의할 때 사용자 정의 DSL 만들기 DSL을 만들기 전 리시버를 사용하는 함수 타입에 대한 개념을 이해해야 합니다. 람다식을 떠올리면 좋으며 함수 타입의 몇 가지 예시입니다. () -> Unit 아규먼트를 갖지 않고 Unit을 리턴 (Int, Int) -> Int Int타입 아규먼트 2개를 받고, Int를 리턴하는 함수 함수 타입을 만드는 기본적인 방법들 람다 표현식 익..
-
34장 - 기본 생성자에 이름 있는 옵션 아규먼트를 사용하라Kotlin/Effective Kotlin 요약 2023. 3. 20. 00:01
객체를 생성하고 사용하는 가장 기본적인 방법 class User(var name: Stirng, var surname: String) val user = User("Marcin", "Moskala") 이처럼 객체의 초기 상태를 나타내는 아규먼트를 전달합니다. 데이터 모델 객체 data class Student( val name: String, val surname: String, val age: Int, ) 하지만 생성자에 선언된 아규먼트 이외에도 클래스의 필드로도 프로퍼티를 가질 수 있습니다. 이럴 때는 어떻게든 초기화된 되면 상관없습니다. 일반적으로 기본생성자가 제일 좋은 방식인 이유를 이해하려면, 점층적 생성 패턴과 빌더 패턴에 대해 이해하는 것이 좋습니다. 점층적 생성 패턴 class Pizza{..