Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What is going on with this article?
@e-takazawa

KotlinをAndroid Studioで触って一か月間経った話

More than 3 years have passed since last update.

ディップ Advent Calendarの13日目です。

Kotlinを触り始めた理由

私個人はAndroidアプリの実装はJavaで書き慣れているので、今のところKotlinに対する需要はあんまりない。
だが、導入を検討しないで放置できるほどでもないほど、Kotlinが盛り上がりを見せていると思っている。
また、Swiftエンジニアが楽ちんというからにはKotlin触っていればSwiftにも慣れやすくなるのではという淡い期待もあって触ってみることにした。
まだまだ触って一ヶ月程度なので、あまり知見が溜まっているとは言い難いが、それなりにハマるところにはハマった感があるので、ここで共有してきたい。

ここから先の話

ここから先はこれからKotlinを触ろうとしている人に向けて、私がハマった落とし穴に共有することで同じ穴にはまらないようにするために書きます。
すでにKotlinを触っている方にはあんまり珍しい話はではないと思いますので、軽く読み流していただければと思います。

Kotlinは0.x版と1.0版では細かいところで書き方が異なる。

Kotlinは2011年7月にJetBeans社がドラフトバージョンを発表してから、安定稼働版の1.0版が2016年2月にリリースされるまでの間に実に4年半近くかかっています。
その4年半の間に0.x版公開当時のノウハウがインターネット上に広く公開されているため、調べ物をする時によく見ないと混乱することになります。

私は有志の方が解説しているこちらのサイトを読みながら、Webブラウザ上でKotlinプログラムを実行し、練習できるTry Kotlinで書いたプログラムを動作させて最初は勉強してましたが、解説サイトは0.x版での解説であるため、「あれ、コンパイル通らないぞ?」のような事態に陥ることがあります。

例えば、こちらのコード。

isUpperCase
fun isUpperCase(str : String) : Boolean {
  fun String.all(f : (Char) -> Boolean) : Boolean {
    for(val c in this) {
      if(!f(c)) {
        return false
      }
    }

    return true
  }

  return str.all {
    Character.isUpperCase(it)
  }
}

fun main(args: Array<String>) {
    println(isUpperCase("HI")) // 本来はtrueが返却されるはず。
}

なんてことのない普通のfor文に見えますが、for(val c in this) {'val' on loop parameter is not allowedというエラーが発生して実行できません。
初学者でしかもあまりプログラミングに慣れていない人にとってはこういった単純な落とし穴でも解決するまでに時間がかかると思いますので、注意が必要です。
ちなみにこちらのコードは以下のようにvalを取り除けば動きます。

isUpperCase
fun isUpperCase(str : String) : Boolean {
  fun String.all(f : (Char) -> Boolean) : Boolean {
    for(c in this) {
      if(!f(c)) {
        return false
      }
    }

    return true
  }

  return str.all {
    Character.isUpperCase(it)
  }
}

fun main(args: Array<String>) {
    println(isUpperCase("HI")) // trueが返却されます。
}

他にも中置き呼び出しのためにinfixが必要だったり、Intでtimesが使用できなくなったりと、0.x版からの変更点が多いので、初学者は注意が必要です。
では、どうするかという話ですが、手っ取り早く入門書を買うのが良いと思います。

Kotlinスタートブック - 新しいAndroidプログラミング

Null安全は重要なので必ず理解する。

Null安全に関する詳しい説明はこちら

何故かというと、Android StudioのKotlinプラグインを使えば、簡単にJavaファイルをKotlinにコンバートできる(プラグインをインストール後、[Code] → [Convert Java File to Kotlin File]を選択)のですが、元がJavaファイルということもあるのか、前のコードでnullチェックをしていないような変数にはNon-null(!!演算子)をコンバート時に指定されることがあるからです。

Non-nullは結構危険な演算子で、nullが代入されたときはそれだけで実行時例外(KotlinNullPointerException)を吐きます。

この辺りをコンバート時に自動で設定されてしまうので、あんまりKotlinを理解しないでコンバート処理にかけると、動かしてみたけどエラーで落ちる、といった痛い目にあいます。(今の私のようの)

Kotlinで宣言されたインタフェースにはSAM(Single Abstract Method)変換が働かない。

AndroidのOnClickListenarのような一つのインタフェースに実装するメソッドが一つの場合、SAM変換で匿名クラスにオーバーライドメソッドの宣言や引数を省略できます。

普通にjavaで書く場合
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.v(TAG, "クリックされました");
    }
});
Kotlinで書く場合
button.setOnClickListener { Log.v(TAG, "クリックされました") }

button.setOnClickListenerは
android.view.View.OnClickListenerなので、Javaで実装されたインターフェースについては問題なく動作するのですが、Kotlinで書かれたインタフェースの場合はSAM変換が働かないです。

Kotlinで定義したインタフェース
interface OnStringUpdateListener {
    fun onStringUpdate(str: String)
}
コンパイルエラーになるケース
private var mStr: String? = null
private var mStringUpdateListener: OnStringUpdateListener? = null

// SAM変換を期待しているがコンパイルエラーになる
mStringUpdateListener = OnStringUpdateListener{ str -> mStr = str }

何故なんだという話ですが、マニュアルにJavaインタフェースのみ対応と書かれてるので、Kotlinで記述したインタフェースではSAM変換は働きません。

じゃあ、このインタフェースは実装するにはどうすればいいのという話ですが、以下のように実装すればよろしいかと思います。

private var mStr: String? = null
private var mStringUpdateListener: OnStringUpdateListener? = null

mStringUpdateListener = object : OnStringUpdateListener {
    override fun onStringUpdate(str: String) {
        mStr = str
    }
}

うーん、なんかあんまりJavaと手間が変わらない。。。
というかKotlinならインタフェースを実装しなくてももっと効率のいい書き方ができる気がする。。。
⇒教えてもらいました。ありがとうございます。

private var mStr: String? = null
private var mStringUpdateListener: ((String) -> Unit)? = null
mStringUpdateListener = {
    mStr = it
}

まとめ

本家Java8でラムダ式が導入されましたが、Android開発で利用できるのはまだまだ先の話だと思います。
Kotlinでコードの記述量が減れば開発効率が上がるのかなとは思いますが、導入するかどうかはもう少しいじって判断したいかなぁと思います。

3
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
e-takazawa
WEBサイト開発チームでマネジメントを担当しています。(WEBサイト自体はLaravelです。) Java、CakePHP、Androidの開発を経験して、iOS/Android開発チームのマネージャーになった後、現在のポジションにいます。
dip-net
ディップ株式会社は「バイトル」「はたらこねっと」などの求人情報サービスをはじめ、人工知能専門メディア「AINOW」、スタートアップ専門メディア「スタートアップタイムズ」、アニメなどの舞台を紹介するサイト「聖地巡礼マップ」といった新しい分野のサービスを自社で開発・運営しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
3
Help us understand the problem. What is going on with this article?