- 公開日:2017年11月13日
- 最終更新日:2017年11月29日
- 学習期間:2017年11月06日 - 途中
- 学習期間:705minites[途中]
初めに
本格的にkotlinを利用するようになってきたので、詳細な仕様を把握するために本書を購入しました。
この記事は感想とまとめを兼ねています。
本の評価には色々な視点がありますが、私はjavaのサーバーサイド、android, kotlinの開発経験があるので、その視点で本書を評価しています。
また、まとめの量が多くなってきたので、更新しながら感想を書いていきます。つまり、途中の殴り書きです。。。
良書だし、ちゃんと最後にまとめます。
紙 or 電子書籍
頻繁に持ち運ぶなら電子書籍。職場や家置いとくなら紙で良いと思います。私はkindleで買いました。kindleだと容量を70Mくらい使うので、空容量に注意しましょう。
本書の対象者
Javaの実装経験と、簡単なkotlinの実装経験がある人が読む本です。javaやkotlinの実装経験がない人が読む本ではありません。
kotlinの実装経験がない場合は、「Kotlinスタートブック」から読みましょう。
章別感想とまとめ
後々開発や復習で見返すようためのメモ書き。気になった事項の調査等。結構無駄に深く読み込んでいる箇所もあるので、そこは無視してください。
1章
kotlinは実用主義。アイデアを探求する言語ではない。
多重配列が使いにくいのはそれでかな?
もしくは、 Effective Javaの項目25「 配列よりリストを好む 」が適用されているか。。。
2章
if文(p23 - p24)
ifは式なので、値を返す。
ブロック本体と式本体で記述可能
fun max (a : Int = 0, b : Int = 0) : Int { return if a > b : a ? b }
{}で囲むことを「ブロック本体を持つ」という。
return文が必要。
式本体だけで書く
fun max (a : Int = 0, b : Int = 0) : Int = if a > b : a ? b
直接返す場合は「式本体を持つ」という。
式本体の関数の場合は、戻り値も省略可能
fun max (a : Int = 0, b : Int = 0) = if a > b : a ? b
変数
なるべくval(イミュータブル(不変))で宣言するべき。
クラス
valはイミュータブル(不変)なのでgetterのみ
varはミュータブル(可変)なのでgetterとsetterの両方作成
プロパティを呼び出すとき、実際はgetterを利用している。
greteな仕様だ。
カスタムアクセサ
使ったことない。p33
enum
私は、Android開発ではenumは使わないで、Support Annotationを使う派です。でも、Android Architecture Componentsでは普通に使われていますね。Lifecycleのpublic enum Stateとか。。。proguardで難読化すれば問題はないのですが。。。
Androidの神と呼ばれているJakeWhartonさんはenum使うべき派だそうです。参考
理由は、我々は組み込みエンジニアではなく、Webエンジニアである。との理由だそうです。AndroidエンジニアはWebエンジニアではなく、組み込みエンジニアであるじゃないのかな???よくわかりません。。。
when
whenは式なので値を返す。当然、ブロックを使うこともできます。
javaと異なり、オブジェクトも利用可能。本書では、setOfでSetオブジェクトを作成して比較している。
setOfはkotlinで以下のように実装されている。
public fun <T> setOf(vararg elements: T): Set<T> = if (elements.size > 0) elements.toSet() else emptySet()
Setオブジェクトを返していますね。toSetはkotlin.collectionsパッケージで実装されています。
/** * Returns a [Set] of all elements. * * The returned set preserves the element iteration order of the original array. */ public fun <T> Array<out T>.toSet(): Set<T> { return when (size) { 0 -> emptySet() 1 -> setOf(this[0]) else -> toCollection(LinkedHashSet<T>(mapCapacity(size))) } }
ここでもwhenを使ってますね。out Tのout 修飾子を利用しています。分散アノテーションともいいます。つまりクラスC は T の プロデューサ であり、 T の コンシューマ ではない、と考えます。
スマートキャスト
kotlinの地雷ですね、これ。ネットにもあまり良い説明が載ってない。どうしても好きになれない仕様。
isでチェックとキャストを両方やる。
valで宣言されている必要がある。
3章
トップレベル関数(p64 - 66)
説明がわかりにくいです。要は、javaのようにクラス宣言をしなくてもメソッドを作成できるし、呼び出せるってことですね。
まずはjavaで乗数を計算するクラスと実行クラスを実装してみます。
package inaction; public class Top { public static Double topFunction() { double a = 2.0; return Math.pow(a, 2.0); } }
import inaction.Top; public class Jikko { public static void main(String []args) { System.out.println(Top.topFunction()); } }
実行結果は[4]です。両方ともclassを宣言して、メソッドにstatic宣言をしています。
kotlinの場合は、classとstatic宣言が不要になります。
import inaction.topFunction fun main(args : Array) { System.out.println(topFunction()) }
package inaction fun topFunction() : Int { val a = 2.0 return Math.pow(a, 2.0).toInt() }
結果は同じように4になります。javaクラスにコンパイルされる時に勝手にクラスが作成されて、メソッドがstaticになります。
さらに、ファイルクラスの名前も変更できます。
@file:JvmName("AnotherTop") package inaction fun topFunction() : Int { val a = 2.0 return Math.pow(a, 2.0).toInt() }
@file:JvmNameアノテーションでファイル名を変更できます。
呼び出してみます。
import inaction.AnotherTop; public class Jikko { public static void main(String []args) { System.out.println(AnotherTop.topFunction()); } }
別名AnotherTopで呼び出せています。
拡張関数
これはkotlinを使っている人はみんな知っていますね。
拡張関数はオーバーライドは無理なことを覚えておきましょう。静的関数だから、当たり前ですね。
可変長引数
使うケースは、まずない気がしますが、忘備録的に記載しておきます。
fun main(args : Array<String>) { accept("test1", "test2", "test3") } fun accept(vararg msg: String) { System.out.println(listOf(*msg)) }
可変長引数は、スプレッド演算子「*」を使います。
to
mapOfで利用するtoは関数です。中置呼び出しと呼びます。toはPairクラスを返します。ScalaのTupleと同じ機能です。
val map = mapOf(1 to "one", 2 to "two") for ((key, value) in map.iterator().withIndex()) { System.out.println("key:${key}, valu:${value}") } key:0, valu:1=one key:1, valu:2=two
トリプルクヴォート
あまり使い道がなさそう
ローカル関数
関数の中で関数の宣言をすることです。javaScriptのような記載が可能です。無駄な宣言を減らせます。
4章
kotlinのクラスやメソッドはデフォルトでfinal。継承可能なクラスはopenをつける必要がある。
class Button { fun disable() {} open fun amimate() {} fun click() {} } // finalエラーが出る。 class TextButton : Button() { }
openを追加します。
open class Button { fun disable() {} open fun amimate() {} fun click() {} } class TextButton : Button() { override fun amimate() { super.amimate() } // これはfinalエラー override fun click() {} }
デフォルトがfinalの利点は、スマートキャストが可能になることです。
ただし、abstractクラスのメソッドは継承前提なので、openは不要。
sealed class
暗黙的にopenのついているクラス。クラスの継承を制限するために使います。インタフェースにはsealedがつけられません。子クラスにdataクラスを持つこともできます。
whenでelse文で使うとelseが必要なくなります。まだあまり使い道が理解できてません。
クラス移譲 byキーワード
説明がわかりにくいです。記載してあるコードも動かないし。移譲に関しては、公式サイトを読みましょう。クラス移譲は、インターフェースの実装を他のクラスに委譲できます。
デザインパターンのデリゲートパターンですね。
interface Base { fun onClick() } class BaseImpl() : Base { override fun onClick() { System.out.println("clicked!!") } } class Application(base: Base) : Base by base fun main(args: Array) { val b = Application(BaseImpl()) Application(b).onClick() }
オブジェクト宣言
シングルトンを作成する
5章
コレクション操作
mapは集約
filterはフィルタリング
遅延コレクション操作
一時オブジェクトを生成しないコレクションチェーンです。
mapは集約
SAM
関数が一つのjava interfaceはラムダで代用できる。
匿名objectでも代用できるが、呼び出しごとにインスタンスを生成する。
インスタンスを何度も生成しないで利用する場合は、以下のように実装する(p168)
vae listener = OnClickListener { view - > // something }
ラムダ内でthisは使えない。なぜならコードブロックだから。
with
最初の引数を、二番目の引数のラムダレシーバに変換する。
fun alphabet = with(StirngBuilder()) { // something toString }
上記のような書き方も可能。。。
ラムダの実行結果を返す。
レシーバ(引数)を返したい場合は、applyを使う
apply
レシーバ(引数)を返したい場合に使う。TextViewで複数の値を設定する場合に利用する。(p172)
6章
エルビス演算子
監獄ロックだろ。知ってるよ。
null値の代わりにデフォルトを返す演算子です。
fun alphabet = with(aaa :Stvring?) { val msg: String? = aaa ?: "hello" }
as?
null値の代わりにデフォルトを返す演算子です。
let
型のチェック
if (aaa != null) { mesoddo(aaa) }
aaa?.let { mesoddo(it)}
0 件のコメント:
コメントを投稿