Kotlin/Kotlin

Kotlin takeIf와 takeUnless 함수

Junuuu 2024. 3. 13. 00:01

개요

Kotlin에서 takeIf()와 takeUnless() 함수를 제공한다는 사실을 알게 되었고, 해당 함수들에 대해서 알아보고자 합니다.

 

takeIf 함수

public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (predicate(this)) this else null
}

takeIf 함수는 T (어떤 객체)의 확장함수입니다.

predicate를 인자로 받아서 조건에 만족하는경우 자기 자신을 반환하거나 null을 반환합니다.

 

takeUnless 함수

public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (!predicate(this)) this else null
}

takeIf 함수와 굉장히 유사하지만 return 구문의 ! 부정문이 들어가 있어서 takeIf와 반대로 동작합니다.

 

 

직접 호출해보며 takeIf, takeUnless 함수 이해해 보기

@Test
fun `takeIf, takeUnless 메서드 사용하기`(){
	val simpleNumber = 3
	println(simpleNumber.takeIf { true })	// 3
	println(simpleNumber.takeUnless { true }) // null
}

결과는 3과 null이 나오게 됩니다.

즉, Predicate 구문에 따라 T 객체를 반환할 건지 null을 반환할건지 결정됩니다.

 

 

언제 사용하면 좋을까?

// 원본 코드
if (status) { doThis() }
// 수정 된 코드
takeIf { status }?.apply { doThis() }

무작정 takeIf를 활용한다고 하면 오히려 가독성이 떨어질 수 있습니다.

 

takeIf, takeUnless 함수가 Predicate에 따라 null을 반환하기 때문에 null을 다루는 코드에 사용하면 좋을 것 같습니다.

 

예시) null을 다루는 코드에 takeIf, takeUnless 적용하기

@Test
fun `takeIf, takeUnless 적합한 상황은 언제일까`(){
	val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
	val evenNumbers = numbers.filter { it % 2 == 0 }
	val oddNumbers = numbers.filterNot { it % 2 == 0 }

	val evenNumbers2 = numbers.mapNotNull { it.takeIf { number -> number % 2 == 0 } }
	val oddNumbers2 = numbers.mapNotNull { it.takeUnless { number -> number % 2 == 0 } }
}

홀수와 짝수를 구분하는 상황에서 filter를 활용하는 것도 좋은 예시입니다.

하지만 mapNotNull을 활용하는 경우라면 takeIf, takeUnless도 활용해 볼 수 있습니다.

 

 

 

참고자료

https://kotlinlang.org/docs/scope-functions.html#takeif-and-takeunless