LoginSignup
16

More than 3 years have passed since last update.

Kotlinの小技

Last updated at Posted at 2017-05-25

気がついたら、追記していきます。
何か間違っていることなどあれば、コメントをいただけると嬉しいです。

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")
}

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16