torutkのブログ

ソフトウェア・エンジニアのブログ

今週末の読書会に備えて「Kotlinイン・アクション」を読み始める

明後日1月13日(土)はJava読書会「Kotlinイン・アクション」を読む会(第1回)です。
http://www.javareading.com/bof/

名著「達人プログラマー」では1年に1つの言語を覚えることを推奨しています。そこで毎年ではないですが数年に1回正月に新しいプログラミング言語にとりかかることがあります。ですが、なかなか使えるようには至りません。

が、今年は1月の読書会からKotlinを学ぶことになりました。読書会では、1回の開催で10時〜17時の間で休憩を除くと正味5時間ほど、1冊の本を6回程度で読むので30時間ほどはじっくりKotlinに触れることになります。これならば、それなりに覚えられるのではないか? ということで期待度大です。

Java読書会の開催概要と運営の紹介を次に書いています。
Java読書会BOFの運営について〜1998年から毎月開催

「Kotlinイン・アクション」を事前に読んでおく

最初のKotlinコード

最初(p.4)にKotlinでPersonクラスを定義したコード例が登場します。理解のためではなくKotlinの雰囲気を味わうために記載されています。

data class Person(val name: String, val age: Int? = null)

fun main(args: Array<String>) {
    val persons = listOf(Person("Alice"), Person("Bob", age = 29))
    val oldest = persons.maxBy { it.age ?: 0 }
    println("The oldest is: $oldest")
}

初見ではさすがにコードを理解するには至りません。ですが、この後数回読書会を経れば理解できるようになるのですね。とりあえず以下の感想を持ちました。

  • data class という定義は何だろう
  • クラス宣言に引数定義のようなものが続いている
  • fun というのは関数定義のようだ
  • 引数は型を後置で指定
  • 変数宣言にval、型は記述なし
  • インスタンス生成にnewなし
  • listOfは関数なのか
  • javaのコレクション(List)にはmaxByメソッドはないが
  • maxByに続く波括弧は何だろう
  • 名前付き引数指定ができる
  • エルビス演算子
  • printlnをトップで使える
Kotlin言語とは

1章のp.5にKotolinの目的が書かれています。

Kotlinの第一目標は、現在Javaが使われている全ての状況に適した、より簡潔で、より生産性が高く、より安全なJavaの代替言語を提供すること

静的型付き言語はJavaと同様ですが、型システムが強化されています。Javaにもあるクラス、インタフェース、ジェネリックスに加えて、新たに型推論、null許容型、関数型が導入されます。

p.12にKotlinの特徴が書かれています。

相互運用性を重視し、実用主義で、簡潔で、安全な言語である

ここでの相互運用性は、既存のライブラリ(Java)の活用、KotlinとJavaの混在(JavaからKotlinを利用することも)といったことを指しています。

開発環境について

「Kotlinイン・アクション」では、あまり開発環境については触れられておりません。 
「1.5 Kotlinのツールを使う」のセクションで、kotlinc(コマンドラインコンパイラ)を使ってコンパイルし、javaコマンドで実行する例がちょっとだけ書かれています。コマンドラインコンパイラのインストールについては記載はありません。あとはIDEプラグインがあるよ、対話シェル(REPL)があるよ、といった程度の紹介です。
また、付録Aに、Gradle、Maven、Antを使う方法が記載されています。

2章 Kotlinの基本

トップレベル関数でHello worldを表示する例です。関数の定義方法が説明されています。

fun main(args: Array<String>) {
    println("Hello, world!")
}

関数の本体が1つの式であればreturn文と波括弧が省略でき、戻り値の型も式本体から推論できれば省略できるので、次のような関数定義が存在します。

fun max(a:Int, b:Int) = if (a > b) a else b

変数は、val と var があり、valはイミュータブルな参照、varはミュータブルな参照、極力valを使うのが推奨。

文字列テンプレートで、変数の値や式の値を展開することができます。

val name = ...
println("Hello, $name!")
println("Hello, ${args[0]}!")

プロパティがあり、Javaのフィールドとアクセッサ定義を簡潔に記述できます。

class Person {
    val name: String         // 読み取り専用プロパティ。フィールドとgetterが生成
    var isMarried: Boolean   // 書き込み可能プロパティ。フィールドとgetter/setterが生成
}

getter/setterはカスタム定義可能です。

enumクラスがあります。

enum class Color {
    RED, ORANGE, YELLOW
}

プロパティ、メソッドを持たせることができます。

enum class Color (
    val r: Int, val g: Int, val b: Int
) {
    RED(255, 0, 0), ORANGE(255, 165, 0), YELLOW(255, 255, 0);
    fun rgb() = (r * 256 + g) * 256 + b
}

Javaのswitch文に相当するwhen

when (color) {
    Color.RED -> "Richard"
    Color.ORANGE -> "of"
    Color.YELLOW -> "York"
}

スマートキャスト(インスタンスの型確認とキャスト)

when (e) {
    is Num -> e.value
    is Sum -> eval(e.right) + eval(e.left)
    else -> throw IllegalArgumentException("Unknown expression")
}

while, do-while構文はJavaとほぼ一緒

レンジ

val oneToTen = 1..10

例外処理
Javaと同じくtry-catch-finally構文あり。
検査例外はなく、メソッドシグネチャのthrowsはない