코틀린에서 자바 코드 사용 시 nullable과 non-nullable를 주의하자
개요
요즘 자바와 같은 JVM 언어인 코틀린을 공부하고 있습니다.
자바와 코틀린은 비슷한 점도 많지만 수많은 차이점도 존재하는데, 차이점 중 가장 흥미가 생긴 부분은 코틀린에서의 nullable과 non-nullable 타입이었습니다.
자바에서는 참조타입에 null을 자유롭게 담을 수 있지만, 코틀린은 null을 담을 수 있는 nullable 타입과 null을 담을 수 없는 non-nullable 타입을 완전히 다르게 취급합니다.
코틀린은 자바와 100% 호환 가능한 언어이기에 자바에서 코틀린으로 작성된 코드를 사용하거나, 코틀린에서 자바 코드를 사용할 수 있는데요.
nullable 타입과 non-nullable 타입을 다르게 간주하는 코틀린의 특성으로 코틀린에서 자바 코드를 사용할 때 주의할 점이 있어 이를 공유하고자 포스팅하게 되었습니다.
코틀린의 nullable과 non-nullable
개요에서 언급했다시피, 참조타입에 마음껏 null을 담을 수 있는 자바와 다르게 코틀린은 null을 담을 수 있는 nullable 타입과 null을 담을 수 없는 non-nullable 타입을 다르게 간주합니다.
그래서 코틀린에서 null을 포함할 수 있는 타입은 ?를 붙여서 표현하고, null을 포함할 수 없는 타입은 ? 없이 표현됩니다.
- String? : String 타입에 null 포함 가능 → nullable 타입
- String : String 타입에 null 포함 안됨 → non-nullable 타입
따라서 기본적으로 코틀린은 non-nullable 타입에 null이 전달될 여지가 있다면 컴파일 에러를 발생시킵니다.
따라서 코틀린은 nullable과 non-nullable 타입을 명확하게 구분하여 보다 안전한 코드를 작성할 수 있습니다.
코틀린 컴파일러는 자바 코드의 null 관련 어노테이션 정보를 이해한다.
코틀린에서 자바 클래스를 가져오는 예시를 살펴보겠습니다.
자바로 작성된 Person 클래스의 getName 메서드는 @Nullable 어노테이션을 사용해서 반환값이 null이 포함될 수 있음을 명시하고 있습니다. 즉, person.name은 null을 포함할 수 있습니다.
이어서 startWith_platform 함수는 매개변수가 String? 이 아닌 String으로 non-nullable 타입으로 선언되어 있습니다.
startWith_platform 함수 인자로 person의 name을 전달할 때 컴파일 에러가 발생하는데요.
이유는 Person의 name이 null일 여지가 있기 때문입니다.
반대로 getName 메서드의 @Notnull 어노테이션 적용하면 name에 null을 포함할 수 없기 때문에 컴파일 에러가 사라지게 됩니다.
이처럼 코틀린 코드에서 자바 코드를 가져왔을 때 null에 대한 어노테이션 정보를 코틀린이 이해하는 것을 알 수 있습니다.
자바 코드의 null 관련 어노테이션이 없다면 문제 발생
하지만 자바 코드에서 "null 관련 어노테이션이 없다면" 큰 문제가 발생하게 됩니다.
Person 클래스의 getName 메서드에 null 관련 어노테이션을 제거했습니다.
하지만 startWith_platform 함수 인자로 person의 name을 전달할 때 컴파일 에러가 전혀 발생하지 않았고,
결국 런타임 시점에 null이 전달되어 NPE가 발생했습니다!
실제로 코틀린 컴파일러는 자바 객체를 가져올 때 null 관련 어노테이션이 없다면 null에 대한 위험을 체크하지 않습니다.
문제점을 방지하기 위해서
이러한 문제점을 방지하기 위해서 아래와 같은 노력이 필요합니다.
- 기본적으로 코틀린에서 라이브러리를 포함한 자바 코드를 가져다 사용할 때, 해당 값이 null을 포함할 수 있는지 확인한다.
- 자바 라이브러리를 가져다 사용하는 지점을 래핑하서 단일 지점으로 만들고, 추후에 이슈가 있을 때 쉽게 대응할 수 있게 한다.
결론
코틀린에서 자바 객체를 가져올 때 null 관련해서 발생할 수 있는 문제점을 알아보았는데요.
앞으로도 코틀린을 공부하면서 자바와 함께 사용 시에 많은 주의사항들이 있겠지만,
코틀린의 특징을 잘 이해하고 활용한다면 자바와의 상호 운용성을 유지하면서도 안전하고 효율적인 코드를 작성할 수 있을 것 같습니다!