Let’s see how we can apply Joshua Bloch’s Effective Java in the Kotlin world. Today’s topic is Generics.
Item 26: Don’t use raw types
Kotlin doesn’t support raw types, and you always have to specify the type parameter.
However, to support interoperability, Kotlin converts Java’s raw types to star-projections. For example, Java’s List becomes Kotlin’s List<*>!, i.e. List<out Any?>!.
Item 27: Eliminate unchecked warnings
Kotlin provides reified type parameters for inline functions to allow accessing type information.
Item 28: Prefer lists to arrays
Unlike Java, Kotlin’s arrays are represented by a generic class, Array. However, we should still prefer lists, especially if we want to ensure immutability.
Also note that Kotlin provides specialized classes for primitive arrays, e.g. IntArray, DoubleArray, etc., to avoid the cost of boxing / unboxing.
Item 29: Favor generic types
There is nothing special in Kotlin about this item.
Item 30: Favor generic methods
There is nothing special in Kotlin about this item.
Item 31: Use bounded wildcards to increase API flexibility
Kotlin doesn’t support wildcards, and Java’s wildcards are converted into type projections. Therefore, instead of producer-extends, consumer-super (PECS), we now have Consumer in, Producer out.
For example, Java’s Foo<? extends Bar> becomes Foo<out Bar!>!, and Foo<? super Bar> becomes Foo<in Bar!>!.
Item 32: Combine generics and varargs judiciously
Kotlin is using the generic class Array for varargs, where a vararg parameter of type T is effectively Array<out T>. Therefore, we don’t have many of the problems as in Java.
When passing a Kotlin array to a Java’s vararg function, we need to use the spread operator *, e.g.:
// Java
public class JavaClass {
public void function(int... args) {
...
}
}
// Kotlin
val javaObj = JavaClass()
javaObj.function(1, 2, 3) // more efficient
javaObj.function(*intArrayOf(1, 2, 3))Item 33: Consider typesafe heterogeneous containers
There is nothing special in Kotlin about this item.