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.