kawaii kotlin functional_literal_and_sam20140704

44
明日からちょっと KotlinAndroidが書きたくなる(かもしれない?) SAM変換と拡張関数 室星亮太 2014/7/4() 2回 かわいいKotlin勉強会 #jkug

Upload: ryota-murohoshi

Post on 07-Jul-2015

1.000 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Kawaii kotlin functional_literal_and_sam20140704

明日からちょっと

KotlinでAndroidが書きたくなる(かもしれない?)

SAM変換と拡張関数 

室星亮太

2014/7/4(金))第2回)かわいいKotlin勉強会)#jkug

Page 2: Kawaii kotlin functional_literal_and_sam20140704

突然ですが質問です!

Page 3: Kawaii kotlin functional_literal_and_sam20140704

Kotlin書いたことある方?

Page 4: Kawaii kotlin functional_literal_and_sam20140704

「Kotlin'書いたことない」ってイベントページに書いたけれど本当は書いたことある方?

Page 5: Kawaii kotlin functional_literal_and_sam20140704

Androidアプリ開発したことある方?

Page 6: Kawaii kotlin functional_literal_and_sam20140704

ありがとうございました!

Page 7: Kawaii kotlin functional_literal_and_sam20140704

お前だれよ• 名前":"室星亮太

• 仕事":"Androidアプリ開発(Java)、Unityゲーム開発(C#)

• Twi6er":"@RyotaMurohoshi

• 投稿先":"h6p://qiita.com/RyotaMurohoshi

• 興味":"Kotlin,"Groovy,"C#,"Unity,"SonyのWearable"Device

Page 8: Kawaii kotlin functional_literal_and_sam20140704

AndroidアプリをJavaで開発していて、

「なんでこんなに冗長なコードが必要なんだ!」

ってイラっとすることはありませんか?

Page 9: Kawaii kotlin functional_literal_and_sam20140704

私はあります!

C#を業務で使い始めたりしたり、

Groovyをほんのちょっと勉強したら、

「なんでJava、〇〇できないのー!」って、イラッとなりました

Page 10: Kawaii kotlin functional_literal_and_sam20140704

そこでKotlinですね!

Page 11: Kawaii kotlin functional_literal_and_sam20140704

明日からちょっと

KotlinでAndroidが書きたくなる(かもしれない?)

SAM変換と拡張関数と題して今日はLTします!

Page 12: Kawaii kotlin functional_literal_and_sam20140704

いらっとする冗長なコード1

button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.v(TAG, "clicked"); }});

どんなAndroid入門書にも載っている、アクティビティでよくみるコード

Kotlinで書いたやつと比べると、冗長なのが一目瞭然!

Page 13: Kawaii kotlin functional_literal_and_sam20140704

Kotlinだとすっきり

button.setOnClickListener { Log.v(TAG, "clicked") }

Page 14: Kawaii kotlin functional_literal_and_sam20140704

Java、KotlinそれぞれのクリックリスナーKotlin

button.setOnClickListener { Log.v(TAG, "clicked") }

Java

button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.v(TAG, "clicked!"); }});

Page 15: Kawaii kotlin functional_literal_and_sam20140704

行数が短くなったことではなく、「冗長な部分は書く必要がなく

本質的なことだけ書けばよくなった」というのがミソ

Page 16: Kawaii kotlin functional_literal_and_sam20140704

Javaのコードをもう一度見てみましょうbutton.setOnClickListener(new View.OnClickListener() { // new以降本質じゃない @Override // <- 本質じゃない public void onClick(View v) { // <- 本質じゃない Log.v(TAG, "clicked!"); } // <- 本質じゃない}); // <- 本質じゃない

Javaは本質じゃない部分が多い。Kotlinは本質のみを記述すればいい

Kotlinはなぜあんな記述ができるのか?

Page 17: Kawaii kotlin functional_literal_and_sam20140704

Single'Abstract'Method'Conversions

SAM変換h"p://blog.jetbrains.com/kotlin/2013/08/kotlin;m6;is;here/

Page 18: Kawaii kotlin functional_literal_and_sam20140704

SAM$インターフェース一つの(Single))抽象(Abstract))メソッド(Method)

をもつインターフェース

• Runnable):)void)run()

• View.OnClickListener):)void)onClick(View)v)

• Response.Listener<T>):)void)onResponse(T)response))

など、他にもたくさん

Page 19: Kawaii kotlin functional_literal_and_sam20140704

