-
아이템3 - 최대한 플랫폼 타입을 사용하지 말라Kotlin/Effective Kotlin 요약 2022. 12. 31. 00:01728x90
개요
코틀린에서 null-safety는 주요 기능 중 하나입니다.
만약 자바에서 String 타입을 리턴하는 메서드가 존재하고 코틀린에서 이를 사용하려면 어떻게 해야 할까요?
@Nullable, @NotNull 어노테이션이 붙어있다면 해당 프로퍼티에 맞게 변환해주면 됩니다.
하지만 어노테이션이 붙어있지 않는다면 안전하게 nullable으로 가정해야 합니다.
하지만 어떤 메서드는 null을 리턴하지 않을 것이 확실할 수 있습니다.
이런 경우에는 not-null을 나타내는 !!를 붙입니다.
이때 자주 문제가 되는 부분이 자바의 제네릭 타입입니다.
코틀린과 자바의 제네릭 타입
코틀린이 디폴트로 모든 타입을 nullable로 다룬다면, 리스트 자체만 널 인지 확인해서는 안 되고, 그 내부에 있는 것들도 널 인지 확인해야 합니다.
//자바 public class UserRepo{ public List<User> getUsers(){ } } //코틀린 fun main() { val users: List<User> = UserRepo.users!!.filterNotNull() }
조금 더 나아가서 List<List<User>>를 반환한다면?
val users: List<List<User>> = UserRepo.groupedUsers!!.map {it!!.filterNotNull()}
리스트는 적어도 map와 filterNotNull 등의 메서드를 제공하지만 다른 제네릭 타입이라면 null을 확인하는 것 자체가 복잡한 일이 됩니다.
플랫폼 타입
코틀린은 자바 등의 다른 프로그래밍 언어에서 넘어온 타입들을 플랫폼 타입이라고 부릅니다.
String! 처럼 이름 뒤에 ! 기호를 붙여서 표기합니다.
직접적인 코드에는 나타나지 않지만 이를 선택적으로 사용합니다.
val repo = UserRepo() val user1 = repo.user //user1의 타입은 User! val user2: User = repo.user //user2의 타입은 User val user3: User? = repo.user //user3의 타입은 User?
하지만 null이 아니라고 생각되는 것이 null일 가능성이 존재하여 여전히 위협적입니다.
따라서 자바를 코틀린과 함께 사용할 때, 자바 코드를 직접 조작할 수 있다면 가능한 @Nullable, @NotNull 어노테이션을 붙여서 사용하기 권장됩니다.
statedType VS platformType
//자바 public class JavaClass{ public String getValue(){ return null; } } //코틀린 fun statedType(){ val value: String = JavaClass().value //NPE println(value.length) } fun platformType(){ val value = JavaClass().value println(value.length) //NPE }
두 가지 모두 NPE가 발생합니다.
statedType에서는 자바에서 값을 가져오는 위치에서 NPE가 발생합니다.
따라서 코드를 굉장히 쉽게 수정할 수 있습니다.
platformType에서는 값을 활용할 때 NPE가 발생합니다.
따라서 오류를 찾는데 더 오랜 시간이 걸릴 수 있습니다.
플랫폼 타입의 더 많은 위험성
인터페이스에서 플랫폼 타입을 사용하고 있습니다.
interface UserRepo{ fun getUserName() = JavaClass().value }
이런 경우 메서드의 inferred 타입이 플랫폼 타입이며 누구나 nullable을 지정할 수 있게 됩니다.
어떤 사람이 상속을 받아 nullable을 리턴하게 됐는데, 사용하는 사람이 nullable이 아닐 거라고 받아들였다면 문제가 발생합니다.
class RepoImpl: UserRepo{ override fun getUserName(): Stirng?{ return null } } fun main(){ val repo: UserRepo = RepoImpl() val text: STring = repo.getUserName() //Runtime 시 NPE }
다행히 인텔리제이에서는 경고를 출력해줍니다.
정리
다른 프로그래밍 언어에서 nullable 여부를 알 수 없는 타입을 플랫폼 타입이라고 합니다.
이런 플랫폼 타입은 해당 코드뿐만 아니라 활용하는 곳까지 영향을 줄 수 있는 위험한 코드입니다.
따라서 이런 플랫폼 타입을 활용하기 보다는 @NotNull, @Nullable 어노테이션을 활용하는 것이 권장됩니다.
'Kotlin > Effective Kotlin 요약' 카테고리의 다른 글
6장 - 사용자 정의 오류보다는 표준 오류를 사용하라 (0) 2023.01.21 아이템5 - 예외를 활용해 코드에 제한을 걸어라 (0) 2023.01.04 아이템4 - inferred 타입으로 리턴하지 말라 (0) 2023.01.03 아이템2 - 변수의 스코프를 최소화하라 (0) 2022.12.29 아이템1 - 가변성을 제한하라 (0) 2022.12.26