Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【Kotlin】Java(8) -> Kotlinやってみて「良い」と思ったことリスト

f:id:rennnosukesann:20190106130012p:plain:w500

Kotlinをやっていて、Java(8)と比較して良いな、と思った部分を書きました。

null許容型

Swiftなどにもありますが、Kotlinではnull許容型が定義されており、それと対を成すようにデフォルトの型宣言ではnullが許容されないようになっています。

val hoge: String = null // Error:(9, 23) Null can not be a value of a non-null type String
val hoge: String? = null // OK 

エルビス演算子(?:)

オペランド(被演算子)がnullのときのデフォルト値を設定できる

String fuga = hoge == null ? "hoge is null" : hoge;

val fuga = hoge ?: "hoge is null"

第一級関数

Kotlinは関数を言語仕様に持ち、かつそれらを第一級関数として扱えます(値として扱える)。

fun hoge(arg1: String) {
    println(arg1)
}

fun main(args: Array<String>) {
    val func = ::hoge // Javaのメソッド参照のように渡す
    func("hoge")
}

if式

Scalapythonのように、ifが式なので返り値を持ちます。

val isHoge = true;
val hoge = if (isHoge) "hoge" else "not hoge"

文字列テンプレート

JavaScript言語仕様が持つ文字列テンプレートをKotlinでも使用できます。 文字列リテラル内で $ を使って変数を文字列として埋め込みます。

val message = "Hello, Kotlin!"
println("Welcome to Kotlin world : $message")

${} を使用すると、カッコ内に式を使用できます。

val kotlin = "Kotlin!"
val java = "Java"
val isKotlin = true
println("Hello ${if (isKotlin) kotlin else java}")

クラスフィールドにデフォルトでアクセサがつく

immutableフィールド val で宣言した場合はgetterのみが、 mutableフィールド var で宣言した場合はsetter+getterが生成されます。 Kotlinでは暗黙的にgetter/setterが呼ばれます。

class Gorilla(
    val name: String,
    var isAdult: Boolean // getter + setter
)


fun main(args: Array<String>) {
    val gorilla = Gorilla("ゴリラ", true)
    
    // 暗黙的なgetter呼び出し
    println(gorilla.name)  // ゴリラ
    println(gorilla.isAdult) // true
    
    // 暗黙的なsetter呼び出し
    gorilla.isAdult = false
    println(gorilla.isAdult) // false
}

値forループの廃止

言語仕様で for (int i = 0; i < 10; i++) のような繰り返し変数をインクリメントしていく for 文が廃止されており、基本的に拡張forループのみを使用することになります。

Kotlinでfor文による値のインクリメントは .. 演算子によるレンジによって実現できます。

for (i in 1..10) {
    println(i) // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
}

レンジは逆順・数値飛ばしが可能です。

for(i in 10 downTo 1) {
    println(i) // 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
}
for(i in 1..10 step 2) {
    println(i) // 1, 3, 5, 7, 9
}

レンジは閉区間であり、.. 演算子の右側の値を数列に含みます。 開区間のレンジを作る場合、 until を利用します。

for(i in 1 until 10) {
    println(i)  // 1, 2, 3, 4, 5, 6, 7, 8, 9
}

分割代入

オブジェクトプロパティを複数の変数に代入することができます。

fun divMod(a: Int, b: Int) : Pair<Int, Int> {
    return Pair(a / b, a % b)
}

fun main(args: Array<String>) {
    val (div, mod) = divMod(10, 3)
    println("div: $div , mod: $mod")
}

when式

Javaではif/switch文で処理できた複数の分岐処理が、Kotlinではwhen式と呼ばれる言語仕様で実装できます。 when式は式として評価されるので分岐先で結果を返す・変数に入れるなどの操作ができます。 whenはJavaのswitch文のように並列に記述できます。

fun main(args: Array<String>) {
    val num = 3;
    println(fizzbuzz123(num)) // 
}

fun fizzbuzz123(num: Int): String{
    return when (num) {
        1 -> "fizzbuzz"
        2 -> "fizz"
        3 -> "buzz"
        else -> "$num"
    }
}

また引数を省略することで、値マッチングの代わりに条件式による分岐が可能になります。

fun main(args: Array<String>) {
    val num = 3;
    println(fizzbuzz(num))
}

fun fizzbuzz(num: Int): String{
    return when {
        num % 15 == 0 -> "fizzbuzz"
        num % 3 == 0 -> "fizz"
        num % 5 == 0 -> "buzz"
        else -> "$num"
    }
}

名前付き引数/デフォルト引数

名前付き引数・デフォルト引数もサポートされています。

fun add(a: Int, b: Int = 1) :Int {
    return a + b;
}

fun main(args: Array<String>) {
    println(add(1,2)) //3
    println(add(1)) //2
    println(add(a = 4,b = 2)) // 6
}

全般的に他言語で実装済みのモダンで使いやすい言語仕様が入っている印象でした。 まだまだ良いところがありそうなので、追記するかもしれません。