코틀린에서는 함수에서 추출한 함수를 원 함수 내부에 중첩시킬 수 있다. 이를 이용해 코드 중복을 제거할 수 있다.
예를 들어 아래 코드에서 user의 name과 address 필드 값을 검증할 때 비슷한 코드가 사용되고 있다.
class User(val id: Int, val name: String, val address: String)
fun saveUser(user: User) {
if (user.name.isEmpty()) {
throw IllegalArgumentException(
"Can't save user ${user.id}: empty Name"
)
}
if (user.address.isEmpty()) {
throw IllegalArgumentException(
"Can't save user ${user.id}: empty Address"
)
}
// user를 데이터베이스에 저장
}
검증 코드를 로컬 함수로 분리하면 중복을 없앨 수 있다.
fun saveUser(user: User) {
fun validate(user: User, value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException(
"Can't save user ${user.id}: empty $fieldName"
)
}
validate(user, user.name, "Name")
validate(user, user.address, "Address")
}
// user를 데이터베이스에 저장
}
로컬 함수는 자신이 속한 바깥 함수의 모든 파라미터와 변수를 사용할 수 있다. 이런 성징을 이용해 불필요한 User 파라미터를 없앨 수 있다.
fun saveUser(user: User) {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException(
"Can't save user ${user.id}: empty $fieldName"
)
}
validate(user.name, "Name")
validate(user.address, "Address")
}
// user를 데이터베이스에 저장
}
중첩된 함수의 깊이가 깊어지면 코드를 읽기가 상당히 어려워진다. 따라서 일반적으로는 한 단계만 함수를 중첩시키라고 권장한다.