気がついたら、追記していきます。
何か間違っていることなどあれば、コメントをいただけると嬉しいです。
static field , method(っぽいもの)の定義
class Hoge {
companion object {
@JvmField
val hoge: String = "HOGE"
@JvmStatic
fun HogeHoge() { ... }
}
}
companion object の中で変数や関数を定義すれば、Kotlin上でstaticなメンバとして扱える。
Javaでもstaticなメンバとして扱えるが、Companionオブジェクトを介したアクセスになるらしい。
@JvmField
や@JvmStatic
と言ったアノテーションをつけることで、Companionオブジェクトを介さなくなるみたい。
Kotlinのコレクション
kotlinのコレクション(List, Set, Map)には、読み取り専用のものと、書き込み可能なものがある。
List, Set, Mapは読み取り専用、要素の追加等をする場合には、各インターフェースの頭に'Mutable'とついたクラスを使用する。
また、各インターフェースのインスタンスを作る際には、~Of()
と言うファクトリ関数を使用する。
// 読み取り専用
val list: List<Int> = listOf(1, 2, 3)
// 書き込みも可能
val mutableList: MutableList<Int> = mutableListOf(1, 2 ,3)
// OK
mutableList.add(4)
// NG
// list.add(4)
読み取り専用 ≠ immutable
Kotlinのmutableではないコレクションは、読み取り専用ではあるが、完全なImmutable(作成後に、状態を変更できないオブジェクト)と言う訳ではないらしい。
val mutableList = mutableListOf(1, 2, 3)
val list: List<Int> = mutableList // mutableを読み込み専用に代入
mutableList.add(4)
println(list) // 出力 >> [1, 2, 3, 4]
Mutable ~
系インターフェースは読み込み専用インターフェースも継承しているので、そのインスタンスはList
等に代入できてしまう。
結果、後からMutableインターフェース経由で、書き換えられる可能性があるためImmutableではないとのこと。
Mutable(List, Map, Set) <=> (List, Map, Set)
to ~ ()
メソッドを使用する
// MutableList => List
val mutableList: MutableList<Int> = mutableListOf(1, 2, 3)
val list: List<Int> = mutableList.toList()
// List => MutableList
val list: List<Int> = listOf(1, 2, 3)
val mutableList: MutableList<Int> = list.toMutableList()
複数メソッドをもつインターフェースの実装の仕方
OnClickListenerのように、メソッドを1つしか持たないインターフェースであれば、SAM変換を使うことで簡潔に書くことができるが、
AdapterViewのOnItemSelectedListenerのような、メソッドを2つ以上持つインターフェースではSAM変換は使えない。
複数メソッドを持つインターフェースは、object式を用いて実装を行う。
// setOnClickListener
button.setOnClickListener {
// 何らかの処理
}
// OnItemSelectedListener
val listener = object: AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
// 何らかの処理
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// 何らかの処理
}
}
// リスナーの登録
spinner.onItemSelectedListener = listener
これで実装はできるが、Javaっぽいコードになるのが欠点。
何かいい設計はないものか...
if else をスコープ関数で実装
通常
if (hoge) {
// true action
} else {
// false action
}
スコープ関数
hoge?.let {
// true action
} ?: run {
// false action
}
スコープ関数使い方
apply, also, let, run
他に良い記事があるので省略
takeIf
- 渡したラムダの中では、レシーバはthisで呼び出せる
- ラムダの返り値はBoolean
- 返り値がtrueであればレシーバを返し、falseであればnullを返す
val hoge: String = hoge
hoge.takeIf {
hoge == "hoge"
}?.let {
print("hoge is hoge")
} ?: run {
print("hoge is not hoge")
}
バリデーション処理に使えそう
takeUnless
takeIfとほとんど同じ
返り値の判定が逆になり、falseであればレシーバを返し、trueであればnullを返す
val hoge: String = hoge
hoge.takeUnless {
hoge == "hoge"
}?.let {
print("hoge is not hoge")
} ?: run {
print("hoge is hoge")
}