はじめに
Kotlinの基本的な文法等を学びます。 取り扱っていないトピックも多々あるかと思いますが、最低限持っていたい知識をまとめました。 また、所々Javaとの比較も織り交ぜております。
Hello, World!
まずはこれを書かないことにはプログラミングは始まらないですよね。 Javaと比べるとだいぶスッキリした印象です。
fun main() { println("Hello, World!") }
それでは以降、基本的な文法などを見ていきます。
変数
変数宣言には大きく分けて2つの方法があります。
val
は、読み取り専用の変数を宣言し、var
は書き換え可能な変数を定義できます。
val a: Int = 1 a = 10 //valで宣言しているため、コンパイルエラーとなります var b: Int = 2 b = 3
関数
Kotlinでの関数定義方法を見ていきます。
Kotlinでは予約後fun
を使用することで関数を定義できます。以下は、足し算をする関数です。
fun sum(a: Int, b: Int): Int { return a + b }
なお、上記の関数は以下のように書くこともできます。 この場合、返却される型は推論されます。
fun sum(a: Int, b: Int) = a + b
呼び出し方法はJavaなどの構文と同じです。
fun main() { println(sum(3, 5)) // 8 }
分岐と繰り返し
プログラムの基本である分岐と繰り返しです。 これさえ書ければ大半のロジックは組めます。(多分)
分岐
if
Kotlinでは、if
を式として扱います。
そのため、下記のような書き方が可能となります。
fun main() { val a = 10 val b = 20 //ifを式で扱えるため、ifが値を返す val max = if (a < b) b else a println(max) } //以下は、比較のため、ifを文として扱った場合です。 //Kotlinでもこのように書けますが、IDEによっては「もっとシンプルに書けるよ」と警告が出ます。 if (a < b) { max = b } else { max = a }
when
ifで分岐が多くなってしまう場合はwhenが利用できます。 場面に合わせて効果的な方を使いましょう。
when(age) { in 0..3 -> println("baby") in 4..12 -> println("child") in 13..19 -> println("youth") in 20.. 100 -> println("adult") }
なお、whenは値を取らなくとも使用できます。
この場合、各式でtrue
となった行の右辺が実行されます。
途中でtrue
となった場合は以降の行は評価されないことに注意しましょう。
(Javaなどのswith文で、breakがあることをイメージすると良いかもしれません)
when { age in 0..3 -> println("baby") age in 4..12 -> println("child") age in 13..19 -> println("youth") age in 20.. 100 -> println("adult") }
繰り返し
for
for
は、いくつか書き方があります。
fun forExample(){ //1,2,3,4,5,6,7,8,9,10 for (i in 1..10) { println(i) } //stepを使用すると、指定した数値だけ飛ばしていきます。 //1,3,5,7,9 for (i in 1..10 step 2) { println(i) } //downToを使用すると数値を逆順で出せます。 //10,8,6,4,2,0 for (i in 10 downTo 0 step 2) { println(i) } //コレクションの全要素に対して処理をする場合です。 //Javaの拡張For文に似ていますね。 var arr: Array<String> = arrayOf("one", "two", "three") for (s in arr) { println(s) } }
while
while
とdo while
はJavaとほとんど同じようです。
fun whileExample() { var x :Int = 10 while(x > 0) { x-- println(x) } do { x++ println(x) } while(x < 10) }
FizzBuzzを書いてみよう
分岐と繰り返しが書ければFizzBuzzが書ける! というわけで、前述までの知識でFizzBuzzを書いてみましょう。
fun fizzBuzz(count : Int) { for (i in 1..count) { when { i % 15 == 0 -> println("FizzBuzz") i % 5 == 0 -> println("Fizz") i % 3 == 0 -> println("Buzz") else -> println(i) } } }
もっといい書き方があれば教えてください
オブジェクト指向
クラスやインターフェースなど、オブジェクト指向の基本的な記述方法です。
クラスの宣言
class
キーワードを使用することでクラスを宣言することができます。
以下、コンストラクタと初期化ブロック(init
)を持つPerson
クラスです。
class Person(val firstName: String, val lastName: String) { init{ println("hello, $firstName") } }
Kotlinでは、コンストラクタはクラス名の直後に記載します。(val firstName: String, val lastName: String)
←この部分です。
また、init
を使用することで、オブジェクト生成時の挙動を定義することもできます。
オブジェクトの生成
Kotlinではオブジェクトの生成時にnew
演算子を用いません。
前述したPersonクラスを用いたオブジェクト生成方法を下記に示します。
fun main() { val tarou: Person = Person("tarou", "tanaka") println(tarou.firstName) }
結果
hello, tarou //initブロック内の実行結果 tarou //main関数内で実行したprintlnの結果
継承
クラスの継承方法です。
注目して欲しいのはopen
キーワードです。
Javaと異なり、Kotlinでは全てのクラスはデフォルトでfinal
となっています。
そのため、継承をさせたい場合は親クラスにopen
キーワードを付与する必要があります。
open class Parent(x: Int) { } class Child(x: Int) : Parent(x) { }
インターフェース
KotlinにおけるインターフェースもJavaと大きく違いはありません。予約語interface
を使用します。
以下のように抽象メソッドを定義できますし、具象メソッドも定義できます。
//インターフェース interface Calculator { fun calc(a : Int, b: Int): Int } //実装クラス class Plus : Calculator { override fun calc(a: Int, b:Int):Int { return a + b } }
コレクション
使用頻度が高いデータ型の代表格であるコレクションについて、詳しくみておこうと思います。 kotlinでは、コレクションを変更可能か、変更不能かで明確に分けていることに注意しましょう。
リスト
fun main() { //MutableList<E>は名前の通りミュータブル(変更可能)なリスト val numbers1: MutableList<Int> = mutableListOf(1,2,3,4,5) //List<E>型はイミュータブル(変更不可)なリスト val numbers2: List<Int> = listOf(1,2,3,4,5) //numbers1はミュータブルなリストのため、要素の追加と削除が可能 numbers1.add(6) numbers1.removeAt(3) //numbers2はイミュータブルなリストのため、参照用のメンバしか呼び出せない numbers2.size val n = numbers2[0] }
セットとマップ
セットとマップもリストと同様にイミュータブルとミュータブルで分かれています。
また、下記のコードにあるように、map
の生成はkey to value
の形式で、1 to "one"
のように書けます。
fun main() { //setの生成 val set1: MutableSet<Int> = mutableSetOf(1,2,3,4,5) val set2: Set<Int> = setOf(1,2,3,4,5) //mapの生成 val map1: MutableMap<Int, String> = mutableMapOf(1 to "one", 2 to "two") val map2: Map<Int, String> = mapOf(1 to "one", 2 to "two") //mapの要素へアクセスする場合 val value = map2[1] // one }
Null安全
Kotlinでは、Javaと異なりNullを許容する変数と許容しない変数を明示的に分けて書くことが可能となっています。そのため、コンパイル時点でNullPointerExceptionの危険性に気づくことができます。
公式ドキュメントにもあるように、プログラマを悩ませてきたNullPointerException
撲滅のため、しっかり理解して上手に扱えるようにしましょう。(自戒)
基本
まずは基本的な使い方から見ていきます。
以下のように、変数宣言時に型指定において、末尾に?
を付けるとNullを参照できる変数となります。
var hoge: String = "hoge" hoge = null //コンパイルエラー!! //String?とすることでnullが設定可能となる var huga: String? = "huga" huga = null
null参照の可能性がある場合、コンパイルエラーとなる
例えば、以下のようなコードを考えてみましょう。
変数huga
はString?
型のため、null
がありうる値となっています。
そのため、huga.length
の呼び出しの際にNullPointerException
が発生する可能性があることに気づくと思います。
Kotlinではこのような場合に、実行時ではなくコンパイル時にNPEを抑止できるようになります。
var huga: String? = getHuga() if (huga.length > 5) { //hoge.lengthでNPEの恐れがあることをコンパイラが気づいてくれる! println("hugehuga") }
Nullableに対する処置
さて、コンパイルエラーになってしまうのではしょうがないので、コードを修正しなければいけません。 いくつか方法がありますので順に見ていきましょう。
nullチェックをする
原始的な(?)やり方ではありますが、これが一番ポピュラーな方法でしょう。 nullチェックを一度噛ませれば当然NPEが起こらないことが保証できるので、コンパイラも怒ったりしません。
if (huga != null) { if (huga.length > 5) { println("hugehuga") } }
セーフコール
?.
を使用することで、その変数がnull
の場合はnull
を、null
でない場合は呼び出したメソッドに応じた値を取れるようになります。
なお、以下の例の場合に返却される値の型はInt?
になることに注意しましょう。
fun main() { var huga: String? = null var len1 = huga?.length //len1はnullになる var hoge: String? = "hoge" var len2 = hoge?.length //len2は4 }
エルヴィス演算子
?:
を使用することもできます。
?:
を使用すると、左辺がnull
の場合に右辺で指定した値を式の結果として返すようになります。
なお、右辺の式は左辺がnull
である場合にのみ評価されます。
//変数hugaがnullでなければlengthの値を、hugaがnullならば−1を返す var len = huga?.length ?: -1
!!演算子
3つ目の方法として、!!
を使用できます。1
この演算子を使用すると、その変数がnull
かどうかに関わらず、メソッドを呼び出すことが可能となります。
つまり、NullPointerException
が発生する恐れがあるということです。
本来NPEの発生抑止を目的としているのがNull安全の考え方だと思いますので、可能な限り使用は控えた方がいいかと思います。
var hoge: String? = null var len = hoge!!.length //NullPointerExceptionが発生してしまう!
セーフキャスト
上記3つとは趣旨が若干異なりますが、Kotlinではセーフキャストという仕組みを利用することで、ClassCastException
を抑止することができます。
キャスト時に、想定した型にキャストできない場合、通常ClassCastException
がスローされますが、as?
を使用すると例外が発生しなくなります。
var str: String? = getHoge() as? String?
例外
例外の補足などを学びます。
try-catch
try-catch
は、Javaと大きく違いありません。
ただし、try-catch
もKotlinでは式として使用することができます。
単純な例を示します。
fun main() { val result: Int = try { something() } catch (e: NullPointerException) { 0 } } fun something():Int { return 10 }
他いろいろ
その他、Kotlinの細かい部分についてもほんの少し触れておきます。
コメント
コメントの書き方もJavaと同じですね。
//1行コメント /* 複数行はこのように書く */
セミコロンは不要
お気づきの方も多いと思いますが、Javaと異なりKotlinでは行末のセミコロンは不要です。
終わりに
公式ドキュメントや書籍から、Kotlinの基礎的な知識を記載しました。 適宜更新していこうと思います!
-
なんと発音すれば良いのだろうか↩