2014/12/03 このエントリーをはてなブックマークに追加 はてなブックマーク - 【Nullいことしてんじゃねぇ】声に出して読みたいKotlin #ktac2014

【Nullいことしてんじゃねぇ】声に出して読みたいKotlin #ktac2014












これはKotlin AdventCalendar2014の3日目ぐらいの記事です。





こんばんは。Javaの皆さん。
今日もNullで消耗していますか????(精一杯の煽り)





ひとむかし前に、声に出したい日本語なんてのがありましたね。
そのまんまなのですが、今回はそれのKotlinバージョンです。リピートアフタミー!





・・・とその前に、どうせ最後まで読まない人が多いと思うので。






先に言っちゃう。Kotlinはコンパイルレベルで厳しく、実行時にやさしい。


すなわち、
コンパイルさえしてしまえば、その時点でかなり精度の高いコード完成している!


優しさの裏返しの厳しさは以下3点





1.Nullにめっちゃ厳しい
だから実行時にNullPointerExceptionは起こらないと言って良いほどですのよ、奥様

2.曖昧なキャストとか許さない
だから型のミスマッチによる例外とか起こりにくいんですよ、お嬢さん。

3.可変と不変(immutableとmutable)にも厳しい
だから「あれ?これどこで代入された変数??(遠い目)」とかいう破壊的代入とか無いんですよ、そこのSIerさん。


あと、優しさもいっぱいある。痒いところに割りと手が届く。



どんな言語なのか知らない人も気になってきたのではないでしょうか?
(Java馬鹿にしてただじゃすまねぇぞ!みたいな人とか)
ということで改めて。。。






・Nullじゃなけりゃ手短に(If not null shorthand)
・Null如何にせよ手短に(If not null and else shorthand)
・Nullじゃなけりゃ、やっちまえ(Execute if not null)
・ユー、whenで返しちゃいなよ(Return on when statement)
・ユー、ifで返しちゃいなよ(Return on if statement)
・ユー、tryブロックごと返しちゃいなよ(Return on try catch block)
・非Nullだってばよ(Not-Null)
・マップにお任せ(Storing Properties in a Map)
・Null安全(Null Safety)
・安全なキャスト(Safe Casts)
・安全呼び出し(Safe Calls)
・エルビス演算子(Elvis Operator)
・Traits
・スマートキャスト(Smart Casts)
・遅延プロパティ(lazy property)
・委譲オブサーバー(Delegates.observable)
・SAM(Single Abstract Method)
・高階関数(Higher-Order Functions )
・インライン関数(Inline Functions)
・拡張関数(Extension Functions)
・関数リテラル(Function literals)


品のある言葉が並んでいますね。心が洗われるようです。


まずは、細かな文法的なところを





val files = File("Test").listFiles()
println(files?.size)




オブジェクトがnullじゃない時だけメソッドを評価します。さようならぬるぽ。







val files = File("Test").listFiles()

println(files?.size ?: "empty")



nullだったら代わりの処理を入れます。Javaの三項演算子に近いですね。今までありがとうぬるぽ。





val data = ...

data?.let {
    ... // execute this block if not null
}



こちらも同じくNullじゃない時はブロック内の処理を実行してくれます。







fun transform(color: String): Int {
    return when (color) {
        "Red" -> 0
        "Green" -> 1
        "Blue" -> 2
        else -> throw IllegalArgumentException("Invalid color param value")
    }
}


when式です。Javaでいうswitchですかね。elseは必須となっております。




fun foo(param: Int) {
    val result = if (param == 1) {
        "one"
    } else if (param == 2) {
        "two"
    } else {
        "three"
    }
}




if式です。戻り値は型推論で善きにはからってくれます。この場合はStringで返してくれますね。
よくあるif文的な使い方ももちろんできます。その場合はUnitという型(voidのようなもの)がリターンされます。





fun test() {
    val result = try {
        count()
    } catch (e: ArithmeticException) {
        throw IllegalStateException(e)
    }

    // Working with result
}




tryブロックそのものを戻り値と出来ます!こいつはクールだ!





//これはコンパイルエラー。
class Foo {
  var bar: Bar // ERROR: must be initialized
}


//Delegates.notNull()を利用すると処理を委譲してコンパイルも問題なし。

class Foo {
  var bar: Bar by Delegates.notNull()
}


Delegates.propertiesというものがあります。これがすごく便利。
非Null型を指定できます。





class User(val map: Map<String, Any?>) {
    val name: String by Delegates.mapVal(map)
    val age: Int     by Delegates.mapVal(map)
}

val user = User(mapOf(
    "name" to "John Doe",
    "age"  to 25
))




