
🧑🏻💻 1. Non-null を基本にする
// 悪い
val name: String?
// 良い
val name: String
Nullable を作らないことが最も重要。
🧑🏻💻 2. DTOだけ Nullable
data class UserResponse(
val name: String?
)
外部データだけ Nullable にする。
🧑🏻💻 3. Domain は Non-null
data class User(
val name: String
)
アプリ内部では Non-null を維持する。
🧑🏻💻 4. Repositoryで吸収する
fun load(): User =
api.load()?.toUser() ?: User.EMPTY
Repository より先へ Nullable を持ち込まない。
🧑🏻💻 5. デフォルト値を使う
data class User(
val name: String = ""
)
初期値で null を不要にする。
🧑🏻💻 6. orEmpty()
val name = user.name.orEmpty()
null を空文字へ変換する。
🧑🏻💻 7. emptyList()
fun users(): List<User> = emptyList()
List? を返さない。
🧑🏻💻 8. emptyMap()
fun settings(): Map<String, String> = emptyMap()
Map? を返さない。
🧑🏻💻 9. emptySet()
fun tags(): Set<String> = emptySet()
Set? を返さない。
🧑🏻💻 10. ?: return
val user = repository.find(id) ?: return
null を早期に除去する。
🧑🏻💻 11. ?: continue
val name = user.name ?: continue
ループ中の null をスキップする。
🧑🏻💻 12. ?: break
val item = iterator.nextOrNull() ?: break
null を終了条件として扱う。
🧑🏻💻 13. ?: error()
val token = token ?: error("Token required")
あり得ない null は即座に失敗させる。
🧑🏻💻 14. mapNotNull()
val names = users.mapNotNull { it.name }
変換と null 除去を同時に行う。
🧑🏻💻 15. filterNotNull()
val names = names.filterNotNull()
Collection の null を取り除く。
🧑🏻💻 16. Flow filterNotNull()
val users: Flow<User> =
repository.userFlow.filterNotNull()
Flow の null を流さない。
🧑🏻💻 17. firstOrNull() ?: return
val user = users.firstOrNull() ?: return
最初の要素が無ければ早期終了する。
🧑🏻💻 18. by lazy
private val repository by lazy {
UserRepository()
}
遅延初期化で Nullable を不要にする。
🧑🏻💻 19. Smart Cast(ローカル変数へ退避)
val user = currentUser ?: return
println(user.name)
Smart Cast を有効にして !! を避ける。
🧑🏻💻 20. StateFlow を Nullable にしない
private val uiState =
MutableStateFlow(UserUiState())
StateFlow
🧑🏻💻 21. Compose State を Nullable にしない
var uiState by mutableStateOf(UserUiState())
mutableStateOf
🧑🏻💻 22. Java境界で Non-null 化する
val title: String =
javaApi.title.orEmpty()
Platform Type (String!) を入口で閉じ込める。
🧑🏻💻 23. requireNotNull()
val user = requireNotNull(user)
引数や入力値の null を早期に拒否する。
🧑🏻💻 24. checkNotNull()
val database = checkNotNull(database)
オブジェクトの状態が不正なら失敗させる。
🧑🏻💻 25. Null Object Pattern
interface Logger
object EmptyLogger : Logger
Logger? の代わりに空実装を使う。
🧑🏻💻 26. sealed class / interface
sealed interface UiState {
data object Loading : UiState
data class Success(val users: List<User>) : UiState
data class Error(val message: String) : UiState
}
null の代わりに状態を型で表現する。
🧑🏻💻 27. Result
fun load(): Result<User>
失敗を null ではなく Result で表現する。
🧑🏻💻 28. value class
@JvmInline
value class UserId(val value: Long)
IDなどを専用型にして null を減らす。
🧑🏻💻 29. takeIf()
val adult = user.takeIf { it.age >= 18 } ?: return
条件を満たさなければ早期終了する。
🧑🏻💻 30. firstNotNullOf()
val token = providers.firstNotNullOf {
it.token
}
最初に見つかった Non-null 値を取得する。
🧑🏻💻 31. SharedFlow を使う
private val events = MutableSharedFlow<Event>(
replay = 1
)
イベントでは StateFlow
🧑🏻💻 32. Nothing を使う
fun fail(message: String): Nothing =
throw IllegalStateException(message)
val token = token ?: fail("Token required")
Nothing を使うと独自のガード関数を作れる。
🧑🏻💻 33. !! を使わない
// 悪い
val user = user!!
// 良い
val user = requireNotNull(user)
!! より意図が明確な API を使う。
🧑🏻💻 34. let を減らす
// 悪い
user?.let {
println(it.name)
}
// 良い
val user = user ?: return
println(user.name)
ネストを減らして読みやすくする。
🧑🏻💻 35. lateinit
private lateinit var repository: UserRepository
後から初期化する参照型では Nullable を避けられる。
🧑🏻💻 36. Delegates.notNull()
var count: Int by Delegates.notNull()
Int や Boolean など lateinit が使えない型向け。
🧑🏻💻 37. takeUnless()
val user = user.takeUnless { it.deleted } ?: return
条件を満たしたら除外したい場合に使う。
🧑🏻💻 38. firstNotNullOfOrNull()
val token = providers.firstNotNullOfOrNull {
it.token
}
最初の Non-null を取得し、無ければ null を返す。
🧑🏻💻 39. Kotlin Contracts
@OptIn(ExperimentalContracts::class)
fun requireUser(user: User?) {
contract {
returns() implies (user != null)
}
requireNotNull(user)
}
独自関数でも Smart Cast を効かせられる。
🧑🏻💻 40. associateNotNull() パターン
val map = users
.mapNotNull {
it.id?.let { id -> id to it }
}
.toMap()
Map を作る途中で null を除外する。
🧑🏻💻 まとめ
「null」を未だに使ってるプロジェクト、実際現場では多いですよね。
「NullPointerExeption(ヌルポ)」の対応による開発時間の損失は、IT業界全体で年間数十兆円、個々の開発プロジェクトでも全体の数割の時間を奪うレベルの巨大なインパクトを持っています。
Related Categories : Android・Developmemt・Javascript・Kotlin・Newbie・Terrible