728x90
- 코드에서 아규먼트의 의미가 명확하지 않은 경우가 있음
- “|”은 무엇을 의미할까?
- joinToString에 대해서 알지 못하면 “|”에 대한 의미를 알기 어려움
val text = (1..10).joinToString("|")
- “|”은 무엇을 의미할까?
- 파라미터가 명확하지 않은 경우에 직접 지정해서 명확하게 만들어 줄수 있음
- val text = (1..10).joinToString(separator = "|")
- 변수를 사용해 의미를 명확하게 할 수 있음
- 실제로 코드에서 제대로 사용되고 있는지 알수 없는 단점
val separator = "|" val text = (1..10).joinToString(separator)
- 이름 있는 아규먼트를 함께 활용 하는 것이 좋음
- 변수를 잘못 만들어 사용 하는 경우 방지
- 잘못된 위치에 배치 하는 경우 방지
val separator = "|" val text = (1..10).joinToString(separator = separator)
이름 있는 아규먼트는 언제 사용해야 할까?
- 이름 있는 아규먼트를 사용하면 코드가 길어지지만, 다음과 같은 장점이 있음
- 이름을 기반으로 값이 무엇을 나타내는지 알수 있음
- 파라미터 입력 순서와 상관 없으므로 안전 함
- 아규먼트 이름은 함수를 사용하는 개발자뿐만 아니라 코드를 읽는 다른 사람들에게도 굉장히 중요한 정보
// 100ms 인지 100s인지 명확하지 않음
sleep(100)
// 이름 있는 아규먼트를 활용하여 명확하게 사용 가능
sleep(timeMillis = 100)
// 함수를 만들어 시간 단위를 표현 가능
sleep(Millis(100))
// 확장 프로퍼티로 DSL과 유사한 문법을 만들어 활용 가능
sleep(100.ms)
- 이름 있는 아규먼트를 사용하지 않으면 순서를 잘못 입력하는 문제가 있을 수 있음
- 이름 있는 아규먼트를 추천 하는 경우
- 디폴트 아규먼트의 경우
- 같은 타입의 파라미터가 많은 경우
- 함수 타입의 파라미터가 있는 경우(마지막 경우 제외)
디폴트 아규먼트의 경우
- 프롵퍼티가 디폴트 아규먼트를 가질 경우, 항상 이름을 붙여서 사용하는 것이 좋음
- 함수 이름은 필수 파라미터들과 관련되어 있기 때문에 디폴트 값을 갖는 옵션 파라미터의 설명이 명확하지 않음
같은 타입의 파라미터가 많은 경우
- 파라미터가 모두 다른 타입이라면, 위치를 잘못 입력하면 오류가 발생할 것
- 쉽게 문제를 찾을 수 있음
- 같은 타입이면 잘못 입력했을 때 문제를 찾아내기 어려울 수 있음
fun sendEmail(to: String, message: String) {}
// 이름 있는 아규먼트를 사용 하는 것을 추천
sendEmail(
to = "contact@kt.academy",
message = "Hello, ..."
)
함수 타입 파라미터
- 함수 타입 파라미터는 마지막 위치에 배치하는 것이 좋음
- 함수 이름이 함수 타입 아규먼트를 설명해 주기도 함
- thread 이후 블록이 스레드 본문이라는 것을 쉽게 알 수 있음
- 모든 함수 타입 아규먼트는 이름 있는 아규먼트를 사용하는 것이 좋음
- 이해하기 쉬움
// 어떤 부분이 빌더 부분이고, 어떤 부분이 클릭 리스너일까요? val view = linearLayout { text("Click below") button({ /* 1 */ }, { /* 2 */ }) } // 이름을 부여하고, 위치를 수정하면 훨씬 명확해짐 val view = linearLayout { text("click below") button(onClick = { /* 1*/ }) { /* 2 */ } }
- 여러 함수 타입의 옵션 파라미터가 있는 경우에는 더 어려움
fun call(before: () -> Unit = {}, after: () -> Unit = {}) {
before()
print("Middle")
after()
}
fun main() {
call({ print("CALL") }) // CALLMiddle
call { print("CALL") } // MiddleCALL
}
// 이름을 붙여 사용하면 쉽게 이해 가능
fun main() {
call(before = { print("CALL") }) // CALLMiddle
call(after = { print("CALL") }) // MiddleCALL
}
- 리액티브 라이브러리에서 굉장히 자주 볼 수 있는 형태
- Observable을 구독할 때 함수 설정
- 각각의 아이템을 받을 때(onNext)
- 오류가 발생했을 때(onError)
- 전체가 완료되었을 때(onComplete)
- Observable을 구독할 때 함수 설정
- 자바에서 람다 표현식을 사용해서 코드 작성
obserable.getUsers()
.subscribe((List<User> users) -> {
// ...
}, (Throwable throwable) -> {
// ...
}, () -> {
// ...
});
- 코틀린에서 이름있는 아규먼트를 활용해서 의미를 더 명확하게 할 수 있음
obserable.getUsers()
.subscribeBy(
onNext = { users: List<User> ->
// ...
},
onError = { throwable: Throwable ->
// ...
},
onCompleted = {
// ...
}
)
정리
- 디폴트 값들을 생략할 때만 유용한 것은 아님
- 개발자가 코드를 읽을 때도 편리하게 활용
- 코드의 안정성 향상
- 함수에 같은 타입의 파라미터가 있는 경우에 활용하면 좋음
728x90
'코틀린 스터디 > 이펙티브 코틀린' 카테고리의 다른 글
아이템19) knowledge를 반복하여 사용하지 말라 (0) | 2024.04.17 |
---|---|
아이템18) 코딩 컨벤션을 지켜라 (0) | 2024.04.17 |
아이템16) 프로퍼티는 동작이 아니라 상태를 나타내야 한다 (0) | 2024.04.17 |
아이템15) 리시버를 명시적으로 참조하라 (0) | 2024.03.19 |
아이템14) 변수 타입이 명확하지 않은 경우 확실하게 지정하라 (0) | 2024.03.19 |