코틀린 스터디/이펙티브 코틀린

아이템3) 최대한 플랫폼 타입을 사용하지 말라

막이86 2024. 2. 7. 14:01
728x90

이펙티브 코루틴을 요약한 내용입니다.

  • null-safety는 코틀린의 주요 기능 중 하나
    • 자바에서 String 타입을 리턴하는 메서드의 경우 nullable로 처리 해야할까?
    • @Nullable 어노테이션이 있다면 nullable로 추정
    • @NotNull 어노테이션이 있다면 String 으로 변경
    • 어노테이션이 없다면 nullable로 가정하고 다루는 것이 좋음
    • not-null을 단정할 수 있다면 !!를 사용
  • nullable과 관련하여 자주 문제가 되는 부분은 자바의 제네릭 타입
    • List<User>를 리턴하는 경우 리스트와 리스트 내부의 User 객체들이 널이 아닌 것을 알아야 함
    public class UserRepo {
    	public List<User> getUsers() {
    
    	}
    }
    
    val users: List<User> = UserRepo().users!!.filterNotNull()
    
    • List<List<User>> 처리의 경우 좀더 복잡해짐
    val users: List<List<User>> = UserRepo().groupedUsers.map { it!!.filterNotNull() }
    
  • 코틀린은 자바 등의 다른 프로그래밍 언어에서 넘어온 타입들을 플랫폼 타입이라고 부름
    • null 가능성이 있으므로 위험한 코드
    public class UserRepo {
    	public User getUser() {
    
    	}
    }
    
    val repo = UserRepo()
    val user1 = repo.user          // User!
    val user2: User = repo.user    // User
    val user3: User? = repo.user   // User?
    
  • 자바를 코틀린과 함께 사용할 때, 가능한 @Nullable과 @NotNull 어노테이션을 붙여서 사용
  • import org.jetbrains.annotations.NotNull public class UserRepo { public @NotNull User getUser() { } }
  • 다양한 어노테이션이 지원되고 있음
    • JSR 305의 @ParametersAreNonnullByDefault 어노테이션 등을 활용하여 자바에서도 디폴트로 파라미터가 널이 아니라는 것을 보장할 수 있음
  • statedType과 platformType의 동작을 살펴보기
    • statedType에서는 자바에서 값을 가져오는 위치에서 NPE가 발생
    • platformType에서는 값을 활용할 때 NPE가 발생
      • NPE가 발생될 거라고 생각하지 않으므로 오류를 찾는데 오랜시간이 걸리게 될 것
    public clas JavaClass {
    	public String getValue() {
    		return null;
    	}
    }
    
    fun statedType() {
    	val value: String = JavaClass().value
    	println(value.length)
    }
    
    fun platformType() {
    	val value = JavaClass().value
    	println(value.length)
    }
    
  • 인터페이스에서 플랫폼 타입을 사용하는 경우
    • 메서드의 inferred 타입이 플랫폼 타입
    interface UserRepo {
    	fun getuserName() = JavaClass().value
    }
    
    class RepoImpl: UserRepo {
    	override fun getUserName(): String? {
    		return null
    	}
    }
    
    fun main() {
    	val repo: UserRepo = RepoImpl()
    	val text: String = repo.getUserName()          // 런타임 때 NPE
    	print("UserName length is ${text.length}")
    }
    
  • 플랫폼 타입이 전파되는 일은 굉장히 위험
    • 위험성을 내포하고 있기 때문에

정리

  • 다른 프로그래밍 언어에서 와서 nullable여부를 알수 없는 타입을 플랫폼 타입이라고 함
  • 플랫폼 타입은 사용하는 코드는 해당 부분만 위험할 뿐만 아니라 활용하는 곳까지 영향을 줄 수 있음
  • 자바 생성자, 메서드, 필드에 nullable 여부를 지정하는 어노테이션을 활용하는 것도 좋음
728x90