Javaプログラマー向けのKotlin学習用サンプルプロジェクト

# 概要

Kotlinのちょっとしたコードを試すのに最適な[Try Kotlin] (https://try.kotlinlang.org/)というオンラインのサイトがありますが、IntelliJやEclipseなどのIDE上でソースコードを触りながらいろいろ試したいJavaプログラマー向けに、Kotlin学習用のサンプルプロジェクトを作りました。

ソースコードは[こちら] (https://github.com/rubytomato/kotlin-exercise)にあります。このプロジェクトに初歩的なコードがありますので、チェックアウトしてすぐに動作確認できるようになっています。

なお、私自身Kotlin学習中のためサンプルコードや説明に間違いがあったりKotlinの慣習に従っていない点などあるかと思いますが、そのときはご指摘いただければ助かります。

**環境**

* Java 1.8.0_152
* Kotlin 1.2.10
* Gradle
* IntelliJ IDEA

**参考**

* [Reference - Kotlin Programming Language] (https://kotlinlang.org/docs/reference/)
* [GitHub - JetBrains/kotlin-examples] (https://github.com/JetBrains/kotlin-examples/tree/master/gradle)


# サンプルプロジェクト

## 利用する依存関係

**Loggingフレームワーク**

Kotlin用の[MicroUtils/kotlin-logging] (https://github.com/MicroUtils/kotlin-logging)というのもありましたが、サーバーサイドでは定番のslf4J + logbackの組み合わせを利用しました。

* [SLF4J] (https://www.slf4j.org/)
* [Logback] (https://logback.qos.ch/)

**Jsonプロセッサー**

Kotlin用の[cbeust/klaxon] (https://github.com/cbeust/klaxon)というものもありましたが、定番のJacksonを利用しました。

* [FasterXML/jackson] (https://github.com/FasterXML/jackson)

**Httpクライアント**

Kotlin/Android用のFuelというライブラリを使ってみました。

* [kittinunf/Fuel] (https://github.com/kittinunf/Fuel)

> The easiest HTTP networking library for Kotlin/Android

**Testingフレームワーク**

こちらも定番のJUnit 4とAssertJを利用しました。
Kotlin用では[Spek] (http://spekframework.org/)というものがあるようです。

* [JUnit 4] (http://junit.org/junit4/)
* [AssertJ] (http://joel-costigliola.github.io/assertj/)

**Mockサーバー**

* [WireMock] (http://wiremock.org/)

**Mockingフレームワーク**

* [Mockito] (http://site.mockito.org/)

**FatJar**

実行可能なjarを生成するのにGradleのShadow Pluginを利用しています。

* [Shadow Plugin User Guide & Examples] (http://imperceptiblethoughts.com/shadow/)

```
> gradle build
```

ビルドするとbuild/libs下に実行可能なjarファイル`kotlin-exercise-0.0.1-SNAPSHOT-all.jar`が生成されます。

**Kotlinで利用できるライブラリを見つける**

[Kotlin is Awesome!] (https://kotlin.link/)で簡単に検索できます。

### build.gradle

```groovy
buildscript {
    ext {
        kotlinVersion = '1.2.20'
        jacksonVersion = '2.9.3'
        shadowVersion = '2.0.2'
    }
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
        classpath("com.github.jengelman.gradle.plugins:shadow:${shadowVersion}")
    }
}

apply plugin: 'kotlin'
apply plugin: 'application'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
mainClassName = 'com.example.exercise.ApplicationKt'
applicationDefaultJvmArgs = ['-Xms512m', '-Xmx512m']

apply plugin: 'com.github.johnrengelman.shadow'

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

sourceSets {
    main.java.srcDirs += 'src/main/kotlin/'
    test.java.srcDirs += 'src/test/kotlin/'
}

repositories {
    mavenCentral()
    mavenLocal()
    jcenter()
}

dependencies {
    // jackson
    compile("com.fasterxml.jackson.module:jackson-module-kotlin:${jacksonVersion}")
    // http client
    compile("com.github.kittinunf.fuel:fuel:1.12.0") //for JVM
    compile("com.github.kittinunf.fuel:fuel-jackson:1.12.0") //for Jackson support
    // logging
    compile("ch.qos.logback:logback-classic:1.2.3")
    // Kotlin Library
    compile("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
    compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    // test
    testCompile("junit:junit:4.12")
    testCompile("org.assertj:assertj-core:3.9.0")
    // mock server
    testCompile("com.github.tomakehurst:wiremock:2.14.0")
}
```

kotlinでJDK7またはJDK8から追加されたAPIを利用したい場合は、kotlin-stdlibを依存関係に追加します。

kotlin 1.1.xまで

```
// JDK7
compile("org.jetbrains.kotlin:kotlin-stdlib-jre7:1.1.0")
or
// JDK8
compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:1.1.0")
```

kotlin 1.1.2以降

```
// JDK7
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.20")
or
// JDK8
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.20")
```

## サンプルコード

### Loggingフレームワーク

Javaとほとんど同じ使い方です。私自身の経験ではLombokの`@Slf4j`を使って済ませることが多かったのですが、KotlinからLombokの機能を使えるようにするには設定がややこしくなりそうだったので、単純にトップレベルに下記の関数を定義しました。

```kotlin
fun <T> logger(clazz: Class<T>) = LoggerFactory.getLogger(clazz)!!
```

**用例**

```kotlin
class LoggingExercise {
    private val log = logger(LoggingExercise::class.java)

    init {
        log.debug("init log")
    }

    fun logOutput() {
        val now = LocalDateTime.now()
        log.debug("now:{}", now)
        log.info("now:{}", now)
        log.warn("now:{}", now)
        log.error("now:{}", now)
    }

    fun logOutputWithException() {
        val e = RuntimeException("Something wrong happened")
        log.error("Raise an exception", e)
    }

}
```

### Jsonプロセッサー

Javaとほとんど同じ使い方になりました。

マッピングに使用するデータクラス

```kotlin
import com.example.type.Blood

data class Person(val name: String, val age: Int, val blood: Blood)
```

```kotlin
enum class Blood {
    A,
    B,
    AB,
    O
}
```

**用例**

デシリアライズ (json -> Object)

```kotlin
fun readFromFile() {
    val jsonFile = File("person.json")
    val mapper = jacksonObjectMapper()

    val result: Person = mapper.readValue(jsonFile)
    // 下記のように記述することもできます
    // val result = mapper.readValue<Person>(jsonFile)
    // val result = mapper.readValue(jsonFile, Person::class.java)
}
```

シリアライズ (Object -> json)

```kotlin
fun writeFromObject() {
    val jsonFile = File("person.json").also { file ->
        if (file.exists()) {
            file.delete()
        }
    }

    val person = Person("george", 50, Blood.O)
    val mapper = jacksonObjectMapper()
    mapper.writeValue(jsonFile, person)
}
```

### Httpクライアント

この例では[Weather API - OpenWeatherMap] (https://openweathermap.org/api)のサンプルAPIを利用しました。

下記のデータクラスでWeather APIのレスポンスを格納します。

```kotlin
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty

@JsonIgnoreProperties(ignoreUnknown = true)
data class WeatherMap constructor(
    val id: Long,
    val name: String,
    val cod: Int,
    val base: String,
    val dt: Int,
    val coord: Coord,
    val weather: Array<Weather>,
    val main: `Main`,
    val wind: Wind,
    val clouds: Clouds,
    val sys: Sys
) {
    data class Coord(
        val lon: Double,
        val lat: Double)

    data class Weather(
        val id: Long,
        val main: String,
        val description: String,
        val icon: String
    )
    data class `Main`(
        val temp: Double,
        val pressure: Double,
        val humidity: Int,
        @JsonProperty("temp_min")
        val tempMin: Double,
        @JsonProperty("temp_max")
        val tempMax: Double,
        @JsonProperty("sea_level")
        val seaLevel: Double,
        @JsonProperty("grnd_level")
        val grndLevel: Double
    )
    data class Wind(
        val speed: Double,
        val deg: Int
    )
    data class Clouds(
        val all: Int
    )
    data class Sys(
        val message: Double,
        val country: String,
        val sunrise: Int,
        val sunset: Int
    )
}
```

**用例**

GitHubに載っているUsageと同じコードです。

```kotlin
class HttpClientExercise {

    companion object {
        private const val SAMPLE_URL: String = "http://samples.openweathermap.org/data/2.5/weather?lat=35&lon=139&appid=b6907d289e10d714a6e88b30761fae22"
    }

    fun getApiWithAsyncMode() {
        println("Async mode api call before")
        SAMPLE_URL.httpGet().responseString { _, _, result ->
            when(result) {
                is Result.Success -> {
                    val rawData = result.get()
                    rawData.let {
                        val mapper = jacksonObjectMapper()
                        val jsonData = mapper.readValue<WeatherMap>(rawData)
                        println(jsonData)
                    }
                }
                is Result.Failure -> {
                    error("api call faiure: ${result.get()}")
                }
            }
        }
        println("Async mode api call after")
    }

}
```

### ユニットテスト

別記事に分けました。

**用例**

* [ユニットテストでファイルを扱うサンプルコード] (https://qiita.com/rubytomato@github/items/0c0aacd8b71dcd2cb813)
* [ユニットテストのassertionにAssertJを利用するサンプルコード] (https://qiita.com/rubytomato@github/items/a70395be1853848dacb2)
* [ユニットテストでMockサーバーにWireMockを利用するサンプルコード] (https://qiita.com/rubytomato@github/items/0af8179071324fa43d06)
* [ユニットテストでmocking frameworkにMockito 2.13を利用するサンプルコード] (https://qiita.com/rubytomato@github/items/525c12a6e786787784b1)


# Kotlinの関数とラムダ式について

以降はKotlinの関数とラムダ式についてのおさらい的な内容になります。

## 関数 ([Functions] (https://kotlinlang.org/docs/reference/functions.html))

関数の定義

```kotlin
fun sum(x: Int, y: Int): Int { return x + y }
//  ^^^ ^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^
//   |   |                       |
//  (A) (B)                     (C)
```

* A: 関数名
* B: 関数の型
* C: 関数の本体(Body)

関数の本体が単一式の場合は中括弧(curly braces)`{ }`と`return`を省略して記述できます。

```kotlin
fun sum(x: Int, y: Int): Int = x + y
```

## 匿名関数 ([Anonymous Functions] (https://kotlinlang.org/docs/reference/lambdas.html#anonymous-functions))

匿名関数は関数のリテラル表現の1つです。

```kotlin
val sum = fun(x: Int, y: Int): Int { return x + y }
//  ^^^      ^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^
//   |        |                       |
//  (A)      (B)                     (C)
```

* A: 変数(関数)名
* B: 変数(関数)の型
* C: 関数の本体(Body)

関数と同じで単一式の場合は中括弧`{ }`と`return`を省略できます。

```kotlin
val sum = fun(x: Int, y: Int): Int = x + y
```

戻り値の型が推論できるのであれば、戻り値の型も省略できます。

```kotlin
val sum = fun(x: Int, y: Int) = x + y
```

## ラムダ式 ([Lambda Expressions] (https://kotlinlang.org/docs/reference/lambdas.html#lambda-expression-syntax))

ラムダ式は関数のリテラル表現の1つです。

```kotlin
val sum = { x: Int, y: Int -> x + y }
//  ^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
//   |     |
//  (A)   (B)
```

* A: 変数名
* B: ラムダ式 (ラムダ式は常に中括弧`{}`で囲まれます)
    * `->`記号の前にパラメータを定義します。
    * `->`記号の後にラムダ式の本体を記述します。
    * 戻り値の型は指定できません。

上記のラムダ式は、型宣言を明示して記述すると下記のようになります。

```kotlin
val sum: (Int, Int) -> Int = { x, y -> x + y }
//  ^^^  ^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^
//   |    |                    |
//  (A)  (B)                  (C)

// もう少し省略せずに書くとこのようになります
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
```

* A: 変数名
* B: 変数の型
* C: ラムダ式

このスタイルは関数のパラメータにラムダ式を取る場合によく使われます。下記の例ではパラメータ`op`がラムダ式を取ります。

```kotlin
fun calc(x: Int, y: Int, op: (Int, Int) -> Int): Long {
    return op(x, y).toLong()
}
```

関数の呼び出し側でラムダ式を与えます。

```kotlin
val result = calc(5, 2, { x, y -> x + y })
```

パラメータの最後がラムダ式を取る場合、ラムダ式は括弧`()`の外へ出すことができます。

```kotlin
val result = calc(5, 2) { x, y -> x + y }
```

## 関数参照 ([Function References] (https://kotlinlang.org/docs/reference/reflection.html#function-references))

定義済みの関数をパラメータとして渡したい場合は、`::`オペレータを使用します。

```kotlin
private fun numIsEvenNumber(n: Int): Boolean = n % 2 == 0
```

```kotlin
(1..10).filter(::numIsEvenNumber).forEach { even ->
    println(even)
}
```

関数参照の箇所はラムダ式でも記述できます。

```kotlin
(1..10).filter { it % 2 == 0 }.forEach { even ->
    println(even)
}
```

## 拡張関数 ([Extension Functions] (https://kotlinlang.org/docs/reference/extensions.html#extension-functions))

Kotlinの拡張機能の1つで、既存のクラスに（クラスの継承は行わずに）新しい関数を追加しクラスのメンバとして実行することができます。

```kotlin
fun Int.sum(other: Int): Int { return this + other }
//  ^^^ ^^^ ^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^
//   |   |   |                  |
//  (A) (B) (C)                (D)
```

* A: レシーバの型
* B: 拡張関数名
* C: 拡張関数の型
* D: 拡張関数の本体(Body)
    * 関数内のthisキーワードはレシーバオブジェクトを指します。
    * レシーバオブジェクトのprivateやprotectedなメンバ、プロパティにはアクセスできません。

**用例**

拡張関数を定義した同一パッケージ内からはimportせずに使用できますが、パッケージ外から使用するにはimportする必要があります。

```kotlin
val result = 10.sum(20)
```

## レシーバ付き関数リテラル ([Function Literals with Receiver] (https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver))

レシーバ付き関数リテラルについて、こちらの[[Kotlin]レシーバー指定ラムダとは何か] (https://dev.classmethod.jp/smartphone/android/kotlin-lambdas/)、で詳しく説明されていてとても参考になりました。

下記はラムダ式の記法でレシーバ付き関数リテラルを記述しています。ラムダ内でレシーバオブジェクトのメンバを呼び出すことができます。

```kotlin
val sum: Int.(Int) -> Int = { other -> this + other }
//       ^^^ ^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^
//        |   |              |
//       (A) (B)            (C)

// 上記の書き方は次のように書くこともできます
val sum: Int.(Int) -> Int = { this + it }
```

* A: レシーバの型(Receiver Type)
* B: 関数の型
* C: ラムダ式
    * キーワードthisが指すのはレシーバオブジェクト。

下記は匿名関数の記法でレシーバ付き関数リテラルを記述しています。

```kotlin
val sum = fun Int.(other: Int): Int = this + other
//            ^^^ ^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^
//             |    |                  |
//            (A)  (B)                (C)
```

* A: レシーバの型(Receiver Type)
* B: 関数の型
* C: 関数の本体(Body)
    * キーワードthisが指すのはレシーバオブジェクト。

用例

```kotlin
val result = 5.sum(5)
```

## スコープ関数

スコープ関数について、こちらの [Kotlinのスコープ関数を使い分けたい] (http://nyanyoni.hateblo.jp/entry/2017/08/19/152200)、で詳しく説明されていてとても参考になりました。

その他の参考にした情報

* [The difference between Kotlin’s functions: ‘let’, ‘apply’, ‘with’, ‘run’ and ‘also’] (https://medium.com/@tpolansk/the-difference-between-kotlins-functions-let-apply-with-run-and-else-ca51a4c696b8)

Kotlinの標準ライブラリに[apply] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html)、[let] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/let.html)、[run] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/run.html)、[with] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/with.html)、[also] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/also.html)などの、一般的にスコープ関数と呼ばれる関数があります。

**下記の用例で使用しているResultクラス**

```kotlin
open class Result(_key: String, _name: String) {

    companion object {
        private const val ANON: String = "ANONYMOUS"
    }

    val key: String = _key.also { println("set key:$it") }
    val name: String = _name.also { println("set name:$it") }
    var amount: Int = 0
    private var oldAmount: Int = 0

    // secondary constructor
    constructor(_key: String, _amount: Int = 0): this(_key, ANON) {
        amount = _amount
    }

    fun change(newAmount: Int): Unit {
        oldAmount = amount
        amount = newAmount
    }

    override fun toString(): String {
        return "key:$key, name:$name, amount:$amount, oldAmount:$oldAmount"
    }

}
```

### also

レシーバ自体が戻り値となります。
レシーバに任意の名前を付けることができます。明示しなければitがレシーバを指します。

```text
inline fun <T> T.also(block: (T) -> Unit): T
```

**用例**

```kotlin
val result = Result("also", "Mitty").also { result ->
    // resultはレシーバ
    // println(this) // thisはインスタンス
    result.amount = 888
    result.change(777)
}
```

### apply

also関数とほぼ同じですが、レシーバに任意の名前を付けることはできず、thisがレシーバを指します。

```text
inline fun <T> T.apply(block: T.() -> Unit): T
```

**用例**

```kotlin
val result = Result("apply", "Mitty").apply {
    // thisはレシーバ
    this.amount = 999
    this.change(888)
}
```

### let

also関数とよく似ていますが、戻り値の型を選ぶことができ最後の式が戻り値となります。なのでUnit型を返すこともできます。
また、レシーバに任意の名前を付けることができます。

```text
inline fun <T, R> T.let(block: (T) -> R): R
```

**用例**

```kotlin
val result = Result("let", "Mitty").let { result ->
    // resultはレシーバ
    // println(this) //thisはインスタンス
    result.amount = 777
    result.change(666)
    result  // 戻り値はResult型
    // Unit // コメントを外すと戻り値の型はUnitになる
}
```

[Idioms] (https://kotlinlang.org/docs/reference/idioms.html#execute-if-not-null)で紹介されているlet関数の使い方として「レシーバがnullでない場合に任意の処理を実行する」というものがあります。

```kotlin
val strIsNullable: String? = null

try {
    //
    val strIsNotNull: String = strIsNullable?.let {
        it.toUpperCase()
    } ?: error("String must Not-NULL")
} catch (e: Exception) {
    println(e)
}
```

### run

apply関数とよく似ていますが、最後の式が戻り値となります。

```text
inline fun <T, R> T.run(block: T.() -> R): R
```

**用例**

```kotlin
val result = Result("run", "Mitty").run {
    // thisはレシーバ
    this.amount = 666
    this.change(555)
    this // 戻り値はResult型
}
```

run関数は2種類定義されていて、もう1つの定義はレシーバを持たず任意の型Rを返します。

```text
inline fun <R> run(block: () -> R): R
```

**用例**

トップレベルの関数定義でrun関数を使用するとこの定義が適用されます。
最後の式が戻り値となります。
またレシーバを持たないのでthisは参照できません。

```kotlin
fun getNow(): LocalDateTime = run {
  LocalDateTime.now()
}
```

```kotlin
val now = getNow()
```

### with

also、apply、let、runなどの関数とは異なり、第1引数にレシーバを取り、第2引数に第1引数のレシーバを持つ関数リテラルを取ります。
戻り値の型を選ぶことができ最後の式が戻り値となります。

```text
inline fun <T, R> with(receiver: T, block: T.() -> R): R
```

**用例**

```kotlin
val result = Result("with", "Mitty")
with(result) {
    // thisはレシーバ
    this.amount = 555
    this.change(444)
}
```

[Idioms] (https://kotlinlang.org/docs/reference/idioms.html#calling-multiple-methods-on-an-object-instance-with)で紹介されているwith関数の使い方として「レシーバオブジェクトの複数のメンバを呼び出す」というものがあります。


## その他の標準関数

### [Package kotlin] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/index.html)

#### [Functions] use

[use] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/use.html)関数は、AutoCloseableインターフェースを実装したクラスをレシーバに持つ拡張関数です。Java 1.7より実装された仕様`Try-with-resources`に相当する機能でリソースを自動的に閉じてくれます。

```text
inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R 
```

**用例**

```kotlin
val textLines = listOf("first line", "2nd line", "3rd line")

val file = File("newFile,txt").apply {
    if (exists()) delete()
}
FileOutputStream(file).use { writer ->
    textLines.forEach {
        writer.write(it)
        writer.writeln()
    }
}
```

#### [Functions] lazy

[lazy] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/lazy.html)関数は、ラムダ式でプロパティを遅延初期化します。
最初に参照したときにラムダ式が実行され、次回以降は最初の結果を返します。
初期化のコストが重く必ず参照されるか不定のプロパティの初期化に使用すると効果的です。

```text
fun <T> lazy(initializer: () -> T): Lazy<T>
```

**制約**

* varには使えません
* Nullable Typeに使えますが再代入できません。
 
**用例**

```kotlin
val dateTime: LocalDateTime = LocalDateTime.now()
val lazyDateTime: LocalDateTime by lazy { LocalDateTime.now() }

fun demoLazy() {
    println(LocalDateTime.now())
    // 2018-02-05T22:43:35.132

    Thread.sleep(1500)

    println(dateTime)
    // 2018-02-05T22:43:34.500
    println(lazyDateTime)
    // 2018-02-05T22:43:36.645

    Thread.sleep(1500)

    println(lazyDateTime)
    // 2018-02-05T22:43:36.645

    Thread.sleep(1500)

    println(LocalDateTime.now())
    // 2018-02-05T22:43:39.661
}
```


### [Package kotlin.text] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/index.html)

#### [Functions] buildString

[buildString] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/build-string.html)は、StringBuilderクラスの拡張関数です。

```
public inline fun buildString(builderAction: StringBuilder.() -> Unit): String
```

**用例**

```kotlin
val str =  buildString {
    append("first line", "\n")
    append("2nd line", "\n")
    append("3rd line", "\n")
}
println(str)
```


### [Package kotlin.collections] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index.html)

#### [Functions] onEach

[onEach] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/on-each.html)は、コレクションの各要素にラムダ式を適用し、そのコレクションを返します。Kotlin 1.1で追加されました。
ちなみにforEachは何も返しません。

```
inline fun <T, C : Iterable<T>> C.onEach(
    action: (T) -> Unit
): C
```


### [Package kotlin.properties] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/index.html)

#### [Functions] Delegates.notNull

[notNull] (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-delegates/not-null.html)関数は、lazy関数と同じようにプロパティの遅延初期化を行います。
lazy関数と違い、Not Nullで再代入可能なプロパティの初期化に使えます。
また、lateinit修飾子と同様に初期化前にアクセスすると例外をスローします。

```text
fun <T : Any> notNull(): ReadWriteProperty<Any?, T>
```

**制約**

* Nullable Typeには使えません
* 初期化前にアクセスすると例外をスローする

**用途**

```kotlin
var lazyInt by Delegates.notNull<Int>()

fun demoLazy() {
    // 初期化前にアクセスすると例外をスローする
    // println(lazyInt)

    lazyInt = 100
    println(lazyInt)
}
```

# プロパティ、変数の遅延初期化

[Late-Initialized Properties and Variables] (https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties-and-variables)

lateinit修飾子(modifier)でプロパティの初期化を遅延させることができます。

lateinit修飾子はクラス本体内のvarプロパティ、Kotlin 1.2以降ではトップレベルのプロパティ、およびローカル変数に使用できます。

**制限**

* valには使えません
* Nullable Typeには使えません
* Primitive Typesには使えません
* 初期化前にアクセスすると例外をスローする

**用例**

```kotlin
lateinit var lazyVar: String

// コンパイルエラー
// Property must be initialized or be abstract
// var lazyVar: String 

fun demoLazy() {
    lazyVar = "lazy variable is initialized."
    println(lazyVar)
}
```

初期化前にアクセスすると例外がスローされます。

```text
Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property lazyVar has not been initialized
```

Kotlin 1.2以降は、lateinit varプロパティが初期化されているか確認することが可能です。

```kotlin
if (::lazyVar.isInitialized) {
    println("lazyVar is initialized")
}
```