튼튼발자 개발 성장기🏋️

Java Optional to Kotlin Nullable Type 본문

프로그래밍/Kotlin

Java Optional to Kotlin Nullable Type

시뻘건 튼튼발자 2025. 6. 4. 19:43
반응형
자바에서 코틀린으로 포팅하면서 고려해야할 리팰토링 중 [Optional]부문에 대해서 설명한다.
백문이 불여일견이라고 직접 실습을 통해 차근차근 설명하겠다.

 

public class Legs {

    public static Optional<Leg> findLongestLegOver(
        List<Leg> legs,
        Duration duration
    ) {
        Leg result = null;
        for (Leg leg : legs) {
            if (isLongerThan(leg, duration))
                if (result == null ||
                    isLongerThan(leg, result.getPlannedDuration())
                ) {
                    result = leg;
                }
        }
        return Optional.ofNullable(result);
    }

    private static boolean isLongerThan(Leg leg, Duration duration) {
        return leg.getPlannedDuration().compareTo(duration) > 0;
    }
}

 

자바 코드를 단순히 코틀린으로 포팅하면 아래와 같다.

object Legs {
    fun longestLegOver(
        legs: List<Leg>,
        duration: Duration
    ): Leg? {
        var result: Leg? = null
        for (leg in legs) {
            if (isLongerThan(leg, duration))
                if (result == null ||
                    isLongerThan(leg, result.plannedDuration))
                    result = leg
        }
        return result
    }

    private fun isLongerThan(leg: Leg, duration: Duration): Boolean {
        return leg.plannedDuration.compareTo(duration) > 0
    }
}

원래 자바 메서드가 정적 메서드였기 때문에 이 함수들이 들어갈 무언가가 필요해서 object에 넣었다. 사실 코틀린은 이러한 추가적인 네임스페이스가 불필요하지만 지금은 이해를 돕기 위해 이렇게 하겠다. 이 코드를 한 층 더 개선한다면 Move to top level을 적용하면 된다. 추가로 isLongerThan()메서드에서 단일식 함수 구문을 사용하였으며 코틀린의 자랑인 확장함수를 사용했다.

fun longestLegOver(
    legs: List<Leg>,
    duration: Duration
): Leg? {
    var result: Leg? = null
    for (leg in legs) {
        if (leg.isLongerThan(duration))
            if (result == null ||
                leg.isLongerThan(result.plannedDuration))
                result = leg
    }
    return result
}

private fun Leg.isLongerThan(duration: Duration) =
    plannedDuration.compareTo(duration) > 0

 

이제 로직을 리팩토링해보자.

longestLegOver 함수는 가장 긴 구간을 찾고 그 구간이 주어진 기간보다 길다면 그 값을 반환하고 그렇지 않으면 null을 반환한다.

가장 긴 구간은 legs.maxByOrNull 함수로 대체할 수 있다.

fun longestLegOver(
    legs: List<Leg>,
    duration: Duration
): Leg? {
    val longestLeg: Leg? = legs.maxByOrNull(Leg::plannedDuration)
    return if (longestLeg != null && longestLeg.plannedDuration > duration)
        longestLeg
    else
        null
}

 

여기서 또 한 층 개선한다면 엘비스 연산자 혹은 ?.let식, when식, takeIf을 사용할 수도 있다.

(takeIf는 술어가 true이면 수신 객체를 리턴하고 false이면 null을 리턴한다.)

// 엘비스 연산자
fun longestLegOver(
    legs: List<Leg>,
    duration: Duration
): Leg? {
    val longestLeg = legs.maxByOrNull(Leg::plannedDuration) ?:
        return null
    return if (longestLeg.plannedDuration > duration)
        longestLeg
    else
        null
}

// ?.let식
fun longestLegOver(
    legs: List<Leg>,
    duration: Duration
): Leg? =
    legs.maxByOrNull(Leg::plannedDuration)?.let { longestLeg ->
        if (longestLeg.plannedDuration > duration)
            longestLeg
        else
            null
    }
    
// when식
fun longestLegOver(
    legs: List<Leg>,
    duration: Duration
): Leg? {
    val longestLeg = legs.maxByOrNull(Leg::plannedDuration)
    return when {
        longestLeg == null -> null
        longestLeg.plannedDuration > duration -> longestLeg
        else -> null
    }
}

// takeIf
fun longestLegOver(
    legs: List<Leg>,
    duration: Duration
): Leg? =
    legs.maxByOrNull(Leg::plannedDuration)?.takeIf { longestLeg ->
        longestLeg.plannedDuration > duration
    }
반응형

'프로그래밍 > Kotlin' 카테고리의 다른 글

Java Collections to Kotlin Collections  (1) 2025.06.15
Java Bean to Kotlin Value  (1) 2025.06.14
Java Class to Kotlin Class  (0) 2025.06.04
[Kotlin] 리스트  (1) 2024.12.08
[Kotlin] 재귀와 공재귀  (0) 2024.12.07