What is a Kotlin platform type, why does it show up as String! in the IDE, and what happens to null checking when you use one?
answer
- Java value -> platform type
- Shown as String! (tooling only, not writable)
- Null checks relaxed at the boundary
- NPE happens at use, not at crossing
- Pin contract with explicit String? type
basics
~20 sA platform type is a value coming from Java whose nullability Kotlin can't know. The compiler relaxes null checks for it. If you treat it as non-null but it's actually null, you get a NullPointerException at runtime.
solid answer
~40 sJava has no built-in nullability info, so when a Java method returns a value Kotlin assigns it a platform type, written String! in IDE tooling (the ! is not real syntax you can type). For platform types the compiler suspends strict null-safety: you may assign the value to a non-null String or a nullable String?, and you may call members without ?. The trade-off is that the safety net is gone — if the Java value is actually null and you used it as non-null, you get a NullPointerException where you dereference it, not at the boundary. Best practice: decide the contract at the boundary by explicitly typing the variable (val s: String? = javaObj.getName()) so the compiler enforces a null check, rather than letting the platform type silently flow as non-null.
code
kotlin · 12 lines// Java side:
// public class User { public String getName() { return null; } }
val user = User()
val name = user.name // type is String! (platform type)
// Treated as non-null -> NPE at runtime when actually null:
// val len = name.length
// Pin it explicitly to force compiler null-safety:
val safeName: String? = user.name
println(safeName?.length) // null, no crashgo deeper
Knows a platform type comes from Java and that mishandling it can throw an NPE.
Explains the relaxed-check trade-off and pins the contract with an explicit nullable type at the boundary.
Discusses where the NPE actually surfaces and why Kotlin chose this pragmatic compromise over forcing nullable everywhere.
Frames boundary discipline as an API-design and team-convention concern, e.g. wrapping noisy Java APIs in null-safe Kotlin facades.
## What a platform type is Kotlin's type system tracks nullability: `String` can never be null, `String?` can. **Java** has no such distinction at the language level — any reference can be null. When a value crosses from Java into Kotlin, the compiler often cannot prove whether null is possible, so it assigns a **platform type**. ## The `String!` notation In IDE hovers, error messages, and docs the platform type is written `String!`, meaning "`String` or `String?`, the compiler doesn't know". **`!` is not syntax you can write** — it only appears in tooling. You can't declare `val x: String!`. ## Relaxed null checks For a platform type the compiler **lifts** its usual rules: - You may assign it to a **non-null** type (`val s: String = javaObj.name`) — no error. - You may assign it to a **nullable** type (`val s: String? = javaObj.name`). - You may **dereference it directly** (`javaObj.name.length`) with no `?.` or `!!`. ## Where the NPE happens If the Java value is actually `null` and you treated the platform type as non-null, the failure is a **NullPointerException at the point of use** (the dereference), not at the boundary crossing. This makes platform-type bugs feel "late" and far from the cause. ```kotlin // Java: String getName() { return null; } val name = javaObj.name // platform type String! println(name.length) // NPE here at runtime if name is null // Safer: pin the contract at the boundary val safe: String? = javaObj.name // now compiler forces a null check println(safe?.length) // prints null, no crash ``` ## Takeaway Platform types are a **pragmatic compromise**: full strictness would make every Java call require `!!` or `?.`. Instead Kotlin trusts you at the boundary and asks you to **assign an explicit nullable/non-null type** when you know the real contract. The keywords involved are the safe-call `?.`, the not-null assertion `!!`, and explicit type annotations.
- Can you write the type String! yourself in Kotlin source?No. The ! suffix is only a tooling/diagnostic notation. You declare String or String?; the platform type exists only implicitly for unannotated Java values.
- Why doesn't Kotlin just treat every Java return as nullable?That would force ?. or !! on essentially every Java call, making interop unbearably noisy. Platform types are the pragmatic middle ground.
It's an unlabeled package from a vendor who never marks 'fragile' — Kotlin lets you carry it however you like, but drops it (NPE) if it really was fragile.
saying these in an interview costs you the question
- Claiming Kotlin throws at the boundary when the Java value is null (it throws at use)
- Saying you can declare a variable of type String!
- Thinking platform types are always non-null
- Believing platform types disable null safety for the whole program rather than just that value