Platform Types in Kotlin

Categories:
4 minute read
Platform types are a crucial concept in Kotlin’s type system, particularly when dealing with Java interoperability. They represent types coming from Java code whose nullability is unknown. This comprehensive guide explores platform types, their behavior, and best practices for handling them effectively.
Understanding Platform Types
What are Platform Types?
Platform types are Kotlin’s way of handling Java types that don’t have explicit nullability information. They’re represented in error messages and documentation using an exclamation mark (!).
// Java class
public class JavaClass {
public String getText() {
return "Hello";
}
}
// Kotlin usage
val javaClass = JavaClass()
val text = javaClass.text // Type is String!, a platform type
Platform Type Behavior
Flexible Nullability
Platform types can be treated as both nullable and non-nullable:
class PlatformTypeExample {
private val javaClass = JavaClass()
fun demonstrateFlexibility() {
// Treating as non-null
val nonNullText: String = javaClass.text
// Treating as nullable
val nullableText: String? = javaClass.text
// Both compilations succeed
}
}
Potential Runtime Issues
Platform types can lead to runtime errors if not handled carefully:
class PlatformTypeRisks {
fun processJavaString(javaString: String!) { // Platform type parameter
// This might throw NPE if Java code returns null
val length = javaString.length
// Safer approach
val safeLength = javaString?.length ?: 0
}
}
Working with Platform Types
Defensive Programming
It’s important to handle platform types defensively:
class SafePlatformTypeHandling {
private val javaClass = JavaClass()
fun safeProcessing() {
// Defensive approach using safe call
val length = javaClass.text?.length
// Defensive approach using Elvis operator
val nonNullLength = javaClass.text?.length ?: 0
// Defensive approach with explicit null check
val text = javaClass.text
if (text != null) {
println(text.length)
}
}
}
Type Inference with Platform Types
Understanding how Kotlin infers types from platform types:
class TypeInferenceExample {
private val javaClass = JavaClass()
fun demonstrateInference() {
// Type inference with platform types
val inferred = javaClass.text // Type inferred as String!
// Explicit type declaration recommended
val explicit: String? = javaClass.text // Clearly nullable
val nonNull: String = javaClass.text // Clearly non-null
}
}
Collections and Platform Types
Handling Java Collections
Working with collections from Java requires special attention:
// Java class
public class JavaCollections {
public List<String> getItems() {
return Arrays.asList("one", "two", null);
}
}
// Kotlin handling
class CollectionHandler {
private val javaCollections = JavaCollections()
fun handleCollections() {
// Platform type collection
val items = javaCollections.items // List<String!>
// Safer approach with explicit nullability
val nullableItems: List<String?> = javaCollections.items
// Process safely
nullableItems.forEach { item ->
println(item?.length ?: 0)
}
}
}
Best Practices
1. Explicit Nullability
Always declare explicit nullability when storing platform types:
class BestPractices {
// Bad: Implicit platform type
private val javaString = getJavaString()
// Good: Explicit nullability
private val nullableString: String? = getJavaString()
private val nonNullString: String = getJavaString()
?: throw IllegalStateException("String cannot be null")
}
2. Boundary Protection
Create protective boundaries around platform types:
class BoundaryProtection {
private val javaClass = JavaClass()
// Protect internal code from platform types
fun getProtectedText(): String {
return javaClass.text ?: ""
}
// Handle nullable case explicitly
fun getOptionalText(): String? {
return javaClass.text
}
}
3. Collection Safety
Handle collection platform types carefully:
class CollectionSafety {
private val javaCollections = JavaCollections()
fun getSafeList(): List<String> {
return javaCollections.items.filterNotNull()
}
fun getSafeNullableList(): List<String?> {
return javaCollections.items
}
}
Advanced Platform Type Scenarios
Generic Types
Handling generic platform types requires extra care:
class GenericPlatformTypes {
// Java method returning Generic<String>
fun processGeneric(javaGeneric: Generic<String!>!) {
// Handle both container and content nullability
javaGeneric?.content?.let { content ->
println(content.length)
}
}
}
Function Types
Platform types in function parameters and returns:
class FunctionPlatformTypes {
// Java method returning Function1<String, String>
fun processFunction(javaFunction: ((String!) -> String!)?) {
// Safe handling of nullable function
javaFunction?.let { fn ->
val result = fn("input")
println(result.length) // Still need to be careful with result
}
}
}
Tips for Platform Type Safety
1. Documentation
Document platform type assumptions:
class DocumentedPlatformTypes {
/**
* Processes text from Java API.
* @param text Platform type from Java, assumed non-null
* @throws IllegalArgumentException if text is null
*/
fun processText(text: String!) {
requireNotNull(text) { "Text must not be null" }
println(text.length)
}
}
2. Testing
Test platform type boundaries thoroughly:
class PlatformTypeTests {
@Test
fun `test platform type handling`() {
val javaClass = JavaClass()
// Test null case
assertDoesNotThrow {
processPlatformType(javaClass.text)
}
// Test non-null case
val result = processPlatformType(javaClass.text)
assertNotNull(result)
}
}
Conclusion
Platform types are a necessary bridge between Java’s type system and Kotlin’s null safety features. Key points to remember:
- Always handle platform types defensively
- Use explicit nullability declarations when storing platform types
- Create protective boundaries around platform type usage
- Take extra care with collections and generic types
- Document assumptions about platform types
- Test thoroughly, especially null cases
By following these guidelines and understanding platform type behavior, you can write safer and more maintainable code when working with Java interoperability in Kotlin.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.