4장 - 옵셔널에서 널이 될 수 있는 타입으로

4장 - 옵셔널에서 널이 될 수 있는 타입으로를 정리한 내용입니다.

널 참조 발명을 실수라고 생각할 수도 있지만 소프트웨어 시스템에서는 무언가가 없다는 사실을 기술해야 할 필요가 있다.

없음을 표현하기

  • 널 가능성은 코틀린에서 가장 매력적인 기능이다.

  • 이전 자바에서는 @Nullable @NotNullable 어노테이션의 도움을 받았고, 8부터는 Optional 타입을 사용한다.

  • 코틀린은 널을 포용하지만 자바와의 호환성을 유지하기 위해 일관된 형태로 완벽하게 처리하지는 않는다.

  • Map.get()은 값이 없을때 null을 리턴하지만 List.get(), Iterable.first()는 Exception을 던진다.

  • 코틀린에서는 래퍼 타입인 Optional을 사용하는 대신 언어에서 제공하는 널 가능성을 사용하는 편이 좋다.

  • 코틀린 타입 시스템에서 T는 T?의 하위 타입이지만 T는 Optional<T>의 하위 타입이 아니다.

  • 널 가능성 사용시 String과 String? 관계에서 String?을 String으로 바꿔도 클라이언트 코드가 깨지지 않는다.

  • String과 Optional<String>은 위의 변경시 클라이언트 코드가 깨지게 되어 변경이 쉽지 않다.

옵셔널에서 널 가능성으로 리팩터링하기

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;
    }
}
  • Legs와 LongestLegOverTests 자바 코드를 툴을 사용해 코틀린으로 변환한다.

object Legs {

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

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

이터레이션과 for 루프

코틀린에서는 Iterable이 아닌 타입을 for 루프에 사용할 수 있다.

  • Iterable를 확장한 타입

  • Iterator를 반환하는 iterator() 메서드를 제공하는 타입 (hasNext(): Boolean, next(): T 제공)

  • Iterator를 반환하는 T.iterator() 확장 함수가 영역 안에 정의된 T 타입

두번째, 세번째는 Iterable 취급을 해주진 않아 map, reduce 확장 함수를 사용할 수는 없다.

코틀린다운 코드로 리팩터링하기

다음으로 나아가기

Last updated