목록Kotlin/이펙티브 코틀린 (52)
안드로이드 개발자 노트
아규먼트(argument)로 함수에 값을 전달할 수 있는 것처럼, 타입 아규먼트를 사용하면 함수에 타입을 전달할 수 있습니다. 타입 아규먼트를 사용하는(타입 파라미터를 갖는) 함수를 제네릭 함수라고 부릅니다. 예를 들어, slice 함수는 타입 파라미터 T를 갖습니다. public fun List.slice(indices: IntRange): List { if (indices.isEmpty()) return listOf() return this.subList(indices.start, indices.endInclusive + 1).toList() } 타입 파라미터는 컴파일러에 타입과 관련된 정보를 제공하여 컴파일러가 타입을 정확하게 추측할 수 있게 해줍니다. 제네릭은 기본적으로 List 또는 Set처럼 ..
코틀린은 코드 재사용과 관련해서 프로퍼티 위임이라는 새로운 기능을 제공합니다. 프로퍼티 위임을 사용하면 일반적인 프로퍼티의 행위를 추출해서 재사용할 수 있습니다. 대표적인 예로 지연 프로퍼티가 있으며, 코틀린의 stdlib는 lazy 프로퍼티 패턴을 쉽게 구현할 수 있게 lazy 함수를 제공합니다. val value by lazy { createValue() } 프로퍼티 위임을 사용하면, 변화가 있을 때 이를 감지하는 observable 패턴을 쉽게 만들 수 있습니다. val items: List by Delegates.observable(listOf()) { _, _, _ -> notifyDataSetChanged() } val key: String? by Delegates.observable(null..
많은 개발자는 같은 알고리즘을 여러 번 반복해서 구현합니다. 여기서 말하는 알고리즘은 비즈니스 로직을 포함하는 특정 프로젝트에 국한된 것이 아닌, 수학적인 연산, 수집 처리처럼 별도의 모듈 또는 라이브러리로 분리할 수 있는 부분을 의미합니다. 예를 들어 Iterable.sorted와 같이 이미 있는 것을 활용하면, 단순하게 코드가 짧아진다는 것 이외에도 다양한 장점이 있습니다. 코드 작성 속도가 빨라진다. 호출을 한 번 하는 것이 알고리즘을 만드는 것보다 빠르다. 구현을 따로 읽지 않아도, 함수의 이름 등만 보고도 무엇을 하는지 확실하게 알 수 있다. 직접 구현할 때 발생할 수 있는 실수를 줄일 수 있다. 제작자들이 한 번만 최적화하면, 이러한 함수를 활용하는 모든 곳에 최적화의 헤택을 받는다. 표준 라..
"프로젝트에서 이미 있던 코드를 복사해서 붙여넣고 있다면, 무언가가 잘못된 것이다" 필자가 생각하는 프로그래밍의 가장 큰 규칙이며, 이를 'knowledge를 반복하여 사용하지 말라'라는 규칙으로 표현하고 있습니다. knowledge는 '의도적인 정보'를 뜻하며, 코드 또는 데이터로 표현할 수 있습니다. 또한, knowledge는 알고리즘의 작동 방식, UI의 형태, 원하는 결과 등 모든 의도적인 정보를 말합니다. 프로그램에서 중요한 knowledge를 크게 두 가지 뽑는다면, 다음과 같습니다. 로직(logic): 프로그램이 어떠한 식으로 동작하는지와 프로그램이 어떻게 보이는지 공통 알고리즘(common algorithm): 원하는 동작을 하기 위한 알고리즘 둘의 가장 큰 차이점은 시간에 따른 변화입니다..
코딩 컨벤션이란 읽고 관리하기 쉬운 코드를 작성하기 위한 일종의 코딩 스타일 규약입니다. 코틀린은 굉장히 잘 정리된 코딩 컨벤션을 갖고 있습니다. 코틀린뿐만 아니라, 어떤 개발 언어든 공식적인 컨벤션을 따르는게 좋습니다. 어떤 프로젝트를 접해도 쉽게 이해할 수 있다. 다른 외부 개발자도 프로젝트의 코드를 쉽게 이해할 수 있다. 다른 개발자도 코드의 작동 방식을 쉽게 추측할 수 있다. 코드를 병합하고, 한 프로젝트의 코드 일부를 다른 코드로 이동하는 것이 쉽다. IntelliJ 에서 설정이나 도구, 플러그인을 활용해 코틀린 컨벤션 검사를 할 수 있습니다. Setting ➡ Editor ➡ Code Style ➡ Kotlin 클릭 우측 상단 Set from... ➡ 원하는 스타일 가이드를 지정 Style i..
이름있는 아규먼트(네임드 파라미터)를 사용하면 코드가 길어지지만, 두 가지 장점이 생깁니다. 이름을 기반으로 값이 무엇을 나타내는지 알 수 있습니다. 파라미터 입력 순서와 상관 없으므로 안전합니다. 예제를 통해 살펴보겠습니다. val text = (1..10).joinToString("|") joinToString에 대해 이미 알고 있다면, "|"이 구분자(separator)를 의미한다는 것을 알 것입니다. 해당 함수에 대해서 잘 모른다면, 한눈에 파라미터가 명확하지 않게 보일 수도 있습니다. 파라미터가 명확하지 않은 경우에는 이를 직접 지정해서 명확하게 만들어 줄 수 있습니다. val text = (1..10).joinToString(separator = "|") 파라미터에 변수를 사용해서 더욱 의미를..
기본적으로 코틀린의 프로퍼티는 사용자 정의 게터와 세터를 가질 수 있습니다. var name: String? = null get() = field?.toUpperCase() set(value) { if (!value.isNullOrBlank()) { field = value } } 이 코드에서 field라는 식별자를 확인할 수 있습니다. 이는 프로퍼티의 데이터를 저장해두는 백킹 필드(backing field)에 대한 레퍼런스입니다. val을 사용해서 읽기 전용 프로퍼티를 만들 때는 field가 만들어지지 않습니다. val fullName: String get() = "$name $surname" var를 이용한 프로퍼티는 게터와 세터를 정의할 수 있으며, 이를 파생 프로퍼티(derived property..
코틀린에서는 특정 객체(타입)을 리시버(수신 객체)로 사용할 수 있습니다. // block: (T) -> R 일반적인 함수 정의 val block: (Int) -> Int = ... block(3) // block: T.() -> R 객체 T를 receiver 로 활용한다. val block: Int.() -> Int = ... 100.block(3) 이 경우에는 this를 사용해서 리시버를 참조할 수 있습니다. val sum = fun Int.(other: Int): Int { return this + other // 키워드 this 를 이용해 리시버 객체에 접근한다. } val result = 3.sum(5) print(result) // 8 this를 명시적으로 사용하지 않고 생략할 수도 있으며, ..
코틀린은 타입 추론 시스템을 갖추고 있습니다. 이는 개발 시간을 줄여줄 뿐만 아니라 유형이 명활할 때 코드가 짧아지므로 코드의 가독성이 크게 향상됩니다. 하지만 유형이 명확하지 않을 때는 남용하면 좋지 않습니다. val data = getSomeData() 가독성을 위해 코드를 설계할 때는 읽는 사람에게 중요한 정보를 숨겨서는 안 됩니다. 또한 가독성 향상 이외에 안전을 위해서도 타입을 지정하는 것이 좋습니다. 관련된 내용으로, 'item3: 최대한 플랫폼 타입을 사용하지 말라' 와 'item4: inferred 타입으로 리턴하지 말라'가 있겠습니다. 따라서 유형이 명확하지 않다면, 아래 처럼 타입을 명시해줍니다. val data: UserData = getSomeData()
코틀린에서는 void 대신, Unit 과 Nothing 이라는 타입을 제공해줍니다. Unit 은 함수가 끝났으나, 의미있는 반환값이 없는 경우 사용합니다. fun report() { // 아무것도 반환하지 않으면 return Unit 이 반환된다. } fun main(){ val result = report() println(result) // Kotlin.Unit } Nothing 은 함수가 끝이 나지 않는 경우 사용합니다. 예를 들면 throw Exception, while (true) { yield ... } 등이 있습니다. Nothing?은 모든 Nullable 타입을 상속받아서 사용합니다. 타입추론 과정에서 생긴 컴파일 오류를 명시적으로 만들어 줄 수 있습니다. var user = if ( is..