Kotlin制御構文(Control statement)

条件文(Conditional statement)

if文

if(expr) stmt1 else stmt2は、exprが真ならstmt1を、そうでなければstmt2を実行する。

if (a > b) {
    println("Big")
} else {
    println("Small")
}

main関数でargsが空でなければ、受け取った引数に応じて文字列を変更するようにしてみよう。条件に応じて処理を分岐する構文は、Javaでもおなじみのif-elseである。

例: argsが空ではないか確認する

fun main(args: Array<String>) {
  if (args.isNotEmpty()) {
    println("Hello, ${args[0]}!")
  } else {
    println("Hello, world!")
  }
}

isNotEmptyメソッドは配列が空ではないかを確認する。配列が空でなければ、isNotEmptytrueを返し、ifの後に続くブロックを実行する。そうでなければ、elseの後に続くブロックを実行する。Javaのif-elseと同じく、分岐後のブロック内の文が1つだけの場合に限り、中括弧({ })を省略して書くことができる。

Kotlinではif-elseは式である。if-elseは値を返す。

var c = if (a > b) a else b

これはJavaの三項演算子と同じ動作をする。上の例を書き直すと次のようになる。

例: if-elseは式である。

fun main(args: Array<String>) {
  val name = if (args.isNotEmpty()) args[0] else "名無しさん"
  println("Hello, ${name}!")
}

Kotlinには三項演算子がなく、上のようにif文で表現する必要がある。

Javaでは三項演算子を(condition) ? a : bのように書くが、Kotlinは三項演算子をサポートしていない。

繰り返し文(Loop Control)

forループ

forループ文の基本形はfor (... in ...) ...であり、範囲、配列、コレクションを繰り返すときに使用される。

for (i in 1..10) {
    println(i)
}

for (i in 10 downTo 0 step 2) {
    println(i)
}

var colors = arrayOf("Red", "Green", "Blue")
for (color in colors) {
    println(color)
}

main関数で複数のコマンドライン引数に対してすべてHelloを出力したい場合は、forループを使用する。

例: argsの各要素にHelloを繰り返す。

fun main(args: Array<String>) {
  for (name in args) {
    println("Hello, ${name}!")
  }
}

KotlinのforはJavaの「拡張for文」と似ている。ループカウンターを増やしていくスタイルのループをKotlinのforはサポートしていない。

forEachループ

forEachforEachIndexedは、配列やコレクションに対して処理を繰り返す。

var a = arrayOf("Red", "Green", "Blue")

a.forEach {
    value -> println(value)
}

a.forEachIndexed {
    index, value -> println("${index}: ${value}")
}

次の例は、リストを複数の形式で繰り返して出力するプログラムである。

ForTutorial.kt

fun main() {
    val langList = listOf("javascript", "python", "kotlin", "java", "go")

    println("========= for loop =============");
    for (item in langList) {
        println(item)
    }

    println("========= for loop index =============");
    for (index in langList.indices) {
        println("${index} = ${langList[index]}")
    }

    println("========= for each loop =============");
    langList.forEachIndexed { index, value ->
        println("$index = $value")
    }
}

Output:

========= for loop =============
javascript
python
kotlin
java
go
========= for loop index =============
0 = javascript
1 = python
2 = kotlin
3 = java
4 = go
========= for each loop =============
0 = javascript
1 = python
2 = kotlin
3 = java
4 = go

for文はiterationされた値を繰り返すことができる。 for (item in list)と書くと、listの値を1つずつ取り出し、item変数で受け取れる。

for (index in list.indices)と書くと、itemが何番目に位置するかを表すインデックス値をindex変数で受け取れる。インデックスを受け取るため、list[index]にアクセスして該当する値を取得することもできる。

forEachIndexed()メソッドを使用すると、indexvalueを一緒に受け取れる。Javaでは別途変数を作り、インクリメント演算子を入れる必要があるが、Kotlinではこのメソッドで解決できる。

whileループ

whileは条件が成立している間、処理を繰り返す。

var i = 10
while (i > 0) {
    println(i--)
}

whileを活用したコードは次のとおりである。

WhileTutorial.kt

fun main(args:Array<String>) {
    val mostLang = listOf("javascript", "python", "kotlin", "java", "go")

    println("== while case 1 ==============")
    var i = 0
    while (true) {
        if (i == mostLang.size) {
            break
        }
        println(mostLang[i])
        i++
    }

    println("== while case 2 ==============")
    var j = 0
    while (j < mostLang.size) {
        println(mostLang[j])
        j++
    }
}
== while case 1 ==============
javascript
python
kotlin
java
go
== while case 2 ==============
javascript
python
kotlin
java
go

do-whileループ

do ... whileは条件が成立しなくなるまでループを繰り返す。

var i = 10
do {
    println(i--)
} while (i > 0)

分岐文(Branching statement)

break文

breakは最も内側のループを抜ける。

for (i in 1..5) {
    if (i == 2) {
        break
    }
    println(i)
}

continue文

continueは最も内側のループで次の繰り返しを開始する。

for (i in 1..5) {
    if (i == 2) {
        continue
    }
    println(i)
}

when式

whenは条件に応じて異なる値を返す。is文でデータ型に応じて処理を振り分けることができる。

fun describe(obj: Any): String =
    when (obj) {
        1          -> "One"
        in 2..3    -> "Two or Three"
        "Hello"    -> "Greeting"
        is Long    -> "Long"
        !is String -> "Not a string"
        else       -> "Unknown"
    }

switch case文と似ているように見えるが、少し異なる。通常、switch文のcaseには1つの型だけが入るが、whenではすべての型を入れることができる。ロジックが完了した後にbreak文を入れて抜ける必要もない。該当条件に合えばすぐに抜ける。defaultの代わりにelseを使用する。

WhenTutorial.kt

fun whenFunc(value: Any) {
    when (value) {
        0 -> println("0 입니다.")
        "two" -> println("two 입니다.")
        3.14 -> println("3.4 입니다.")
        else -> println("아무것도 해당되지 않아요")
    }
}

fun main(args: Array<String>) {
    whenFunc(0)
    whenFunc("two")
    whenFunc(3.14)
    whenFunc(1234)
}
0 입니다.
two 입니다.
3.4 입니다.
아무것도 해당되지 않아요

その他

ラベル(@)

@でラベルを指定することで、breakcontinueの対象ループを指定できる。

foo@ for (i in 1..5) {
    for (j in 1..5) {
        if (i == 3 && j == 3) break@foo
        println("$i $j")
    }
}

関数のラムダ式でreturnすると通常は関数から返るが、@ラベルを指定してラムダ式からreturnすることができる。

fun foo() {
    listOf(1, 2, 3, 4, 5).forEach baa@ {
        if (it == 3) return@baa
        println(it)		// 1, 2, 4, 5
    }
}

クラスや関数は暗黙的にクラス名、関数名のラベルを持っている。次のように内部クラスから外部クラスのインスタンスを参照することもできる。

class A {
    val foo = "AAA"
    inner class B {
        val foo = "BBB"
        fun foo() = println("${this.foo} ${this@A.foo}")	// BBB AAA
    }
}

fun main() {
    A().B().foo()
}

例外処理(try, throw, catch, finally)

例外処理は次のような例である。

try {
    if (...) {
        throw IllegalStateException()
    } catch (e: Exception) {
        println(e)
    } finally {
        println("Finally")
    }
}

tryは例外処理を開始する。throwは例外を投げる。catchは例外を捕捉する。finallyは例外発生の有無に関係なく、記述された処理を必ず実行する。