Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
明日からちょっと
KotlinでAndroidが書きたくなる(かもしれない?)
SAM変換と拡張関数
 
室星亮太
2014/7/4(金))第2回)かわいいKotlin勉強会)#jkug
突然ですが質問です!
Kotlin書いたことある方?
「Kotlin'書いたことない」
ってイベントページに書いたけれど
本当は書いたことある方?
Androidアプリ
開発したことある方?
ありがとうございました!
お前だれよ
• 名前":"室星亮太
• 仕事":"Androidアプリ開発(Java)、Unityゲーム開発(C#)
• Twi6er":"@RyotaMurohoshi
• 投稿先":"h6p://qiita.com/RyotaMurohos...
AndroidアプリをJavaで開発していて、
「なんでこんなに冗長なコードが必要なんだ!」
ってイラっとすることはありませんか?
私はあります!
C#を業務で使い始めたりしたり、
Groovyをほんのちょっと勉強したら、
「なんでJava、〇〇できないのー!」
って、イラッとなりました
そこでKotlinですね!
明日からちょっと
KotlinでAndroidが書きたくなる(かもしれない?)
SAM変換と拡張関数
と題して今日はLTします!
いらっとする冗長なコード1
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "c...
Kotlinだとすっきり
button.setOnClickListener { Log.v(TAG, "clicked") }
Java、Kotlinそれぞれのクリックリスナー
Kotlin
button.setOnClickListener { Log.v(TAG, "clicked") }
Java
button.setOnClickListener(new Vie...
行数が短くなったことではなく、
「冗長な部分は書く必要がなく
本質的なことだけ書けばよくなった」
というのがミソ
Javaのコードをもう一度見てみましょう
button.setOnClickListener(new View.OnClickListener() { // new以降本質じゃない
@Override // <- 本質じゃない
public v...
Single'Abstract'Method'Conversions
SAM変換
h"p://blog.jetbrains.com/kotlin/2013/08/kotlin;m6;is;here/
SAM$インターフェース
一つの(Single))抽象(Abstract))メソッド(Method)
をもつインターフェース
• Runnable):)void)run()
• View.OnClickListener):)void)onCli...
SAM変換
関数リテラル!">!SAMインターフェース!な変換
Kotlinでは、SAMインターフェースを引数にとるメソッドで、
引数の型と順序そして返値型が一致する関数リテラルを渡すと
インターフェースに変換してくれる
SAMインターフェース...
SAM変換できる例
button.setOnClickListener( { (v : View): Unit -> Log.v(TAG, "clicked") })
button.setOnClickListener( { v -> Log....
SAM変換できない例
// 下記はコンパイルエラー
// Type mismatch
val listener : View.OnClickListener = { (v : View) : Unit -> Log.v(TAG, "clicke...
SAM変換で無駄コードを無くせますね!
もう一例
VolleyのStringRequest
VolleyのStringRequest0Java版
StringRequest request = new StringRequest(
"https://www.google.co.jp/",
new Response.Listener<S...
VolleyのStringRequest0Kotlin版
val request = StringRequest(
url = "https://www.google.co.jp/",
listener = { response ->
Toas...
ちょっとGroovyもみてみましょう
GroovyもSAM変換が使えるようです。
button.setOnClickListener { v -> Toas.makeText(this, "click", Toast.LENGTH_LONG)....
ちょっとGroovyもみてみましょう
SAMインターフェースだけでなく、複数メソッドを持つインターフェースも
Map+クロージャー+as演算子でこんな感じに!
viewPager.setOnPageChangeListener ([
onPag...
実はAndroidStudioとIntelliJだと
一つだけメソッドを実装した匿名クラスがいい感じに!(SAM型も)
button.setOnClickListener((v) -> {Log.v(TAG, "clicked");});
ID...
以上
SAM変換でした。
いらっとする冗長なコード2
ImageView imageView = (ImageView)findViewById(R.id.image_view);
どんなAndroid入門書にも載っている、アクティビティでよくみるコード
けれど「Ima...
とりあえず継承します?
Ac#vityを継承したクラスBaseAc#vityにて、こんなメソッド定義すれば、
public <T extends View> T findById(int viewId) {
return (T)findView...
けど継承って
• 継承むずい
• 「継承が許されるのは小学生までだよね」、だと...
• Ac$vityのサブクラスいくつかあるけど、全部に更にサブクラス
作ってメソッド定義する?
ちょっとないかな...
さてどうしましょう?
• 冗長な記述が頻発したり、よく使う処理がある
• Ac$vityとかに、メソッドを追加したい!
• けど継承したくない)or)できない
Extension)Funcitons
拡張関数
h"p://confluence.jetbrains.com/display/Kotlin/Extension+func=ons
Extension)Funcitons(拡張関数)とは
• 継承せずにメソッドを追加できる"
• 継承禁止なクラスにもメソッドを追加できる
• privateなメンバにアクセスはできない
• メソッドをオーバーライドはできない
Extension)Func-onsの例)定義側
extensions.kt内にて
package com.mrstar.extensions
import android.app.Activity
import android.view.Vi...
Extension)Func-onsの例)利用側
package com.mrstar.android_with_kotlin
// 略
import com.mrstar.extensions.findById // <- 注目
public...
• fun$ClassName.methodName(hoge$:$Hoge)$:$Fuga"みたいな感じで
メソッドを定義します
• 定義した拡張メソッドをimportします
• そうすると普通のメソッドのように使えます
• この例だとAc+...
Extension)Func-onsを使えば...
• 継承しなくてもメソッドを追加できますね
• たくさんのクラスにメソッドを追加しなくてもいいですね
• 自作のメソッドで冗長な記述をスッキリできますね!
ちょっとC#もみてみましょう
C#にも拡張関数と同じような拡張メソッドがあります。
// 定義側
public static class StringExtensions
{
public static string Decorate(this...
ちょっとC#もみてみましょう
C#は
• Javaのpackageアクセスのような、メンバを同じ名前空間だけに
公開するという制限がない
• privateでsta.cな入れ子のクラスは作れる
• が↑なクラスでは拡張メソッドを定義できない
こ...
一方Kotlinでは
• packageにその名前空間とそのサブ名前空間限定で
• クラス内にprivateアクセスレベルで
• 関数内にローカル関数内として、ローカルスコープで
Kotlinだと拡張関数を定義できる!
以上
拡張関数でした。
質問ありますか?
ご清聴ありがとうございました!
 
SAM変換について(Qiita)
h"p://qiita.com/RyotaMurohoshi
Upcoming SlideShare
Loading in …5
×

明日からちょっと KotlinでAndroidが書きたくなる(かもしれない?)SAM変換と拡張関数

3,513 views

Published on

2014/07/04 かわいいKotlin勉強会で行った発表の資料です

  • Be the first to comment

明日からちょっと KotlinでAndroidが書きたくなる(かもしれない?)SAM変換と拡張関数

  1. 1. 明日からちょっと KotlinでAndroidが書きたくなる(かもしれない?) SAM変換と拡張関数   室星亮太 2014/7/4(金))第2回)かわいいKotlin勉強会)#jkug
  2. 2. 突然ですが質問です!
  3. 3. Kotlin書いたことある方?
  4. 4. 「Kotlin'書いたことない」 ってイベントページに書いたけれど 本当は書いたことある方?
  5. 5. Androidアプリ 開発したことある方?
  6. 6. ありがとうございました!
  7. 7. お前だれよ • 名前":"室星亮太 • 仕事":"Androidアプリ開発(Java)、Unityゲーム開発(C#) • Twi6er":"@RyotaMurohoshi • 投稿先":"h6p://qiita.com/RyotaMurohoshi • 興味":"Kotlin,"Groovy,"C#,"Unity,"SonyのWearable"Device
  8. 8. AndroidアプリをJavaで開発していて、 「なんでこんなに冗長なコードが必要なんだ!」 ってイラっとすることはありませんか?
  9. 9. 私はあります! C#を業務で使い始めたりしたり、 Groovyをほんのちょっと勉強したら、 「なんでJava、〇〇できないのー!」 って、イラッとなりました
  10. 10. そこでKotlinですね!
  11. 11. 明日からちょっと KotlinでAndroidが書きたくなる(かもしれない?) SAM変換と拡張関数 と題して今日はLTします!
  12. 12. いらっとする冗長なコード1 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.v(TAG, "clicked"); } }); どんなAndroid入門書にも載っている、アクティビティでよくみるコード Kotlinで書いたやつと比べると、冗長なのが一目瞭然!
  13. 13. Kotlinだとすっきり button.setOnClickListener { Log.v(TAG, "clicked") }
  14. 14. 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!"); } });
  15. 15. 行数が短くなったことではなく、 「冗長な部分は書く必要がなく 本質的なことだけ書けばよくなった」 というのがミソ
  16. 16. Javaのコードをもう一度見てみましょう button.setOnClickListener(new View.OnClickListener() { // new以降本質じゃない @Override // <- 本質じゃない public void onClick(View v) { // <- 本質じゃない Log.v(TAG, "clicked!"); } // <- 本質じゃない }); // <- 本質じゃない Javaは本質じゃない部分が多い。Kotlinは本質のみを記述すればいい Kotlinはなぜあんな記述ができるのか?
  17. 17. Single'Abstract'Method'Conversions SAM変換 h"p://blog.jetbrains.com/kotlin/2013/08/kotlin;m6;is;here/
  18. 18. SAM$インターフェース 一つの(Single))抽象(Abstract))メソッド(Method) をもつインターフェース • Runnable):)void)run() • View.OnClickListener):)void)onClick(View)v) • Response.Listener<T>):)void)onResponse(T)response)) など、他にもたくさん
  19. 19. SAM変換 関数リテラル!">!SAMインターフェース!な変換 Kotlinでは、SAMインターフェースを引数にとるメソッドで、 引数の型と順序そして返値型が一致する関数リテラルを渡すと インターフェースに変換してくれる SAMインターフェースが必要な所も、関数リテラルでスッキリ!
  20. 20. 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") } //or val listener : (View) -> Unit = { Log.v(TAG, "click") } //or val listener = { (v : View) : Unit -> Log.v(TAG, "clicked") } button.setOnClickListener(listener)
  21. 21. SAM変換できない例 // 下記はコンパイルエラー // Type mismatch val listener : View.OnClickListener = { (v : View) : Unit -> Log.v(TAG, "clicked") } // 下記は実行時エラー // java.lang.ClassCastException val listener = { (v : View) : Unit -> Log.v(TAG, "clicked") } as View.OnClickListener 引数に関数リテラルを渡さないといけない
  22. 22. SAM変換で無駄コードを無くせますね! もう一例 VolleyのStringRequest
  23. 23. 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(); } } ); 無駄な部分が多く、縦に長い...
  24. 24. 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変換可能 名前付き引数で可読性アップ
  25. 25. ちょっと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
  26. 26. ちょっと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
  27. 27. 実はAndroidStudioとIntelliJだと 一つだけメソッドを実装した匿名クラスがいい感じに!(SAM型も) button.setOnClickListener((v) -> {Log.v(TAG, "clicked");}); IDE上ではいい感じで折り畳まれてますが、 githubとかでコードリビューするときは、 ほら畳まれないし... h"p://qiita.com/RyotaMurohoshi/items/0ce799c747d91756131a
  28. 28. 以上 SAM変換でした。
  29. 29. いらっとする冗長なコード2 ImageView imageView = (ImageView)findViewById(R.id.image_view); どんなAndroid入門書にも載っている、アクティビティでよくみるコード けれど「ImageView」ってなんで2回書く必要あるん?型推論してくれてもいいじゃん!
  30. 30. とりあえず継承します? 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);
  31. 31. けど継承って • 継承むずい • 「継承が許されるのは小学生までだよね」、だと... • Ac$vityのサブクラスいくつかあるけど、全部に更にサブクラス 作ってメソッド定義する? ちょっとないかな...
  32. 32. さてどうしましょう? • 冗長な記述が頻発したり、よく使う処理がある • Ac$vityとかに、メソッドを追加したい! • けど継承したくない)or)できない
  33. 33. Extension)Funcitons 拡張関数 h"p://confluence.jetbrains.com/display/Kotlin/Extension+func=ons
  34. 34. Extension)Funcitons(拡張関数)とは • 継承せずにメソッドを追加できる" • 継承禁止なクラスにもメソッドを追加できる • privateなメンバにアクセスはできない • メソッドをオーバーライドはできない
  35. 35. Extension)Func-onsの例)定義側 extensions.kt内にて package com.mrstar.extensions import android.app.Activity import android.view.View fun <T : View> Activity.findById (id : Int) : T = findViewById(id) as T
  36. 36. 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) // <- 注目 } }
  37. 37. • fun$ClassName.methodName(hoge$:$Hoge)$:$Fuga"みたいな感じで メソッドを定義します • 定義した拡張メソッドをimportします • そうすると普通のメソッドのように使えます • この例だとAc+vityのサブクラスだけでなく、 FragmentAc+vity、Ac+onBarAc+vity、他のサブクラスでも使え ます(継承で定義するなら、各クラスにメソッド定義が必要)
  38. 38. Extension)Func-onsを使えば... • 継承しなくてもメソッドを追加できますね • たくさんのクラスにメソッドを追加しなくてもいいですね • 自作のメソッドで冗長な記述をスッキリできますね!
  39. 39. ちょっと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なメソッドとして拡張メソッドを定義します。
  40. 40. ちょっとC#もみてみましょう C#は • Javaのpackageアクセスのような、メンバを同じ名前空間だけに 公開するという制限がない • privateでsta.cな入れ子のクラスは作れる • が↑なクラスでは拡張メソッドを定義できない このクラスにだけ、この名前空間でだけ使えるという拡張メソッドを定義できない!
  41. 41. 一方Kotlinでは • packageにその名前空間とそのサブ名前空間限定で • クラス内にprivateアクセスレベルで • 関数内にローカル関数内として、ローカルスコープで Kotlinだと拡張関数を定義できる!
  42. 42. 以上 拡張関数でした。
  43. 43. 質問ありますか?
  44. 44. ご清聴ありがとうございました!   SAM変換について(Qiita) h"p://qiita.com/RyotaMurohoshi

×