Kotlinスタートブック -新しいAndroidプログラミング
- 作者: 長澤太郎
- 出版社/メーカー: リックテレコム
- 発売日: 2016/07/13
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
やろうやろう詐欺をし続けて、結構時間が経ったので本腰を入れていく。kotlinだけでなくAndroidのライブラリ全般で開発がめちゃくちゃ早いので、一年前の本なのに読んでみたはいいけどかなりの部分がもう古い情報になっているので注意。読めば「なるほど〜」となるが手を動かすのが重要。サンプルアプリを作るところまでがこの本のゴールなので作ったはいいが、Dagger周りで仕様変更が大きすぎて公開するにはもう少し直さないといけない。
※2017/08/03追記 シンプルにDagger2.11を使って実現したので、サンプルを公開した。サブコンポーネントはややこしいので使ってない。
基本的には冗長なnullチェックがなくなるってインパクトが強いけど、正確には nullをしっかり区別して、簡潔に書ける ところが素晴らしいなと感じる。 普通に書くだけでnullを意識しないとコンパイルできないのが強力だよなぁ。
new
や;
(セミコロン)は不要- コンストラクタの引数に
var
やval
をつけるとgetter
やsetter
が生える require
関数で初期値違反を検出する- tailrecは末尾再帰(tail recursive)
- 演算子オーバーロードが便利
- 拡張関数最高
kotlinc
コマンドでREPL起動- 原則として
val
を使い、再代入不可にする - ${変数名}で値参照(同じリテラルなら中かっこ省略可能)
- 拡張関数の思いつき:toggle(Visibilityの反転)
+=
とか-+
とかで要素を追加、削除できるのよいlistOf
で不変長リスト,mutableListOf
で可変長リストto
でPair
オブジェクトの作成が可能 ->val pair = ("key" to value)
- Mapには
Pari
オブジェクトを渡す必要がある - Stringは
toRegex
で正規表現に変換可能 - 基底クラスは
Any
。クラスとして定義したものは全てAny
のサブクラス - open修飾子で継承可能にできる
===
で等価かどうか判別a.plus(b)
をa plus b
のようにする(中値呼び出し)にするにはinfix
修飾子をメソッドにつけるrange
の代わりに[1..10]
で使っている..
もstep
関数のinfix- 内部クラスにするには
inner
修飾子をつける(アクセスが外側のオブジェクト経由でないとできなくなる) - 可変長引数にするには
vararg
で指定し、一つに関数に一つのみ - 返り値のない関数は
Unit
::
で関数オブジェクトを取得(そしてそれを変数に代入やメソッドに渡せる! Function)- 関数オブジェクトを直接生成するのがラムダ式
->
。中かっこ必須{}
val square: (Int) -> Int = { i: Int -> i * i } //型推論による省略式 val square = { i: Int -> i * i } //引数が一つのときのみ`it`が使える val square: (Int) -> Int = { it * it }
リスト系
val range: IntRange = 12..15
in
で存在確認
>>> 5 in range true >>> 5 !in range false
List
オブジェクトへの変換
(1..5).toList()
反転
//(1..5).reversed().toList() (5 downTo 1).toList()
等間隔
(0..100 step 25).toList() //[0,25,50,75,100]
オブジェクトと型クラス
object式
値と関数を持つオブジェクト
val bucket = object { val capacity: Int = 5 val quantity: Int = 0 fun fill() { quantity = capacity } fun drainAway() { quantity = 0 } fun printQuantity() { pringln(quantity) } }
※単体では型がないため名前参照ができない
interface
型を与えることができる。名前参照が可能になる
interface Bucket { fun fill() fun drainAway() fun pourTo(that: Bucket) fun getCapacity(): Int fun getQuantity(): Int fun setQuantity(quantity: Int) }
fun createBucket(capacity: Int): Bucket = object : Bucket { var _quantity: Int = 0 override fun fill() { setQuantity(getCapacity) } override fun drainAway() { setQuantity(0) } //バケツに注ぐ override fun pourTo(that: Bucket) { val thatVacuity = that.getCapacity() - that.getQuantity() if(getQuantity() <= thatVacuity) { that.setQuantity(that.getQuantity() + getQuantity()) drainAway() } else { that.fill() setQuantity(getQuantity() - thatVacuity) } } override fun getCapacity(): Int = capacity override fun getQuantity(): Int = _quantity override fun setQuantity(quantity: Int) { _quantity = quantity } }
SAM interface
Single Abstract Method interfaceはラムダに変換できる
Runnable : run()
View.OnClickListener : onClick(View v)
などを次のように書ける。
view.setOnClickListener { v -> //do something }
クラス
バッキングフィールド
カスタムゲッター
プロパティにカスタムゲッターを設定することで
class Person { var name: String = "" //プロパティ var age: Int = 0 //プロパティ val nameLength: Int //バッキングフィールドを持たないプロパティ get() = this.name.length //カスタムゲッター }
以上のようにすると
val hanako = Person() hanako.name = "はなこ" println(hanako.nameLength) // =3
となる。
カスタムセッター
プロパティへ
class Person { var name: String = "" set(value) { //カスタムセッター println("${value}がセットされました") field = value //fieldがbucking } var age: Int = 0 val nameLen: Int get() = this.name.length }
とすることで、値がセットされた時に処理を行える。
val test = Person() test.name = "test" //testがセットされましたを出力 println(test.nameLen) // =4
コンストラクタ
constructor
キーワードでコンストラクタに引数を与えれる。それらをプロパティにセットする。
class Rational constructor(n: Int, d: Int) { val numerator: Int = n val denominator: Int = d }
普通はconstructor
キーワードを省略して、引数に直接val
やvar
をつけると同じ意味になる。
class Rational (val numerator: Int, val denominator: Int)
デフォルト値も設定可能。 デフォルト値を設定することでメンバ変数の初期化を書かなくてよい。
class Rational (val numerator: Int, val denominator: Int = 1)
イニシャライザも追加可能。
class Rational (val numerator: Int, val denominator: Int = 1) { init { require(denominator != 0) } }
require
は条件を満たさない時に例外を投げる関数
ジェネリクス
基本
class Container<T>(var value: T)
型制約
//単数 class Container<T: Hoge>(var value: T) //複数 class Container<T> where T : Hoge, T : Fuga
Null safety
いろんな書き方や制約のつけ方があるので、導入前にチームで話した方がいい。
最近lintも増えつつある。
チームでコード規約を作っていくのもいいと思う。
nullを代入
val s: String = null //コンパイルエラー val s: String? = Null
nullの可能性がある変数の参照
s.toUpperCase()//コンパイルエラー s?.toUpperCase()//nullでなければ実行される
引数がNotNull
でないといけないメソッドなどはlet
を使う
fun square(i: Int): Int = i * i val a: Int? = 5 val aSquare = a?.let(::square)//引数が一つなので関数オブジェクトを渡せる
!!
は使うな
val hoge: String? = null val fuga: String = requireNotNull(hoge, {"ぬるぽ"}) //NPE
エルビス演算子?:
null
の時はデフォルトを使う的な実装をするときに使う
val foo: String? = "hello" (foo ?: "default").toUpperCase() //>>>HELLO val hoge: String? = null (hoge ?: "default").toUpperCase() //>>>DEFAULT
安全キャスト
ClassCastException
を防ぐ
val str: Any = "ぺろーん" str as String //ok str as Int // ClassCastException str as? Int //return null
その他
演算子オーバーロード
+
は.plus()
と等価のようにメソッドに演算子を対応づけられる。
対応させるにはoperator
修飾子をつける
class MyInt(val value: Int) { operator fun times(that: MyInt): MyInt = MyInt(value * that.value) } val product = MyInt(3) * MyInt(5) product.value //=15
分解宣言
pair
のfirst
とsecond
を別々に宣言してアクセスできるようにする方法
val (name, age) = Pair("Yuichi", 27) println(name) //Yuichi println(age) //27
データクラス
クラス宣言にdata
をつけるとAny
クラスが持つメソッドの適切な実装が行われる。
これにより、toString
でデータを表示したり、equals
での中身が同じかどうかの比較、
copy
でJavaのclone
と同じように、ディープコピーが可能。
class User(val id: Long, val name: String) User(1, "you") == User(1, "you") //false --- data class User(val id: Long, val name: String) User(1,"you") == User(1, "you") //true
シングルトンにするには
class
ではなくobject
を使うと実現可能
object Me { fun hello() { println("Hello world") } }
- クラス内に作るときは
companion object
修飾子をつける - コンパニオンオブジェクトは1クラスに1つ
enum
enum class SomeType(val num: Int) { S(100) { override fun message(): String = "small" }, M(300) { override fun message(): String = "medium" }, L(500) { override fun message(): String = "large" }; abstruct fun message(): String } SomeType.S.num //100 SomeType.M.message() //medium val types: Array<SomeType> = SomeType.values() types.toList() //[S, M, L] SomeType.valueOf("S") //S SomeType.S.name //S SomeType.values().map { type -> type.ordinal } //[0, 1, 2]
以上。
豪華執筆陣による「Kotlin入門までの助走読本」をリリースします!
— 日本Kotlinユーザグループ (@kotlin_jp) 2017年5月29日
話題のプログラミング言語の「味見」をぜひ!PDF注意https://t.co/LJJDReAzue
これから助走読本を読みつつ、公式が用意している try! kotlinのkoansも解く。
余談だけどkoans
って中国の公案のことで、いわゆる禅問答のことだ。
悟りを開いていこう。