プロパティに対してマップ構造でアクセス出来ちゃうんですね。
これで変にマップを複数持たせたりみたいなこともしなくて良い感じです。
実際のインスタンス生成では中置呼び出し記法の「to」を使っています。もちろん、普通のマップの呼び出し方も出来ます。





「Kotlinええやろ?」
※この人はKotlin Projectの中心人物Andrey Breslav。



・・・・・・・・・・・・・。



つづいて、ちょっとまじめに。概念的なところを。。。






Nullのほぼ無い世界。さようならぬるぽ。


var a : String = "abc"
a = null // compilation error


var b : String? = "abc"
b = null // ok





キャスト失敗してもnull返す。(CastExceptionにならない)

val aInt : Int? = a as? Int





安全呼び出し演算子(safe call operator)「?.」でnullでない時だけ呼んでくれる


b?.length()





nullだったら善きに計らうイイヤツ。


// it's typical(old syntax)
val l : Int = if (b != null) b.length() else -1

↓

val l = b?.length() ?: -1




Javaでいうinterface。状態を持たない。
プロパティは持つがabstractでなくてはならない。





人間的にはここは絶対キャスト例外とかないでしょ?って
いうのを解決してくれるかわいいKotlin。



fun demo(x : Any) {
  if (x is String) {
    print(x.length) // x is automatically cast to String
  }
}





プロパティの代入処理を遅延評価してくれる。
immutableなプロパティでも後から値入れたいときとか
簡単な処理を加えたいときとか便利。


import kotlin.properties.Delegates

class LazySample(p : String, f:(String) -> String) {
  val p: String by Delegates.lazy {
      f(p)
  }
}

    
fun main(args : Array<String>) {
  val sample = LazySample("hoge",{
      it + it  + it
  })
  println(sample.p)
}


スレッドセーフな処理にしたい場合は、
Delegates.blockingLazyを使う。
ただし、immutableなプロパティ(val宣言したもの)にしか適用できないみたい。


import kotlin.properties.Delegates
<br>
class User {
  val name: String by Delegates.blockingLazy{
    init()
  }
}

fun init() : String{
  return "initializing..."
}

fun main(args: Array<String>) {
    var user = User()
    println(user.name)
}







オブサーバーに処理を委譲する。というか監視する。


class User {
    var name: String by Delegates.observable("default") {
        d, old, new ->
        println("$old -> $new")
    }
}

fun main(args: Array<String>) {
    val user = User()
    user.name = "first"
    user.name = "second"
}



監視して、値を判定する場合はこのように


class User {
  var name: String by Delegates.vetoable("default value", {
    prop, old, new -> 
    println("$old -> $new")
    old.length < new.length
  })
}

fun main(args: Array<String>) {
    val user = User()
    // 値は適用される
    user.name = "new is longer than default value"
    println(user.name)
    // 値は適用されない
    user.name = "shorter"
    println(user.name)
}








Single Abstract Methodの略。
単一の抽象メソッドを予測してくれる。
例えば、Runnableインターフェースは以下のように書けばKotlinが優しさを見せてくれる


fun main(args: Array<String>) {
    Thread {
        println("Done.")
    }.start()
}





関数を戻り値にとる、または関数を引数にするもの。


fun sayHello(f : (String) -> Unit) {
  f("Hello")
}

fun main(args : Array<String>) {
  sayHello {
    println("$it, world!")
  }
}




inline関数、つまり関数内のローカル関数と出来る。
fun sayHello(f : (String) -> Unit) {
  f("Hello")
}
 
inline fun writeStandardOutput(str : String) {
  println(str)
}
 
fun main(args : Array<String>) {
  sayHello(writeStandardOutput) // ERROR!!!
}





Stringクラスの拡張なんかも出来ちゃう


fun String.任意の関数() {

    // 処理

}




関数がリテラル化されているもの。
即時関数とかって表現が正しいのかどうなのか。



// 関数リテラル
var func = {
    ( 引数リスト ) : 返値型 -> 関数本体
}

// 実行
func()








いかがでしたでしょうか。美しい言葉の数々。



お楽しみいただけたでしょうか。



ざっと見ていただいて伝わったかなぁと思うのですが、
KotlinはNull安全であり、型安全性が高いです。
また、ボイラープレートを極力排除する設計思想となっています(前述したSAMや型推論などが象徴的です)。

なので、「あー決まりきってるけど、これ書かないとダメなんだよなぁ」みたいなことがKotlinではあまりありません。




書いていると痒いところに手が届く言語です。声に出すとともにみなさんコードを書きましょう!




Don't be shy. Write Kotlin!!








0 件のコメント:

コメントを投稿