Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LastaFluteでKotlinをはじめよう

 LastaFluteでKotlinをはじめよう

LastaFluteでKotlinを使うための方法を紹介します。

Shinsuke Sugaya

December 02, 2018
Tweet

More Decks by Shinsuke Sugaya

Other Decks in Programming

Transcript

  1. DBFluteフェス 2018 ▪ 名前: 菅谷信介 ▪ オープンソース活動: ➔ Fess, DBFlute関連,

    Apache PredictionIO,... ▪ 2015年からDBFluteフェスのこの枠で... 自己紹介 2
  2. DBFluteフェス 2018 ▪ JetBrains社が作ったJVMで動く静的型付け言語 ▪ 2017年からAndroidの公式開発言語 ▪ Javaと相互運用可能(”100% interoperable”) ▪

    Javaを簡潔/安全になるように改良した言語 ➔型推論、関数型プログラミング、null安全...etc ▪ JavaでできることはほとんどKotlinでもできる ➔JavaのライブラリはKotlinからも使える ➔Javaより簡潔に書けることが多い ➔コンパイル時間はJavaと比べて気にならない Kotlinとは 7
  3. DBFluteフェス 2018 ▪ JetBrains社がJavaからKotlinへの移行を念頭に 2011年から開発開始 ➔2012年 OSS化 ▪ 歴史 ➔2016年

    2月 v1.0 ➔2017年 3月 v1.1 ➔2017年 5月 Androidの公式開発言語として採用 ➔2017年 11月 v1.2 ➔2018年 10月 v1.3 Kotlinの歴史 8
  4. DBFluteフェス 2018 ▪ Javaと互換だが、見た目は結構違う(?) ➔セミコロンが省略可 ➔top-level(クラスと同レベル)に関数や変数が宣言できる ➔省略表現が豊富 ➔...etc 文法 11

    package project.kotlin // パッケージ名 import java.util.* // インポート val PI = 3.14 // 定数 class Person constructor(val firstName: String, val lastName: String) { ... } fun main(args : Array<String>) { println(“Hello World!”) }
  5. DBFluteフェス 2018 ▪ if-else, try-catch ➔Javaのようにも書けるが... 文法: if, try 12

    var max: Int if (a > b) { max = a } else { max = b } try { readFile() return true } catch (e: IOException) { e.printStackTrace() return false }
  6. DBFluteフェス 2018 ▪ Kotlinではifやtryは式(expression) ➔以下の書き方もできる 文法: if, try 13 val

    max = if(a > b) a else b val success = try { readFile() true } catch (e: IOException) { false }
  7. DBFluteフェス 2018 ▪ switch文はなく、代わりにwhenを使う ➔ifやtryと同様, 式として扱われる ➔必要に応じてelseで指定する 文法: when 14

    fun isZeroOrOne(x: Int) : String { return when (x) { 0 -> "xは0です" 1 -> "xは1です" else -> "xは0でも1でもありません" } } print( isZeroOrOne(0) ) // “xは0です”
  8. DBFluteフェス 2018 ▪ for文はforeach方式で書く ➔while, do-whileはJavaと同じ 文法: for, while 15

    val nameList = listOf(“Taro”, “Hanako”) for (name in nameList) { println(name) } val names = arrayOf("Taro", "Hanako") for(i in names.indices) { println(names[i]) } while (x > 0) { x-- }
  9. DBFluteフェス 2018 ▪ val(読み取り専用)とvar(可変) ➔valはJavaで言うfinalがついた変数 ➔コンパイラが型推論できる場合は型の宣言は不要 ▪ インスタンスの生成 ➔newキーワードは不要 変数の定義

    16 val name = "Taro" val name : String = “Taro” var str = "text" var str: String = "Text" val sb = StringBuilder("Hello") sb.append(" ").append("World!") print(sb) // Hello World!
  10. DBFluteフェス 2018 ▪ Javaと同じくnullがある ▪ Optionalのような機能を文法レベルでサポート ➔Nullableな変数には”(型名)?"をつける ➔Nullableな変数を使うときは ▪ "?"(nullの時は実行されない)

    ▪ "!!"(nullでも強制的に実行) Nullable 17 var str: String? = null str?.length() // strがnullの時実行されない str!!.length() // strがnullなら当然NullPointerExceptionがthrow
  11. DBFluteフェス 2018 ▪ エルビス演算子 ?: ➔左式の評価でnullが発生した場合に右式が評価される ▪ Smart casts ➔型チェックやnullチェックなどをすると暗黙的に安全な型変換を

    してくれる機能(コンパイラが追跡できる範囲で) Nullable 18 var person: Person? = ... val name: String = person?.name ?: "NoName" fun printStringLength(str: String?) { if (str != null) { println(str.length) // strはString?からStringにキャストされる } }
  12. DBFluteフェス 2018 ▪ ==は構造等価性, ===は参照等価性 ➔Javaのようにequalsメソッドを呼ぶ必要はない ➔a == b は

    “a?.equals(b) ?: (b === null) “と同じ意味 ➔!=, !==も同様 文法: ==と=== 19 val actual = getFirstName() val expected = “Taro” assertTrue(actual == expected) assertTrue(actual !== expected)
  13. DBFluteフェス 2018 ▪ Javaで言うプリミティブ型(int, double, ...)はなく、すべ てオブジェクト化(Int, Double...) ➔JavaのInteger, Double...に相当

    ▪ コンパイラが型推論してくれるので型の宣言は省略 できることが多い ▪ 配列はArray<(型名)> ➔Javaの[]に相当 ➔基本的な型(Int等)には最適化されたArray(intArray等)がある 型 20 val a = arrayOf(1, 2, 3) val b = intArray(1, 2, 3) // 速い
  14. DBFluteフェス 2018 ▪ Javaで言うvoid型 ▪ 返り値がない関数などはUnit型 ➔省略可 特殊な型: Unit 22

    fun printStringLength(str: String?) { // Unit型の関数 if (str != null) { println(str.length) } }
  15. DBFluteフェス 2018 ▪ JavaのStringとほとんど同じ ➔JavaのString[]はArray<String> ➔Javaの標準ライブラリとは別にStringBuilder等もある ▪ String Template ➔$変数名,

    ${式}で文字列中に値を埋め込める String 23 val num = 1 print(“num is $num and 2*num is ${2*num}”) val input = readLine(input) print(“the input is $input”)
  16. DBFluteフェス 2018 ▪ コンストラクタはクラス名の後 ➔セカンダリコンストラクタも作れる ➔constructorは省略可 ▪ getter, setterは自動で生成される ➔person.firstNameなどで自動でsetter,

    getterが呼ばれる ▪ init でコンストラクタに共通処理が書ける ▪ 継承される可能性があるときはopenを付ける ➔何も付けなければfinal class ▪ interfacesやabstract classは標準でopenとなる クラス 24 class Person constructor(val firstName: String, var lastName: String) {} val person = Person(“Taro”, “Sato”)
  17. DBFluteフェス 2018 ▪ 生成されるPerson.classをJavaにデコンパイルすると.... Javaだと... 25 public final class Person

    { @NotNull private final String firstName; @NotNull private String lastName; @NotNull public final String getFirstName() { return this.firstName; } @NotNull public final String getLastName() { return this.lastName; } public final void setLastName(@NotNull String string) { Intrinsics.checkParameterIsNotNull((Object)string, (String)"<set-?>"); this.lastName = string; } public Person(@NotNull String firstName, @NotNull String lastName) { Intrinsics.checkParameterIsNotNull((Object)firstName, (String)"firstName"); Intrinsics.checkParameterIsNotNull((Object)lastName, (String)"lastName"); this.firstName = firstName; this.lastName = lastName; } }
  18. DBFluteフェス 2018 ▪ staticな変数や関数のみの集まりを定義したい場合 などに使う ➔シングルトンの実装などに使える object 26 object HttpClient

    { var host : String init { host = getHost() } fun httpGetRequest(path: String) : String { return getResponse("GET", host + path) } } print(HttpClient.httpGetRequest("/test/"))
  19. DBFluteフェス 2018 ▪ データを保持するためのクラス ➔コンストラクタ等を書く必要がない ▪ equals() , hashCode(), toString()などを自動的に

    生成してくれる ➔copy(), componentN()なども Data Class 28 data class User(val name: String, val email: String) val taro = User(name = "Taro", age = 18)
  20. DBFluteフェス 2018 ▪ Javaと同じくジェネリクスをサポート ▪ Javaとの違い ➔変性(<? extends T>的な)はinとoutで書ける Generics

    29 interface Source<out T> { fun nextT(): T } fun demo(strs: Source<String>) { val objects: Source<Any> = strs } class Box<T>(t: T) { var item = t } val box: Box<Int> = Box<Int>(1)
  21. DBFluteフェス 2018 ▪ ラムダ式は{}で囲む ▪ ラムダ式の中からアクセスできる ➔Javaと違い、値の変更も可 ラムダ式 30 val

    sum = {x: Int, y: Int -> x + y} // sumの型は "(Int, Int) -> Int" println(sum(1,2)) // sum.invoke(1,2) でもOK var sum = 0 val ints = arrayOf(1, 2, 3) ints.filter { it > 0 }.forEach { sum += it } // ラムダ式の外側の()は省略可 println(sum)
  22. DBFluteフェス 2018 ▪ List, Set, Mapなどのコレクションが用意 ➔基本的にImmutable ➔MutableList, MutableSet, MutableMapなどもある

    ➔listOf(), setOf(), mapOf()などインスタンス生成用のメソッドが 用意されている ➔map, filter, forEachがある(JavaのStream APIと同じ) Collections 32 val readOnlyList = listOf(1, 2, 3, 4) println(readOnlyList) // "[1, 2, 3, 4]" val hashMap = hashMapOf("r" to 0, "g" to 1, "b" to 2) println(hashMap["g"]) // "1" print( readOnlyList.filter{ it % 2 == 0 } ) // "[2, 4]" hashMap.forEach{ key, value -> print("$key $value") } // "r 0b 2g 1"
  23. DBFluteフェス 2018 ▪ 基本的にJvmアノテーションを付与する ▪ Jvmアノテーション ➔top-levelのクラスやメソッドを使いたい → ファイルの先頭に@JvmName ➔クラスのフィールドをつかいたい

    → @JvmField ➔companion objectの中身を使いたい → @JvmStatic ➔その他にも@Throwsや@Voaltile等々 JavaからKotlinを使う 35 @file:JvmName("User") ... class User { @JvmField val userID = 0 companion object { @JvmStatic private val EMPTY_INSTANCE = Test() } }
  24. DBFluteフェス 2018 ▪ IntelliJ ➔Kotlinの開発元(JetBrains)のエディタ ➔Kotlin用の機能が豊富 ➔Java → Kotlinのコード変換機能 所々自分で修正が必要(他のJavaコードから呼び出されている部分や、実装が

    入り組んでいる場合は適切に変換されないことが多いので大幅に書き直しが必 要なことも) ▪ Eclipse ➔公式のEclipse用のプラグインが提供されている ➔でも、IntelliJを使ったほうが良さそう… ▪ Maven, GradleでもKotlinが使える 開発環境 37
  25. DBFluteフェス 2018 ▪ Kotlinを利用したLastaFluteのプロジェクト ▪ Java版のHarborをKotlin化 ▪ Mavenのプロジェクト ▪ 自動生成されるコードはJavaのまま

    ➔DBFluteの機能はそのまま使える ▪ Javaプロジェクトからの移行の参考に… https://github.com/lastaflute/lastaflute-example-paradeplaza Paradeplaza 38
  26. DBFluteフェス 2018 ▪ @Resourceで指定しているコンポーネント ➔Kotlinへの自動変換がうまくいかない ▪ valになるので、lateint varに変える DIするコンポーネント 43

    // 自動変換だと以下になる… // @Resource // private val responseManager: ResponseManager? = null @Resource private lateinit var responseManager: ResponseManager
  27. DBFluteフェス 2018 ▪ Nullableの整理が必要 ▪ ラムダの整理が必要 ➔ たまにラムダの変換が失敗している ▪ ifなどは式である(return

    if ….みたいな) ▪ 定数のconstがなくなる ▪ StringBuilderをbuildStringにする ▪ String Templateを使う その他の自動変換問題 44
  28. DBFluteフェス 2018 ▪ 書き方は大きくは変わらない 実行メソッド 45 @Execute fun index(): HtmlResponse

    { val recentProducts = mappingToProducts(selectRecentProductList()) val highPriceProducts = mappingToProducts(selectHighPriceProductList()) return asHtml(ParadeplazaHtmlPath.path_Mypage_MypageHtml) .renderWith { data -> data.register("recentProducts", recentProducts) data.register("highPriceProducts", highPriceProducts) } }
  29. DBFluteフェス 2018 ▪ Nullableなvarになる Formクラス 46 class MemberAddForm { @Required

    var memberName: String? = null @Required var memberAccount: String? = null @ValidateTypeFailure // using calendar so basically unneeded but just in case var birthdate: LocalDate? = null @Required var memberStatus: CDef.MemberStatus? = null }
  30. DBFluteフェス 2018 ▪ 普通にBhvを使える ➔dataクラスにするいいことがあるか(?) DBFlute関連 47 private fun insertMember(form:

    MemberAddForm) { val member = Member() member.memberName = form.memberName member.memberAccount = form.memberAccount member.birthdate = form.birthdate member.memberStatusCodeAsMemberStatus = form.memberStatus if (member.isMemberStatusCodeFormalized) { member.formalizedDatetime = timeManager.currentDateTime() } memberBhv.insert(member) }