SAM変換関数リテラル!">!SAMインターフェース!な変換

Kotlinでは、SAMインターフェースを引数にとるメソッドで、

引数の型と順序そして返値型が一致する関数リテラルを渡すと

インターフェースに変換してくれる

SAMインターフェースが必要な所も、関数リテラルでスッキリ!

Page 20: Kawaii kotlin functional_literal_and_sam20140704

SAM変換できる例button.setOnClickListener( { (v : View): Unit -> Log.v(TAG, "clicked") })button.setOnClickListener( { v -> Log.v(TAG, "clicked")})button.setOnClickListener{ v -> Log.v(TAG, "clicked") }button.setOnClickListener{ Log.v(TAG, "clicked") }

val listener : (View) -> Unit = {v -> Log.v(TAG, "clicked") }//orval listener : (View) -> Unit = { Log.v(TAG, "click") }//orval listener = { (v : View) : Unit -> Log.v(TAG, "clicked") }button.setOnClickListener(listener)

Page 21: Kawaii kotlin functional_literal_and_sam20140704

SAM変換できない例// 下記はコンパイルエラー// Type mismatchval listener : View.OnClickListener = { (v : View) : Unit -> Log.v(TAG, "clicked") }

// 下記は実行時エラー// java.lang.ClassCastExceptionval listener = { (v : View) : Unit -> Log.v(TAG, "clicked") } as View.OnClickListener

引数に関数リテラルを渡さないといけない

Page 22: Kawaii kotlin functional_literal_and_sam20140704

SAM変換で無駄コードを無くせますね!もう一例

VolleyのStringRequest

Page 23: Kawaii kotlin functional_literal_and_sam20140704

VolleyのStringRequest0Java版 StringRequest request = new StringRequest( "https://www.google.co.jp/", new Response.Listener<String>() { @Override public void onResponse(String response) { Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Toast.makeText(getApplicationContext(), "onErrorResponse", Toast.LENGTH_LONG).show(); } } );

無駄な部分が多く、縦に長い...

Page 24: Kawaii kotlin functional_literal_and_sam20140704

VolleyのStringRequest0Kotlin版 val request = StringRequest( url = "https://www.google.co.jp/", listener = { response -> Toast.makeText(this, response, Toast.LENGTH_LONG).show() }, errorListener = { volleyError -> Toast.makeText(this, "onErrorResponse", Toast.LENGTH_LONG).show() } );

型パラーメータがあるインターフェースもSAM変換可能

名前付き引数で可読性アップ

Page 25: Kawaii kotlin functional_literal_and_sam20140704

ちょっとGroovyもみてみましょうGroovyもSAM変換が使えるようです。

button.setOnClickListener { v -> Toas.makeText(this, "click", Toast.LENGTH_LONG).show() }

Groovy&2.2からas演算子がいらなくなったそうです。

h"p://groovy.codehaus.org/Groovy+2.2+release+notes

Page 26: Kawaii kotlin functional_literal_and_sam20140704

ちょっとGroovyもみてみましょうSAMインターフェースだけでなく、複数メソッドを持つインターフェースも

Map+クロージャー+as演算子でこんな感じに!

viewPager.setOnPageChangeListener ([ onPageScrollStateChanged: { state -> Log.v(TAG, state) }, onPageScrolled : { position, positionOffset, positionOffsetPixels -> /*略*/ }, onPageSelected : { position -> Log.v(TAG, position) }] as ViewPager.OnPageChangeListener)

h"p://groovy.codehaus.org/Groovy+way+to+implement+interfaces

Page 27: Kawaii kotlin functional_literal_and_sam20140704

実はAndroidStudioとIntelliJだと一つだけメソッドを実装した匿名クラスがいい感じに!(SAM型も)

button.setOnClickListener((v) -> {Log.v(TAG, "clicked");});

IDE上ではいい感じで折り畳まれてますが、

githubとかでコードリビューするときは、

ほら畳まれないし...

h"p://qiita.com/RyotaMurohoshi/items/0ce799c747d91756131a

Page 28: Kawaii kotlin functional_literal_and_sam20140704

以上SAM変換でした。

Page 29: Kawaii kotlin functional_literal_and_sam20140704

いらっとする冗長なコード2

ImageView imageView = (ImageView)findViewById(R.id.image_view);

どんなAndroid入門書にも載っている、アクティビティでよくみるコード

けれど「ImageView」ってなんで2回書く必要あるん?型推論してくれてもいいじゃん!

