개발자가 코드를 작성하는 데는 1분 걸리지만, 이를 읽는 데는 10분이 걸린다.
// 구현 A
if (person != null && person.isAdult) {
view.showPerson(person)
} else {
view.showError()
}
// 구현 B
person?.takeIf { it.isAdult }
?.let(view::showPerson)
?: view.showError()
if/else
)를 사용한 A가 더 읽기 쉬울 것이다.if/else
블록이 코드를 수정하고 리팩터링하기도 쉽다.
if/else
블록 내부에 코드를 추가하면 된다.// 구현 A
if (person != null && person.isAdult) {
view.showPerson(person)
view.hideProgressWithSuccess()
} else {
view.showError()
view.hideProgress()
}
// 구현 B
person?.takeIf { it.isAdult }
?.let {
view.showPerson(person)
view.hideProgressWithSuccess()
} ?: run {
view.showError()
view.hideProgress()
}
let
은 람다식 결과를 리턴하기에 showPerson
이 null
을 리턴하면 showError
도 호출하게 된다.let
은 절대 쓰지 말자는 결론을 내선 안 된다.let
은 좋은 코드에서 다양하게 활용되는 관용구다.
let
을 통해 해결할 수 있다.class Person(val name: String)
var person: Person? = null
person?.let {
print(it.name)
}
let
은 다음 경우도 많이 사용한다.
students
.filter { itresult >= 50 }
.joinToString(separator = "\n") {
"${it.name} ${it.surname}, ${it.result}"
}
.let(::print)
var obj = FileInputStream("/file.gz")
.let(::BufferedInputStream)
.let(::ZipInputStream)
.let(::ObjectInputStream)
.readObject() as SomeObject
val abc = "A" { "B" } and "C"
print(abc) // ABC
operator fun String.invoke(f: () -> String): String =
this + f()
infix fun String.add(s: String) = this + s
invoke
를 이런 형태로 사용하면 안 된다.add
라는 함수 이름이 실제 함수 내부에서 이루어지는 처리와 맞지 않는다.