速習Kotlin
* 変数
var xxx
* クラスありきではないのでトップレベルに関数をかける
エントリーポイント
fun main(args: Array<String>) {
val name: String = "サンタ"
println("こんちは ${name}さん")
}
* 型
プリミティブ(基本型)という概念はない
Boolean Byte Short Int Long Floag Double Char -> JVMではプリミティブとなる
String
型指定しなくても、型推論によって型が決まる
型を指定しない場合は初期値は必須
* 数値リテラル
整数: Int 小数点:Doubleが規定
変える場合は接尾辞をつけるL: Long, F: Float
num::classで型を表示
* 文字列リテラル
EscapedString 普通の文字列
RawString ヒアドキュメント
"""で囲む
trimIndent()でインデントを削除できる
trimMargin()で|より前を削除できる
* 文字列テンプレート
${val}
前後が空白の場合{}は省略可能だが使わなくて良いかも
* null許容
型名に?をつける Int? String?
ボクシング 基本型->ラッパーオブジェクトへ変換すること
Int -> Int? へ代入すると参照先がかわる??
* 比較
値の比較 == JavaのEquals
参照先の比較 === Javaの==
* Any
どの型でもOK、nullはダメ。Any?はnull許容型のみOK
* スマートキャスト
nullチェックをすればnullでない型として扱える
st2?.length // nullの場合null。nullかどうかチェック。
st2?.length ?: 0 // nullの場合0
st2!!.length // nullの場合例外。強制的に非null型に変換
* キャスト
Javaのように大きい型への暗黙的変換を認めない
明示的にやる
Int -> Long は val.toLong()
Float -> Double は val.toDouble()
* 配列
arrayOf(1, 2, 3)
intArrayOf(1, 2, 3)
set() get() が使える
要素は変えられないのでadd()は使えない
空の配列は要素数を指定し、null許容型のみ
var data: Array<String?> = arrayOfNulls(5)
var data = arrayOfNulls<String>(3)
var arr4 = Array(5, { i -> i * 3})
* コレクション
toList()を使えば別の参照として渡せる
* 定数
変数は var
val Javaのfinalになる(再代入不可)変更不可ではない
まずは valを使うようにする
* const
トップレベルかobjectのメンバー
基本型orString
getterを持たない
## 演算子
* 3項演算子はないがifが式なのでそれが使える
val sw1 = if (n1 > 0) "good" else "bad"
* Range
1..10 型はIntRange
1 until 10 末尾を含まない
10 downTo 1 減少
1..10 step 2
* ビット演算子
Java -> k& | ^ ~
Kotlin -> and or xor inv
0B0110 or 0B0001
Integer.toBinaryString() 2進数表記に
* while do while は javaと同じ
* if
式なので値を返せる
式として使う場合はif elseを網羅している必要がある
* when
Javaのswitch
breakは不要、defaultでなくelse
val sw3 = when {
n1 == 8 -> "good"
n1 < 0 -> "bad"
else -> "soso"
}
range, in, !で否定, カンマで列挙も使える
val sw4 = when(point) {
in 5..9 -> "A"
2,3 -> "B"
1 -> "C"
else -> throw Exception("input out of range")
}
* for
ループ変数はval, varはつけない
for (li in lis) { print(li) }
is.forEach { print(it) }
ラベル構文でfor, whileに名前をつけてbreak,continueの対象を指定できる
outer@while
break@outer
* 中置記法
X to X
X in X
## 関数
引数、戻り値の定義は必須
戻り値がないUnitは省略可能
* 単一式の場合
式を{} でなく = の後ろに書く
returnも不要、型も省略可能
* 名前付き引数
イコールで指定
getArea(height = 5)
* 可変長引数
Arrayとして扱える
普通の引数を混在するには、先頭にするか、そうでなければ名前付き引数にする
fun logprint(vararg items: String) {
items.forEach {
print(it)
}
println()
}
* スプレッド演算子
配列を引数として展開
アスタリスク一個つける *list
* 複数の値を返す
これは一時的なもの以外は使い回さず、データクラスなどを使うべき
Pair<String, Int>
Triple<String, Int, Int>
fun pairRerutn(): Pair<String, Int> {
val message = "成功"
val status = 200
return Pair(message, status)
}
呼び元は分解宣言で受け取る(無視するものは_を置く)
val (message, status) = pairRerutn()
forEachなど引数として関数を受け取るもの
メソッドに関数を渡す
::change
fun change()
普通はラムダ式を渡す
{item: String -> println(item)}
型が明白な場合は省略可能
{item -> println(item)}
一番うしろの引数がラムダ式の場合、括弧の外に出せる
() {item -> println(item)}
引数がラムダ式のみの場合()も省略可能
ラムダの中でreturnするとforEachでなくその外側の関数を抜ける
ラムダのみを抜ける場合はラベル構文を使う
forEach @loop {}
return@loop
* 匿名関数
ラムダは戻り値の型を表現できないのでその場合
fun(num: Int): Int { num }
* 高階関数
高階関数を作るには、引数に型を指定し、内部で実行する
fun benchmark(action: () -> Unit): Long {
action()
}
* インライン関数
関数の受け渡しはオーバーヘッドがあるので、高階関数などは有効
モジュールのサイズは大きくなる
## オブジェクト指向
* staticは存在しない
* メンバー関数
Javaではメソッド
* メソッドアクセス修飾子
public 規定(Javaはパッケージ内が規定)
protected 同じクラスとサブクラス(Javaはパッケージ内も可能)
internal 同じモジュール(IntelliJIDEAモジュール、Gradleプロジェクトなどコンパイル単位)
private 同じクラス、インナークラスのprivateは参照不可(Javaは可能
* プロパティ
単なるフィールドでなく、getter setterをもつ
val, varが使用可能。
初期値を入れない場合は、コンストラクタでセットする
field:バッキングフィールド。自動でフィールドを用意してくれる
get() {
return field
}
set(value) {
field = value
}
get() = age >= 20
クラス外からは変更不可にする
private set
class Human constructor(name: String, age: Int)
var name: String
init {
this.name = name
}
class Human(var name: String, var age: Int) {}
constructorは省略できる
var をつけることで引数がプロパティとなり、渡された値で初期化される
class Human {}
引数がない場合は()を省略できる
複数のコンストラクタを作る場合
本体が不要な場合は{}は省略可能
constructor(name: String): this(name, 0)
デフォルト値を指定できる
class Human3(val name: String = "None", val age: Int = 0) {
* パッケージ
Javaと違いフォルダ構造とパッケージは対応してなくて良い
トップレベル(パッケージ直下)
public internal
private ファイル内で有効(パッケージ内ではなく)
* インポート
規定のインポート 明示しなくてもインポートされる KotlinStandardLibraryとか
アスタリスクでパッケージ全部インポート
as XXX でエイリアス
staticインポート Javaのようにimport staticはない*を使うだけ。
クラス名なしでstaticメソッドを使うため。
## 継承、インターフェイス
* open
規定では継承不可。Javaのfinalの状態
クラス、関数にopenをつけると継承、オーバーライド可能となる
open class xxx -> class xxx : xxx
open fun xxx -> override fun xxx
class Child : Parent()
()をつけることでコンストラクタを実行できる
これでconstructor(): super() はいらない
final override fun show()
これ以上overrideさせない場合にfinalをつける
クラス自体がopenじゃないと意味ない
* abstract
抽象メソッドを含んだクラスを抽象クラスという
抽象メソッドにはabstractをつける。オーバーライドが必須になる。
* interface
publicのみ(デフォルト)
abstract open は不要
プロパティを持てる(Javaではpublic static finalのみ)
プロパティはoverrideするかコンストラクタで初期化する必要がある
デフォルト実装(オーバーライドしなくても使える)
super.xxx()で呼び出す
バッキングフィールドは持てない(他のプロパティを使う)
get() = this.xxx
プロパティの初期値は設定できない。getterを使うとできる
get() = 20
* 型変換
アップキャスト済みで実態が派生クラスであれば
var worker: Worker = BusinessWorker("bb")
スマートキャスト
明示的にキャストせず型をチェックすれば、基底ー>派生として動く
if (worker is BusinessWorker)
worker.work()
明示的にチェックする場合はasを使う
var business: BusinessWorker = worker as BusinessWorker
## データクラス
コンストラクタのみなら{}はなくて良い
※コンストラクタで定義していないものは無視される
equals
すべてのプロパティが等しい場合オブジェクトも同一とみなす
componentN
分割代入ができるようになる。
内部的にxxx.component1, xxx.component2, xxx.component3のようにプロパティにアクセス
copy
コピー。引数で変更するプロパティを指定できる。
* オブジェクト宣言
staticクラスが作れる -> トップレベル関数にしてパッケージにまとめる方が良い?
ユーティリティクラス
コンストラクタは無い
継承は可能
object Something
あとは普通のクラスのようにする
* オブジェクト式
object: Something
再利用しないその場限りのクラスを定義する??
* SAM変換
JavaのRunnable Comparator
これをラムダ式に置き換える??
* コンパニオンオブジェクト
クラス内部でオブジェクト宣言することで、インスタンス化せずに呼び出せるメンバーを作れる
(staticメンバー)
class Laptop private constructor(var name: String) {
companion object Factory {
companion object { 無名でも良い
fun getInstance(): Laptop {
return Laptop("サーフェス")
}
}
Laptop.getInstance()
* enum class
シンボルをカンマ区切りで列挙
is で型のチェック可能
name 文字列
ordinal インデックス
entries 列挙
valueOf() 文字列で探す
enum class Season2(val code: Int) {
SPRING(1),
SUMMER(2),
AUTUMN(3),
WINTER(4);
* ジェネリック型
val gen2 = MyGen<String>("tomorrow")
val gen3 = MyGen(12.3) // 推測できる場合は型指定を省略できる
typealias で型名を定義できる
Tの後ろまたは、whereで渡せる型を指定した型を継承しているもののみに制限
where T:Hoge, T:Fuga
* ジェネリック関数
先頭に<T>を置く
クラスから独立して使える
fun <T> tail(list: Array<T>): T
* in out
Java 配列の型に親子関係にあれば代入できる
Kotlin 代入できない
out その派生型を認める
in その上位型を認める
## その他
* 拡張関数
既存のクラスに関数を追加する
openでなくても良い
自分はthisでアクセスできる
operatorをつけて引数と戻り値をクラスにする
operator fun plus(c: Coordinate): Coordinat
* 入れ子のクラス
入れ子を持つクラスをアウタークラスという
そのクラス専用のクラスとかは中に入れてprivateにする
openの場合はこれで呼べる
MacClass.Iphone()
* インナークラス
innerをつける
アウタークラスのプロパティにアクセスするにはthis@MacClass.nameとする
* 委譲プロパティ
プロパティの後ろにbyで変更時に実行する内容を追加
Delegates.observable("") { xx }
Delegates.vetoable(0) { 判定 } // falseで更新キャンセル
* 遅延プロパティ
初回参照時の処理を書く
インスタンス生成時ではなく、初回参照時に動作し初回以降は同じ値を返す
* プロパティをmapで管理
class Book(private val map: Map<String, Any>){
val title: String by map
val price: Int by map
}
* 委譲プロパティの自作
ReadWriteProperty<Any, T> を実装
* 委譲クラス
インターフェイスの実装を別でやる
class XXX: インターフェイス by 実装クラス