Page 30: Kawaii kotlin functional_literal_and_sam20140704

とりあえず継承します?Ac#vityを継承したクラスBaseAc#vityにて、こんなメソッド定義すれば、

public <T extends View> T findById(int viewId) { return (T)findViewById(viewId); }

BaseAc'vityを更に継承したクラスでは、こんな感じでキャスト不要になりますね

ImageView imageView = findById(R.id.image_view);

Page 31: Kawaii kotlin functional_literal_and_sam20140704

けど継承って• 継承むずい

• 「継承が許されるのは小学生までだよね」、だと...

• Ac$vityのサブクラスいくつかあるけど、全部に更にサブクラス作ってメソッド定義する?

ちょっとないかな...

Page 32: Kawaii kotlin functional_literal_and_sam20140704

さてどうしましょう?• 冗長な記述が頻発したり、よく使う処理がある

• Ac$vityとかに、メソッドを追加したい!

• けど継承したくない)or)できない

Page 33: Kawaii kotlin functional_literal_and_sam20140704

Extension)Funcitons

拡張関数h"p://confluence.jetbrains.com/display/Kotlin/Extension+func=ons

Page 34: Kawaii kotlin functional_literal_and_sam20140704

Extension)Funcitons(拡張関数)とは• 継承せずにメソッドを追加できる"

• 継承禁止なクラスにもメソッドを追加できる

• privateなメンバにアクセスはできない

• メソッドをオーバーライドはできない

Page 35: Kawaii kotlin functional_literal_and_sam20140704

Extension)Func-onsの例)定義側extensions.kt内にて

package com.mrstar.extensions

import android.app.Activityimport android.view.View

fun <T : View> Activity.findById (id : Int) : T = findViewById(id) as T

Page 36: Kawaii kotlin functional_literal_and_sam20140704

Extension)Func-onsの例)利用側package com.mrstar.android_with_kotlin

// 略import com.mrstar.extensions.findById // <- 注目

public class MainActivity() : FragmentActivity() { // <- 注目 protected override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main)

val textView: ImageView = findById (R.id.image_view) // <- 注目 }}

Page 37: Kawaii kotlin functional_literal_and_sam20140704

• fun$ClassName.methodName(hoge$:$Hoge)$:$Fuga"みたいな感じでメソッドを定義します

• 定義した拡張メソッドをimportします

• そうすると普通のメソッドのように使えます

• この例だとAc+vityのサブクラスだけでなく、FragmentAc+vity、Ac+onBarAc+vity、他のサブクラスでも使えます(継承で定義するなら、各クラスにメソッド定義が必要)

Page 38: Kawaii kotlin functional_literal_and_sam20140704

Extension)Func-onsを使えば...• 継承しなくてもメソッドを追加できますね

• たくさんのクラスにメソッドを追加しなくてもいいですね

• 自作のメソッドで冗長な記述をスッキリできますね!

Page 39: Kawaii kotlin functional_literal_and_sam20140704

ちょっとC#もみてみましょうC#にも拡張関数と同じような拡張メソッドがあります。

// 定義側 public static class StringExtensions { public static string Decorate(this string str, string symbol) { return string.Format("{0}{1}{2}", symbol, str, symbol); } }

//利用側 string decoratedMessage = "Hello!".Decorate("===")

こんな感じで、sta$cなクラスにsta$cなメソッドとして拡張メソッドを定義します。

Page 40: Kawaii kotlin functional_literal_and_sam20140704

ちょっとC#もみてみましょうC#は• Javaのpackageアクセスのような、メンバを同じ名前空間だけに公開するという制限がない

• privateでsta.cな入れ子のクラスは作れる

• が↑なクラスでは拡張メソッドを定義できない

このクラスにだけ、この名前空間でだけ使えるという拡張メソッドを定義できない!

Page 41: Kawaii kotlin functional_literal_and_sam20140704

一方Kotlinでは• packageにその名前空間とそのサブ名前空間限定で

• クラス内にprivateアクセスレベルで

• 関数内にローカル関数内として、ローカルスコープで

Kotlinだと拡張関数を定義できる!

Page 42: Kawaii kotlin functional_literal_and_sam20140704

以上拡張関数でした。

Page 43: Kawaii kotlin functional_literal_and_sam20140704

質問ありますか?

Page 44: Kawaii kotlin functional_literal_and_sam20140704

ご清聴ありがとうございました! 

SAM変換について(Qiita)

h"p://qiita.com/RyotaMurohoshi