※Notes記事では、英語のセッション動画やポッドキャストの内容を(雑に)英語でメモに書き残すことを行っています。 本記事は、あくまで動画を見ながら、参考程度に読んでいただくことを想定しています。これから動画を見る方にとって本記事の内容が少しでもお役に立てば幸いです。(内容において不備、誤字脱字等ありましたらご連絡いただければと思います。)
本記事はKotlin Types: Exposed by Svetlana Isakova (KotlinConf 2017)の記事です。
Agenda
- Basic Types
- Nullable types
- Collection types
How those types interact with Java and what happens when we mix types of Kotlin and Java
fun foo(): Int = 1 fun bar(): Int? = 1
public static final int foo() { return 1; } public static final Integer bar() { return Integer.of(1); }
If you want to know what is going on under the food, you can "show kotlin bytecode" (and also decompile the byte code) in Android Studio
Correspondence between Kotlin and Java types
Kotlin does not have Primitive types in the language, yet Kotlin still has Primitive types in the byte code level by making use of wrapper types and nullable types
Generic arguments
Arrays of primiteve types
If you want to use primitive types of array, then use IntArray
in Kotlin:
- IntArray
in Kotlin => int[]
in Java
String
kotlin.String
in Kotlin => java.lang.String
in Java
kotlin.String
hides some confusing methods:
e.g. replaceAll
method
In Java:
"one.two.".replaceAll(".", "*") => *******
In Kotlin:
"one.two.".replace(".", "*") => one*two "one.two.".replace(".".toRegex(), "*") => one*two
Any
Any
in Kotlin =>java.lang.Object
in JavaAny
type is the super type for ALL types, includingInt
or anything
Boxing under the hood
log(2017) // the value is autoboxed fun log(any: Any) { println("Value: $any") } fun log(i: Int) { println("Value: $i") }
Unit
(Kotlin) vs Nothing
(Kotlin) vs void
(Java)?
The concept comes from functional programming; from the Type
system
- Unit: "a type that allows only one value and thus can hold no information" => The function completes
- Nothing: "a type that has no values" => The function never completes
Unit
instead of void
Whenever you use void
in Java, you use Unit
in Kotlin
Unit
- No meaningful value is returned
- No explicit returned type implies you return
Unit
by default - Two equivalent syntactic forms:
fun f() { /*…*/ } fun f(): Unit { /*…*/ }
Under the hood, Unit
is still void
in the byte code
Nothing
is different to Unit/void
Unit
and Nothing
are two very different types even though in the byte code level both mean void
type
Nothing
means "this function never returns"
Any & Nothing types
Any
is a super type for all the other typesNothing
is a subtype for all the other types
e.g. fail
function below returns Unit
val answer = if (timeHasPassed()) { 42 } else { fail("Not ready") } fun fail(message: String) { throw IllegalStateException(message) }
- If 42 is returned then the returned type of the expression function is
Int
- If fail function is called then the returned type of the expression function is
Unit
=> Kotlin compiler thinks that the expression function returns Any
type because the super type of both Int
and Unit
is Any
Returning Any
means the variable answer
will be initialized even if it fail
s, which is not what we expect; we expect it not to be initialized when it fails. => We can use Nothing
in this case
Nothing
is a subtype for all the other types, so that means the returned type of the expression function is now Int
, which is what we expect
Type of null
var user = null // => var user: Nothing? = null user = User("svtk") // Error: Type mismatch val users = mutableListOf(null) // => var users: List<Nothing?> = mutableListOf(null) users.add(User("svtk")) // Error: Type mismatch
Nullable types & Java
Nullable Types Under the Hood => Just annotations
If your returned type is annotated with @Nullable
in Java, then in Kotlin, the type will become nullable
How to still prevent NPEs?
- Annotate your Java types
- @Nullable type
- @NotNull type
Non-null by default (JSR-305):
@javax.annotation.Nonnull @TypeQualifierDefault(ElementType.PARAMETER, …) annotation class MyNonnullByDefault
package-info.java:
@MyNonnullByDefault package mypackage;
Then, Kotlin will give you warning when assigning null
to values:
@MyNonnullByDefault public class Session { public void setDescription(String description) { this.description = description; } }
Calling Java code from Kotlin:
val session = Session() session.setDescription(null) // => Warning: Expected type doesn't accept nulls in Java …
If you prefer errors in compile time rather than warnings:
build.gradle
compileKotlin { kotlinOptions { freeCompilerArgs += "-Xjsr305=strict" } }
Then, Kotlin will give you errors when assigning null
to values:
@MyNonnullByDefault public class Session { public void setDescription(String description) { this.description = description; } }
Calling Java code from Kotlin:
val session = Session() session.setDescription(null) // => Error: Null can not be a value of a non-null type …
build.gradle
- Specify types explicitly
public class Session { public void setDescription(String description) { this.description = description; } }
val session = Session() val description: String? = session.description ✅
Or, the code below gives you IllegalStateException in runtime which notifies you very early what is wrong with your code:
val session = Session() val description: String = session.description // IllegalStateException: session.description must not be null
How it works? - Intrinsic checks
The code below will be generated by compiler:
Intrinsics.checkExpressionValueisNotNull()
Collections
Read-only interfaces improve API
- How read-only collections and mutable collections work in Kotlin
List & MutableList
- Two interfaces declared in
kotlin
package MutableList
extendsList
Read-only DOES NOT mean immutable - Read-only interface just lacks mutating methods
The actual list can be changed by another reference:
val mutableList = mutableListOf(1, 2, 3) val list: List<Int> = mutableList println(list) // [1, 2, 3] mutableList.add(4) println(list) // [1, 2, 3, 4]
In Kotlin, there is a plan to provide the immutable data structure in the standard library, but it is not ready yet
String!
= notation, not syntax; platform type, which is a type that comes from Java
Platform types: summary
Good compromise between safety and convenience
Summary
- primitives under the hood, and boxing is possible
- Use
Nothing
whenever possible - Preventing NPE for Java interop: annotations, explicit types
- Read-only does not mean immutable
以上です!