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

자바는 코틀린과 달리 null-safety 메커니즘이 없다. 따라서 자바의 String 타입을 코틀린에서 사용할때 `@Nullable` 어노테이션이 붙어 있으면 String? 타입으로, `@NotNull` 어노테이션이 붙어있으면 String 타입으로 변경하면 된다.

하지만 아무런 어노테이션이 없다면 체크가 까다롭다. 그래서 코틀린에서는 다른 언어에서 넘어온 타입을 특수하게 다루는데 이러한 타입을 **플랫폼 타입(platform type)** 이라고 한다. 플랫폼 타입은 String!처럼 타입 뒤에 !를 붙여서 표기한다.

```kotlin
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` 어노테이션을 붙이는 것이 좋다.

또한 플랫폼 타입은 최대한 빠르게 제거하는 것이 좋다.

```kotlin
// 자바
public class JavaClass {
  public String getValue() {
    return null;
  }
}

// 코틀린
fun statedType() {
  val value: String = JavaClass().value // 타입 명시 -> NPE
  print(value.length)
}

fun platformType() {
  val value = JavaClass().value // 타입 명시 x
  print(value.length) // NPE
}
```

`statedType()` 에선 값을 가져오는 위치에서 NPE가 발생하지만 `platformType()` 에선 사용하는 위치에서 NPE가 발생한다. 이 경우 여러번 호출 되면서 문제가 되지 않는 경우도 있기 때문에 오류를 추적하는데 시간이 오래 걸린다.

또한 인터페이스의 경우 구현하는 클래스에서 null 여부를 지정할 수 있기 때문에 문제가 될 수 있다.

```kotlin
interface UserRepo {
  fun getUserName() = JavaClass().value
}

class RepoImpl: UserRepo {
  override fun getUserName(): String? {
    return null
  }
}
```

이 경우 사용하는 사람이 null이 아닐거라고 받아들일 수 있기 때문에 문제가 될 수 있다. 이처럼 플랫폼 타입이 전파되는 것은 위험하기 때문에 제거하는 것이 좋다.

## 정리

* 다른 프로그래밍 언어로 구현되어 null 여부를 알 수 없는 타입을 **플랫폼 타입**이라고 한다.
* 플랫폼 타입은 해당 부분 뿐만 아니라 이를 활용하는 부분도 문제가 될 수 있기 때문에 제거하는 것이 좋다.
