Java読書会BOF「Kotlinイン・アクション」を読む会 第5回に参加
7,8,9章あたりを読みました。 ジェネリクス、ラムダなどJavaだとちょっと不便なところをKotlinがどう解決しているか?というのが見所だと思います。
- コード
- 分割宣言
- 移譲の例
- withIndexを使ったfor文
- デザインパターンと関数型プログラミング
- インライン展開
- withLock関数でtry-finally節を省略できる
- 拡張関数はどこに?
- 型パラメータに対する複数の制約の指定
- 実行時に消去されない方引数(reified)
- 9.3.2 クラス、型、サブタイプ
コード
自分が朗読するパート以外は今回からコードを動かしながら拝聴しました。 https://github.com/Kotlin/kotlin-in-action
分割宣言
複数の戻り値を持つ関数
分割代入を利用する
class Sums(val sum: Int, val count: Int){ //componentNで operator fun component1() = sum operator fun component2() =count } data class Sums2(val sum: Int, val count:Int){ } /** * 合計と要素数を返す関数 */ fun multiRet(arg:List<Int>):Sums{ return Sums(arg.sum(),arg.count()); //return Sums2(arg.sum(),arg.count()); } fun main(args: Array<String>) { val numbers = listOf(1,2,3,4) val (a,b)=multiRet(numbers) //上記の一文は以下のように解釈される //val a = multiRet(numbers).component1() //val b = multiRet(numbers).component2() println(a) println(b) }
- 宣言時に複数のcomponentN()で実装されたメソッドの戻り値を受け取れる
- データクラスでは自動でcomponentN関数が実装される
- 上記コードはコメントアウトされているデータクラスのsumに書き換えても動く
- Qiitaに昔に書いた逆コンパイルしたデータクラスにもcomponentN関数が入っていることが確認できる
public final String component1() { return name; } public final int component2() { return age; }
これを書いていた当時はcomponent1ってなんだ?と思っていたが腑に落ちた。
- connecting dotsじゃないけど学んでることが繋がると嬉しい。
分割宣言とループとの組み合わせ
コレクションの各クラスには独自にcomponentN関数が実装されており、その恩恵を受けるような書き方ができる。
- Mapのentryにはcomponent1,2がそれぞれkey,valueに対応付けられている。
fun printEntries(map:Map<String,String>){ for((key,value) in map){ println("$key -> $value") } /* //mapのentryのにはcomponentNがkey,valueに実装されており、 //上記のfor文の生身はこんな感じに解釈される for (entry in map.entries){ val key = entry.key val value = entry.value println("$key -> $value") } */ } fun main(args: Array<String>) { val map = mapOf("Oracle" to "Java", "JB" to "Kotlin") printEntries(map) /* 結果 Oracle -> Java JB -> Kotlin */ }
移譲の例
ORマッパーのようなものを移譲を利用して簡単に作成できる
- オブザーバーパターンを活用
- 監視した値が変わったら更新
- これはKotlinでなくてもORマッパーはObserverパターンを利用しているのかな?
withIndexを使ったfor文
分割代入を利用して拡張for文内でindexを使えるようにする
Javaだとfor-each文のなかでindexを扱えないので、 for外のスコープに定義した変数をループの中でインクリメントしてごまかしたりしますが、 Kotlinだと次のように書くと拡張for文内でもindexを使えます
val numbers = listOf(21,19,18) for((index,value) in numbers.withIndex()){ println("$index : $value") }
出力
0 : 21 1 : 19 2 : 18
withIndex()がDataクラスであるIndexedValue(index: Int, value: T)
のイテレータを返しているようです。こちらはデータクラスなので分割代入に対応しています。
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/with-index.html
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-indexed-value/index.html
デザインパターンと関数型プログラミング
276pより
- ストラテジーパターンは高階関数で実現できる。
- 振る舞い(ストラテジー)を外部からラムダとして渡す
design patternでstack overflowを検索すると 最上位に関数型プログラミングはデザインパターンを置き換える?と行った内容の議論が出てくることを思い出しました。
https://stackoverflow.com/questions/327955/does-functional-programming-replace-gof-design-patterns
インライン展開
p279あたり
https://ja.wikipedia.org/wiki/インライン展開
- intelliJはよく、インライン化しろ!と命令してくるらしい。(経験者談)
- インラインはテンプレートではなくマクロっぽい。
withLock関数でtry-finally節を省略できる
import java.util.concurrent.locks.Lock
をかなりシンプルに扱う機能のです
Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }
これ相当のプログラムがKotlinでは以下のようにかけます
val l:lock = ... l.withLock{ //ロックで保護したリソースにアクセス }
かなり強力ではないでしょうか?
javaのtry-with-resources文
- Kotlinにない。 = 代替としてuse関数を使う
import java.io.BufferedReader import java.io.FileReader import java.io.File fun readFirstLineFromFile(path: String): String { BufferedReader(FileReader(path)).use { br -> return br.readLine() } }
Closableインターフケースが実装されている必要があります。try-with-resourcesのAutoCloseable相当なのでしょうか?
拡張関数はどこに?
探すの大変そう。
- C#でも同じ苦労がある
- 知ってたら使えるが、知らなかったら永久に存在がわからない。
- ラッパークラスを作るより、拡張関数の方が良いという意見もある。
型パラメータに対する複数の制約の指定
<>の中で一つだけ上限境界(upper bound)*1を指定できます。 複数の型パラメータをもたせたい場合はwhereを使います JavaでおんなじことやろうとするinstanceOfで型検査する必要があります(多分この方法しかないと思う((単数だとsuer ,extendsなどでできた気がするが、複数はできなかったと思う)))。
fun <T> ensureTrailingPeriod(seq: T) where T : CharSequence, T : Appendable { if (!seq.endsWith('.')) { seq.append('.') } } fun main(args: Array<String>) { val helloWorld = StringBuilder("Hello World") ensureTrailingPeriod(helloWorld) println(helloWorld) }
実行時に消去されない方引数(reified)
p308ページあたり
9.3.2 クラス、型、サブタイプ
これはEffective Javaにも出てくる話ですね。ほったらかしにしている3rd(英語版)があるので、後日復習して書こうと思います。
- 共変
- 不変
- 反変
- 作者: Dmitry Jemerov,Svetlana Isakova
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/10/31
- メディア: Kindle版
- この商品を含むブログを見る