ここ2ヶ月くらいずっとKotlinを触ってたせいですっかり忘れてたけど、Javaの瞳を持つ戦士(プログラマ)が初めてKotlinを読むと結構目が滑るのでした。いくらKotlinが素晴らしいJava連携力を持っているとしても、いざ読むときにいつもの読み方ができないと「なんだか難しそう!やっぱり慣れたJavaがいい!」と思ってしまいがちです。
ここでは、Kotlinを読む上でJavaの読み方をすると目が滑る要素をまとめておきます。これからKotlinのコードを読む人にはもしかしたら役に立つかもしれません。
変数宣言は 変数名: 型名
Int x = 0;
SomeClass method1(int i, String s, Date date){ ... }
val x: Int = 0
fun method1(i: Int, s: String, date: Date) : SomeClass { ... }
いわゆるScalaスタイルというやつです。Swiftもこの書き方をしていますね。
CやJavaに慣れている人は初見だと読みづらく感じると思います。
対処法:慣れる
変数宣言のvalとvarが区別しづらい
val x = 0 // 再代入不可
var y = 2 // 再代入可
x = 1 // コンパイル時エラー
y = 3 // OK
val(value)は再代入不可、var(variable)は再代入可。Scalaと同じ宣言方法ですが、何を考えたのか一字違いです。上のコードを見ても分かる通り、コードにするとすごく判別しづらいです。Viとか使ってると地獄です。
とはいえ、実はAndroid Studio (IntelliJ) のデフォルトではvar宣言された変数名には常にアンダーラインが引かれるため、このルールを知っているなら判別は容易でしょう。注意を要する方(=var)に下線がついていると覚えると良いと思います。他のIDEでどうなっているかはわかりません。
対処法:アンダーラインの有無で判別
変数に型が書いてなくてキモい
型なし変数にアレルギーを持っている人は多いと思います。ご安心ください。型が書いてない変数にもちゃんと型はついてます。
Kotlinコンパイラは型推論機能を持つため、変数宣言時に型宣言を省略した場合でも自動で型宣言を補ってくれます。ここで重要なのは型宣言を補うのはコンパイラだということです。実行時の状態によってどの型がつくか変化したりはしませんし、そういうコードは書けません。
なお、普通型推論器というものは候補となる型のうち最小のものを返すため、上記のコードでyにInt?やらAnyやらがついたりはしません。「初期値は実値だけど、処理が進むとnullが代入され得るよ」という場合は、きちんとyがInt?であることを宣言しましょう。
対処法:変数定義の右辺を見る。右辺の式の型がそのまま左辺の変数の型になる。
インスタンス宣言でnewを書かない
SomeClass obj = new SomeClass(10, "aaa", new Date());
val obj = SomeClass(10, "aaa", Date())
Kotlinではインスタンスを作るときにnewを書きません。Javaに慣れていると「クラス名の前のnewの有無」でコンストラクタ利用なのかgetInstance()的なもの利用なのかを判別したりするので、そういう人は混乱しそうです。
識別子が減る分コードは簡潔になるので、読みやすさ自体はプラマイゼロな気もします。あと(new ナントカ(...))ってわざわざカッコで括らなくて良いし。
クラス宣言がコンストラクタ宣言を兼ねる
class User {
String name;
String email;
public User(String name, String email){
this.name = name;
this.email = email;
}
...
}
class User(val name: String, val email: String){
...
}
Kotlinのコンストラクタ(正確にはプライマリコンストラクタ)は以下の点でjavaと異なっています。
- 引数の宣言はクラス宣言のクラス名直後に書かれる。
- 引数名にval/varを付けることで、同名のプロパティをそのまま宣言できる。
これらの特徴はコード量削減に寄与しているのですが、Javaに慣れている人、特に「メンバ変数はクラスの先頭に列挙する」文化に慣れている人は混乱しそうです。
対処法:読み手と言うより書き手のメソッドなのですが、Javaのときと同じ気持ちで読んでもらうために改行とインデントを工夫すると良いです。
class User (
val name: String,
val email: Stirng
) {
...
}
やたらびっくりしてて目がチカチカする
Int result = obj.method1().method2().method3();
val result : Int = obj!!.method1()!!.method2()!!.method3()!!
コードがやたらびっくりするのはnullable処理のアンチパターンど真ん中なのでむしろコードの方に問題があります。
あなたのjavaコードをkotlinに自動変換したときにこうなったなら、むしろ「こんなにnull-unsafeなコードだったのか、見つかってよかった」と喜びましょう。
他にも思いついたら逐次更新しようと思います。