Java?Kotlin?

Firebase の勉強会 に続いて Kotlin の勉強会を開催したので、その内容をブログにも書きたいと思います。
対象としては、何らかの言語の経験のあるエンジニアを想定しています。

Kotlin とは

2011年7月に発表された静的型付けのオブジェクト指向言語で、Java の仮想マシン上で動きます。
オープンソースであり、現在 Android の公式な開発言語として指定されています。
公式サイト によると、数多くのアプリが Kotlin で開発されているようです。
https://developer.android.com/kotlin?hl=ja
(アイキャッチ画像もこちらからお借りしました)

Kotlin の文法

変数宣言

// 変更可能
var num = 10

// 定数
val max = 100

// 型明記
var longNum: Long = 10000

変数は var、定数は val で宣言します。
なお、Kotlin は文末のセミコロン (;) は必要としません。

配列

var list = arrayOf(1, 2, 3)

要素の追加削除はできません。
追加削除をしたい場合は、下記のコレクションを使用します。

コレクション

var list2 = mutableListOf("apple", "orange", "banana")
list2.add("melon")
list2.removeAt(0)
list2.remove("banana")

こちらは要素の追加削除ができます。

if

val price = if (age < 20) 1000 else 1500

一般的な if 文の書き方ももちろんできますが、Kotlin では上記のように if を式として使うこともできます。
上記のように if を使えるため、Kotlin には三項演算子は存在しません。

when

when (x) {
    1 -> print("1")
    2, 3 -> print("2 or 3")
    in 1..9 -> print("digit")
    !in 1..9 -> {
        print("not digit”)
    }
    else -> print("other")
}

val price = when(age) {
    in 0..15 -> 500
    in 16..20 -> 1000
    else -> 1500
}

val price = when {
    age < 15 -> 500
    age < 20 -> 1000
    else -> 1500
}

Kotlin の when (いわゆる switch)は様々な書き方ができます。

1つめは割と一般的な記述方法ですが、それでもさまざま条件を書けることがわかると思います。
ブロックの末尾に break は不要です。

2つめは when を式として書いています。

3つめはそもそもパラメータが存在していません。
パラメータを書かなければ、 if 文のように条件を書いていくことができます。

for

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

for (i in 0..10 step 3) {
    println(i)
}

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

var list = arrayOf(1, 2, 3)
for (item in list) {
    println(item)
}

for 分は変数と範囲を与えて書きます。
0..10  で 0 から 10 まで(10 を含む)を意味します。
(Kotlin の .. は swift の … に相当)

2つめは 0, 3, 6, 9、3つめは 10, 8, 6, 4, 2, 0 が出力されます。

メソッド(関数)

fun double(x: Int): Int {
  return x * 2
}

fun double(x: Int): Int = x * 2

fun logError(id: Int, message: String = "common error") {
    println("id: " + id + ", message: " + message)
}

logError(1, "format error")
logError(2)
logError(id = 3, message = "unknown error")

Kotlin でのメソッド(関数)は、 fun 関数名 (パラメータ: 型): 戻り値 というように書きます。

2つめはわかりづらいですが、メソッドの中身が1つの式であれば、波括弧を省略して = を使って書くこともできます。

また、パラメータのデフォルト値や、ラベルを使ってメソッドを呼び出すことも可能です。

クラス

class Person(val firstName: String, val lastName: String, var age: Int) {
    var job: String = "neet"

    init {
        println("init: " + firstName)
    }

    constructor(firstName: String, lastName: String, age: Int, job: String): this(firstName, lastName, age) {
        this.job = job
    }
}

val taro = Person("taro", "sato", 37)
taro.age++

val jiro = Person("jiro", "suzuki", 37, “Engineer")

「クラス定義にパラメータがある」という見慣れない書き方ですが、これはそのクラスのデフォルトコンストラクタ (init) のパラメータとして処理されます。
またここに書いておけば、自動でそのクラスのプロパティとして扱うこともできるようになります。

constructor メソッドはセカンドコンストラクタです。
init とは別にコンストラクタを持たせたい場合に使います。
セカンドコンストラクタは、戻り値の部分にデフォルトコンストラクタの呼び出しを書く必要があります。

FizzBuzz

下記のように Kotlin らしさを出して FizzBuzz を書いてみました。
println の中に when があってなんかモゾモゾしますw

for (i in 1..100) {
    println(when {
        i%15 == 0 -> "FizzBuzz"
        i%3 == 0 -> "Fizz"
        i%5 == 0 -> "Buzz"
        else -> i
    })
}

Null 安全

下記の Java コードは NullPointerException が発生する可能性があります。

class Company {
    Person ceo;
    …
}

class Person {
    String name;
    …
}

Company bravesoft = new Company();
…
String ceoName = bravesoft.ceo.name;

回避するには、下記のようにしないといけません。

if (bravesoft != null) {
    if (bravesoft.ceo != null) {
        If (bravesoft.ceo.name != null {
            String ceoName = bravesoft.ceo.name;
        }
    }
}

これは非常に面倒くさいですよね。
そこで Null 安全という考え方があります。

Null 安全とは null チェックをコンパイラが行う、という考え方です。
null になる可能性のあるものとないものとを明確に分けるので、実行時に null のエラーが発生しません。

Kotlin では null になる可能性のあるものを Nullable 型、 null になる可能性のないものを NonNull 型 と呼びます。

NonNull 型に null を代入しようとすると、コンパイルエラーになります。

var name: String = "taro"
// name = null // コンパイルエラー
println(name.length)

Nullable 型は、型の最後に ? をつけます。
Nullable 型の変数をそのまま利用しようとすると、コンパイルエラーになります。

var name: String? = "taro"
name = null
// println(name.length) // コンパイルエラー

Nullable 型の変数を利用するには、変数名の最後に ? をつけます。
そうすると、その変数が null でない場合は普通に実行され、null の場合はその式全体が null になります。

println(name?.length)

name が null の場合、上記コードの実行結果は null が出力されます。

この Nullable 型を使って先の ceoName への代入を書くと、下記のように1行で表現できてしまいます。

var ceoName = bravesoft?.ceo?.name

このように Nullable 型は便利ですが、Nullable 型の変数を NunNull 型にキャストしたいことも出てくるかと思います。
普通にそのまま代入しようとするとエラーになるのですが、下記のように if で null チェックしてあげれば代入することが可能です。

if (name != null) {
    // nameLengthはNonNull型
    nameLength = name.length
}

if で null チェックをすれば、その内部では NonNull 型を Nullable 型のように扱うことができます。

ただ、Kotlin ではこの処理をよりエレガントに書くこともできます。

name?.length?.let {
    nameLength = it
}

null になる可能性のある式の後ろに let をつけてブロック化すると、その内部ではその式の評価結果が null でない場合、NunNull 型の it という変数に代入されます。
式の評価結果が null の場合はブロック内部は実行されません。

まとめ

Kotlin を使うメリットは、Null安全、記述が簡潔、言語機能的な強み多数など、さまざまあると思います。
ブレイブソフトでも今後は積極的に Kotlin を導入していこうと考えています。
(とはいえ、若い言語なので今後仕様に大きなアップデートがある可能性を考えると、手放しで導入を決定するのは危険かもしれません)

ちなみに実際の勉強会では、最後に Kotlin で Android アプリを作ってみました。
ブレイブソフトではこのような勉強会を頻繁に開催しています。
興味のある方は、話をするだけでも良いので↓からのご連絡お待ちしています!