【和訳】Refactoring to Kotlin(Codelabs for the 2019 Android Dev Summit: Mountain View, October 23-24, 2019.)

[Android Dev Summit 2019
Codelabs for the 2019 Android Dev Summit: Mountain View, October 23-24, 2019.](https://codelabs.developers.google.com/ads19/)

[Refactoring to Kotlin](https://codelabs.developers.google.com/codelabs/java-to-kotlin/index.html?index=..%2F..ads19)の日本語訳

# 1.ようこそ！

 > [このコードラボは、中国語とブラジル系ポルトガル語でも利用可能です]

このコードラボでは、JavaからKotlinにリファクタリングする方法を学びます。また、Kotlin言語の規則とあなたが書いているコードがそれらに従うことを保証する方法についても学びます。

このコードラボは、プロジェクトをKotlinに移行することを検討しているJavaを使用している開発者に適しています。IDEを使用してKotlinに変換する事をいくつかのJavaクラスから始めます。次に、変換されたコードを見て、より慣用的にし、一般的な落とし穴を避けることでコードを改善する方法を確認します。

## 学ぶこと
JavaをKotlinにリファクタリングする方法を学習します。 そうすることで、次のKotlin言語の機能と概念を学習します。

- nullabilityの処理
- シングルトンの実装
- データクラス
- 文字列の処理
- エルビス演算子
- Destructuring
- プロパティとバッキングプロパティ
- デフォルトの引数と名前付きパラメーター
- コレクションを操作する
- 拡張関数
- ret, apply, with, run キーワード

## 想定
すでにJavaに精通している必要があります。

## 必要なもの
Android Studio 3.5またはIntelliJ IDEA

> Android Studio 3.6または4.0自動コンバーターは、異なる結果を作成する場合があります。そのため、このコードラボの目的でAndroid Studio 3.5を使用していることを確認してください。

# 2.セットアップ
## 新しいプロジェクトを作成する
IntelliJ IDEAを使用している場合は、Kotlin / JVMで新しいJavaプロジェクトを作成します。
Android Studioを使用している場合は、アクティビティのない新しいプロジェクトを作成します。

## コード
`User`モデルオブジェクトと、`User`オブジェクトと連携してユーザーおよびフォーマットされたユーザー名のリストを公開する`Repository`シングルトンクラスを作成します。
app.java/ <yourpackagename>の下に`User.java`という新しいファイルを作成し、次のコードを貼り付けます。

```java
public class User {

    private String firstName;
    private String lastName;

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}
```

`Repository.java`という新しいファイルを作成し、次のコードを貼り付けます。

```java
import java.util.ArrayList;
import java.util.List;


public class Repository {

    private static Repository INSTANCE = null;

    private List<User> users = null;

    public static Repository getInstance() {
        if (INSTANCE == null) {
            synchronized (Repository.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Repository();
                }
            }
        }
        return INSTANCE;
    }

    // keeping the constructor private to enforce the usage of getInstance
    private Repository() {

        User user1 = new User("Jane", "");
        User user2 = new User("John", null);
        User user3 = new User("Anne", "Doe");

        users = new ArrayList();
        users.add(user1);
        users.add(user2);
        users.add(user3);
    }

    public List<User> getUsers() {
        return users;
    }

    public List<String> getFormattedUserNames() {
        List<String> userNames = new ArrayList<>(users.size());
        for (User user : users) {
            String name;

            if (user.getLastName() != null) {
                if (user.getFirstName() != null) {
                    name = user.getFirstName() + " " + user.getLastName();
                } else {
                    name = user.getLastName();
                }
            } else if (user.getFirstName() != null) {
                name = user.getFirstName();
            } else {
                name = "Unknown";
            }
            userNames.add(name);
        }
        return userNames;
    }
}
```

# 3.nullability、val、var、およびdataクラスの宣言
IDEは、Javaコードを自動的にKotlinコードにリファクタリングするという非常に良い仕事をすることができますが、時には少し助けが必要です。最初にこれを行い、次にリファクタリングされたコードを調べて、この方法でリファクタリングされた方法と理由を理解します。

> Android Studio 3.6または4.0自動コンバーターは、異なる結果を作成する場合があります。そのため、このコードラボの目的でAndroid Studio 3.5を使用していることを確認してください。

`User.java`ファイルに移動して、それをKotlinに変換します。**Menu bar -> Code -> Convert Java File to Kotlin File**.
IDEが変換後に修正を求めるプロンプトを表示した場合、はいを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/278df099-19fd-276c-e6d3-cea869b7a276.png)

次のKotlinコードが表示されます。

```kotlin
class User(var firstName: String?, var lastName: String?)
```

`User.java`が`User.kt`に名前が変更されたことに注意してください。 Kotlinファイルの拡張子は.ktです。

> プロのヒント：JavaコードをKotlinファイルに貼り付けると、IDEは貼り付けられたコードを自動的にKotlinに変換します。

Java `User`クラスには、`firstName`と`lastNameの2つのプロパティがありました。それぞれにゲッターメソッドとセッターメソッドがあり、その値を可変にします。可変変数に対するKotlinのキーワードは`var`です。そのため、コンバーターはこれらの各プロパティに`var`を使用します。Javaプロパティにゲッターのみがある場合、それらは不変であり、`val`変数として宣言されていました。`val`は、Javaの`final`キーワードに似ています。

KotlinとJavaの主な違いの1つは、変数がnull値を受け入れることができるかどうかをKotlinが明示的に指定することです。これを行うには、型宣言に`「？」`を追加します。

Java `User`プロパティはnull値を受け入れることができるため、それぞれ`String？`でnull可能としてマークされます。Javaメンバーに*non-null*アノテーションを付ける場合（`org.jetbrains.annotations.NotNull`または`androidx.annotation.NonNull`）、コンバーターはこれを認識し、Kotlinのフィールドも*non-null*にします。

> プロのヒント：Kotlinでは、可能な限り不変オブジェクトを使用する（つまり、varの代わりにvalを使用する）ことをお勧めします。ヌルアビリティを意味のあるものにし、具体的に処理したいものに努力する必要があります。

基本的なリファクタリングはすでに行われています。 しかし、これをもっと慣用的な方法で書くことができます。方法を見てみましょう。

## データクラス
`User`クラスはデータのみを保持します。 Kotlinには、このロールを持つクラスのキーワードである`data`があります。このクラスを`data`クラスとしてマークすることにより、コンパイラは自動的にゲッターとセッターを作成します。また、`equals()`、`hashCode()`、および`toString()`関数も派生します。

`User`クラスに`data`キーワードを追加しましょう：

```kotlin
data class User(var firstName: String?, var lastName: String?)
```

Kotlinは、Javaと同様に、プライマリコンストラクターと1つ以上のセカンダリコンストラクターを持つことができます。上記の例の1つは、Userクラスのプライマリコンストラクターです。複数のコンストラクターを持つJavaクラスを変換する場合、コンバーターはKotlinでも複数のコンストラクターを自動的に作成します。それらは`constructor`キーワードを使用して定義されます。

> コンストラクターの詳細については、[公式ドキュメント](https://kotlinlang.org/docs/reference/classes.html#constructors)をご覧ください。

このクラスのインスタンスを作成する場合は、次のようにします。

```kotlin
val user1 = User("Jane", "Doe")
```

## 等しいこと
Kotlinには2種類の平等があります。

- 構造的平等では`==`演算子を使用し、`equals()`を呼び出して2つのインスタンスが等しいかどうかを判断します。
- 参照等価では、`===`演算子を使用して、2つの参照が同じオブジェクトを指しているかどうかを確認します。

データクラスのプライマリコンストラクターで定義されたプロパティは、構造的な同等性チェックに使用されます。

```kotlin
val user1 = User("Jane", "Doe")
val user2 = User("Jane", "Doe")
val structurallyEqual = user1 == user2 // true
val referentiallyEqual = user1 === user2 // false
```

> データクラスの詳細については、[公式ドキュメント](https://kotlinlang.org/docs/reference/data-classes.html#data-classes)をご覧ください。

# 4.デフォルト引数、名前付き引数
Kotlinでは、関数呼び出しの引数にデフォルト値を割り当てることができます。引数が省略された場合、デフォルト値が使用されます。Kotlinでは、コンストラクターも関数なので、デフォルトの引数を使用して、`lastName`のデフォルト値が`null`であることを指定できます。これを行うには、`lastName`に`null`を割り当てます。

```kotlin
data class User(var firstName: String?, var lastName: String? = null)

// usage
val jane = User ("Jane") // same as User("Jane", null)
val joe = User ("John", "Doe")
```

関数を呼び出すときに、関数パラメーターに名前を付けることができます。

```kotlin
val john = User (firstName = "John", lastName = "Doe") 
```

別のユースケースとして、`firstName`にはデフォルト値として`null`があり、`lastName`にはないとしましょう。この場合、デフォルトパラメータは、デフォルト値のないパラメータの前にあるため、名前付き引数で関数を呼び出す必要があります：

```kotlin
data class User(var firstName: String? = null, var lastName: String?)

// usage
val jane = User (lastName = "Doe") // same as User(null, "Doe")
val john = User ("John", "Doe")
```

> 関数に複数のパラメーターがある場合は、[名前付き引数](https://kotlinlang.org/docs/reference/functions.html?_ga=2.40893098.969837971.1560273584-565456768.1516189658#named-arguments)を使用するとコードが読みやすくなるため、使用を検討してください。

# 5.オブジェクトの初期化、コンパニオンオブジェクト、およびシングルトン
先に進む前に、*User*クラスが**data**クラスであることを確認してください。`Repository`クラスをKotlinに変換しましょう。自動変換の結果は次のようになります。

```kotlin
class Repository
// keeping the constructor private to enforce the usage of getInstance
private constructor() {

    private val users: MutableList<User>? = null

    val formattedUserNames: List<String>
        get() {
            val userNames = ArrayList<String>(users!!.size)
            for ((firstName, lastName) in users!!) {
                val name: String?

                if (lastName != null) {
                    if (firstName != null) {
                        name = "$firstName $lastName"
                    } else {
                        name = lastName
                    }
                } else if (firstName != null) {
                    name = firstName
                } else {
                    name = "Unknown"
                }
                userNames.add(name)
            }
            return userNames
        }

    init {

        val user1 = User("Jane", "")
        val user2 = User("John", null)
        val user3 = User("Anne", "Doe")

        users = ArrayList()
        users!!.add(user1)
        users!!.add(user2)
        users!!.add(user3)
    }

    fun getUsers(): List<User>? {
        return users
    }

    companion object {

        private var INSTANCE: Repository? = null

        val instance: Repository
            get() {
                if (INSTANCE == null) {
                    synchronized(Repository::class.java) {
                        if (INSTANCE == null) {
                            INSTANCE = Repository()
                        }
                    }
                }
                return INSTANCE
            }
    }
}
```

自動コンバーターが何をしたのか見てみましょう：

- `init`ブロックが追加されました（Repository.kt＃L33）
- `static`フィールドは、`companion object`ブロックの一部になりました（Repository.kt＃L51）
- オブジェクトは宣言時にインスタンス化されなかったため、`users`のリストはNULL可能です（Repository.kt＃L9）
- `getFormattedUserNames()`メソッドは、`formattedUserNames`（Repository.kt＃L11）というプロパティになりました。
- ユーザーのリストに対する反復の構文は、Javaの構文とは異なります（Repository.kt＃L14）

> **注**：生成されたコードはコンパイルされません。 心配する必要はありません。次のステップで変更します。

## 初期化ブロック
Kotlinでは、プライマリコンストラクターにコードを含めることはできないため、初期化コードはinitブロックに配置されます。 機能は同じです。

```kotlin
class Repository private constructor() {
    ...
    init {

        val user1 = User("Jane", "")
        val user2 = User("John", null)
        val user3 = User("Anne", "Doe")

        users = ArrayList()
        users!!.add(user1)
        users!!.add(user2)
        users!!.add(user3)
    }

}
```

`init`コードの多くは、プロパティの初期化を処理します。これは、プロパティの宣言でも実行できます。たとえば、`Repository`クラスのKotlinバージョンでは、usersプロパティが宣言で初期化されたことがわかります。

```kotlin
private val users: MutableList<User>? = null
```

> [公式ドキュメント](https://kotlinlang.org/docs/reference/classes.html#constructors)から初期化ブロックの詳細をご覧ください。

## Kotlinの`static`プロパティとメソッド
Javaでは、フィールドまたは関数に`static`キーワードを使用して、クラスのインスタンスではなくクラスに属していることを示します。これが、`Repository`クラスに`INSTANCE`静的フィールドを作成した理由です。これに対応するKotlinは、`companion object`ブロックです。 ここでは、静的フィールドと静的関数も宣言します。コンバーターは、`INSTANCE`フィールドを作成して、ここに移動しました。

## シングルトンの処理
`Repository`クラスのインスタンスは1つしか必要ないため、Javaで[シングルトンパターン](https://en.wikipedia.org/wiki/Singleton_pattern)を使用しました。Kotlinを使用すると、`class`キーワードを`object`に置き換えることで、コンパイラレベルでこのパターンを適用できます。
プライベートコンストラクターとコンパニオンオブジェクトを削除し、クラス定義を`object Repository`に置き換えます。

```kotlin
object Repository {

    private val users: MutableList<User>? = null

    val formattedUserNames: List<String>
        get() {
            val userNames = ArrayList<String>(users!!.size)
            for ((firstName, lastName) in users!!) {
                val name: String?

                if (lastName != null) {
                    if (firstName != null) {
                        name = "$firstName $lastName"
                    } else {
                        name = lastName
                    }
                } else if (firstName != null) {
                    name = firstName
                } else {
                    name = "Unknown"
                }
                userNames.add(name)
            }
            return userNames
        }

    init {

        val user1 = User("Jane", "")
        val user2 = User("John", null)
        val user3 = User("Anne", "Doe")
        users = ArrayList()
        users!!.add(user1)
        users!!.add(user2)
        users!!.add(user3)
    }

    fun getUsers(): List<User>? {
        return users
    }
}
```

`object`クラスを使用する場合、次のように、オブジェクトに対して関数とプロパティを直接呼び出します。

```kotlin
val users = Repository.users
```

> オブジェクトとコンパニオンオブジェクトの詳細については、[公式ドキュメント](https://kotlinlang.org/docs/tutorials/kotlin-for-py/objects-and-companion-objects.html)をご覧ください。

## Destructuring
Kotlinでは、構造化宣言と呼ばれる構文を使用して、オブジェクトをいくつかの変数に構造化できます。複数の変数を作成し、それらを個別に使用できます。
たとえば、*data*クラスは構造化をサポートしているため、自動コンバーターは`for`ループで`User`オブジェクトを構造化しました。これにより、`firstName`および`lastName`の値を直接操作できます。


```kotlin
for ((firstName, lastName) in users!!) {
       val name: String?

       if (lastName != null) {
          if (firstName != null) {
                name = "$firstName $lastName"
          } 
       ...
```

> [公式ドキュメント](https://kotlinlang.org/docs/reference/multi-declarations.html)で宣言のdestructuringについて詳しく読んでください。

# 6. nullabilityの処理
`Repository`クラスをKotlinに変換する場合、自動コンバータは、宣言時にオブジェクトに初期化されなかったため、ユーザーのリストをnull可能にしました。`users`オブジェクトのすべての使用法について、not-null アサーション演算子`!!`が使用されている。変数をnull以外の型に変換し、値がnullの場合は例外をスローします。 `!!`を使用すると、実行時に例外がスローされる危険があります。
代わりに、次の方法のいずれかを使用してヌル可能性を処理することを好みます。

- nullチェックを行う（if（users！= null）{...}）
- [elvis演算子](https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator)の使用`?:`（コードラボで後述）
- Kotlin標準関数の一部を使用（コードラボで後ほど説明）

> [公式ドキュメント](https://kotlinlang.org/docs/reference/null-safety.html#null-safety)からヌルの安全性に関する詳細をご覧ください。

この場合、ユーザーのリストはNULL値を許可する必要はありませんが、オブジェクトが構築された直後に初期化されるため、宣言時にオブジェクトを直接インスタンス化できます。
コレクションタイプのインスタンスを作成する場合、Kotlinはコードをより読みやすく柔軟にするためのいくつかのヘルパー関数を提供します。ここでは、`users`に`MutableList`を使用しています。

```kotlin
private val users: MutableList<User>? = null
```

簡単にするために、`mutableListOf()`関数を使用できます。リスト要素タイプを提供し、`init`ブロックから`ArrayList`コンストラクター呼び出しを削除し、usersプロパティの明示的な型宣言を削除します。

```kotlin
private val users = mutableListOf<User>()
```

この変更により、`users`プロパティはnullでなくなり、`!!`演算子の出現で不要なものをすべて削除できます。また、ユーザー変数は既に初期化されているため、`init`ブロックから初期化を削除する必要があります。

```kotlin
init {

    val user1 = User("Jane", "")
    val user2 = User("John", null)
    val user3 = User("Anne", "Doe")

    users.add(user1)
    users.add(user2)
    users.add(user3)
}
```

`lastName`と`firstName`の両方が`null`になる可能性があるため、フォーマットされたユーザー名のリストを作成するときにnullを処理する必要があります。自動コンバーターは名前変数をnull可能にしましたが、いずれかの名前が欠落している場合は`"Unknown"`を表示したいので、型宣言から`?`を削除することで名前をnull以外にできます。

```kotlin
val name: String
```

`lastName`がnullの場合、`name`は`firstName`または`"Unknown"`のいずれかです。

```kotlin
if (lastName != null) {
    if (firstName != null) {
        name = "$firstName $lastName"
    } else {
        name = lastName
    }
} else if (firstName != null) {
    name = firstName
} else {
    name = "Unknown"
}
```

これは、elvis演算子`?:`を使用して、より慣用的に記述することができます。elvis演算子は、nullでない場合は左辺の式を返し、左辺がnullの場合は右辺の式を返します。
したがって、次のコードでは、`user.firstName`がnullでない場合に返されます。`user.firstName`がnullの場合、式は右側の値`"Unknown"`を返します。

```kotlin
if (lastName != null) {
    ...
} else {
    name = firstName ?: "Unknown"
}
```

> [公式ドキュメント](https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator)でelvisオペレーターの詳細をお読みください。

# 7.文字列テンプレートとif式
Kotlinでは、[String templates](https://kotlinlang.org/docs/reference/basic-syntax.html#using-string-templates)を使用して文字列を簡単に操作できます。文字列テンプレートを使用すると、文字列宣言内の変数を参照できます。
自動コンバーターは、`$`記号を使用してストリング内の変数名を直接参照し、式を`{}`の間に置くことで、姓と名の連結を更新しました。

```kotlin
// Java
name = user.getFirstName() + " " + user.getLastName();

// Kotlin
name = "${user.firstName} ${user.lastName}"
```

コードで、文字列連結を次のように置き換えます。

```kotlin
name = "$firstName $lastName"
```

Kotlinでは、`if`、`when`、`for`、`while`が式であり、値を返します。IDEは、割り当てを`if`から外す必要があるという警告も表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/b83df096-0959-7d14-ffec-281f6a504657.png)
IDEの提案に従って、両方の`if`ステートメントの割り当てを解除しましょう。`if`ステートメントの最後の行が割り当てられます。このように、このブロックの唯一の目的が名前の値を初期化することであることはより明確です。

```kotlin
name = if (firstName != null) {
      // do something
      firstName 
  }
// name = firstName 
```

> `if`ステートメントから割り当てを解除すると、簡単に悪用される可能性があります。`if`ブロックに1つの役割のみがあり、他の副作用がないことを確認してください。

次に、`name`宣言を割り当てと結合できるという警告が表示されます。 これも適用してみましょう。名前変数の型を推測できるため、明示的な型宣言を削除できます。次に、`formattedUserNames`は次のようになります。

```kotlin
val formattedUserNames: List<String>
        get() {
            val userNames = ArrayList<String>(users.size)
            for ((firstName, lastName) in users) {
                val name = if (lastName != null) {
                    if (firstName != null) {
                        "$firstName $lastName"
                    } else {
                        lastName
                    }
                } else {
                    firstName ?: "Unknown"
                }

                userNames.add(name)
            }
            return userNames
        }
```

> [公式ドキュメント](https://kotlinlang.org/docs/reference/control-flow.html#if-expression)で`if`、`when`、`for`、`while`の詳細を読んでください。

# 8.コレクションの操作
`formattedUserNames`ゲッターを詳しく見て、それをもっと慣用的にする方法を見てみましょう。現在、コードは次のことを行います。

- 文字列の新しいリストを作成します
- ユーザーのリストを反復処理します
- ユーザーの名と姓に基づいて、各ユーザーの書式設定された名前を作成します
- 新しく作成されたリストを返します

```kotlin
val formattedUserNames: List<String>
        get() {
            val userNames = ArrayList<String>(users.size)
            for ((firstName, lastName) in users) {
                val name = if (lastName != null) {
                    if (firstName != null) {
                        "$firstName $lastName"
                    } else {
                        lastName
                    }
                } else {
                    firstName ?: "Unknown"
                }

                userNames.add(name)
            }
            return userNames
        }
```

Kotlinは、Java Collections APIの機能を拡張することにより、開発をより迅速かつ安全にする[コレクション変換](https://kotlinlang.org/docs/reference/collection-transformations.html)の広範なリストを提供します。それらの1つは[マップ](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map.html)機能です。この関数は、指定された変換関数を元の配列の各要素に適用した結果を含む新しいリストを返します。そのため、新しいリストを作成してユーザーのリストを手動で繰り返す代わりに、 `map`関数を使用して、forループ内のロジックを` map`本体内に移動できます。デフォルトでは、 `map`で使用される現在のリスト項目の名前は` it`ですが、読みやすくするために、独自の変数名に置き換えることができます。この例では、`user`に名前を付けましょう。

```kotlin
val formattedUserNames: List<String>
        get() {
            return users.map { user ->
                val name = if (user.lastName != null) {
                    if (user.firstName != null) {
                        "${user.firstName} ${user.lastName}"
                    } else {
                        user.lastName ?: "Unknown"
                    }
                }  else {
                    user.firstName ?: "Unknown"
                }
                name
            }
        }
```

これをさらに単純化するために、 `name`変数を完全に削除できます：

```kotlin
val formattedUserNames: List<String>
        get() {
            return users.map { user ->
                if (user.lastName != null) {
                    if (user.firstName != null) {
                        "${user.firstName} ${user.lastName}"
                    } else {
                        user.lastName ?: "Unknown"
                    }
                }  else {
                    user.firstName ?: "Unknown"
                }
            }
        }
```

> コレクションの変換だけでなく、Kotlin Standard Libraryは[コレクション](https://kotlinlang.org/docs/reference/collections-overview.html)を管理するための幅広いツールを提供します。さまざまなコレクションタイプから、一般的な `Collection`タイプまたは` List`や `Set`などのさまざまなサブタイプに固有のさまざまな[操作](https://kotlinlang.org/docs/reference/collection-operations.html)まで。一般に、コレクションを操作するときは、Kotlinでの書き込みを計画している機能が標準ライブラリによって既に実装されているかどうかを確認し、独自の実装でその機能を使用することを選択してください。

# 9.プロパティとバッキングプロパティ
自動コンバーターが`getFormattedUserNames()`関数を、カスタムgetterを持つ`formattedUserNames`と呼ばれるプロパティに置き換えていることがわかりました。 内部では、Kotlinは`List`を返す`getFormattedUserNames()`メソッドを生成します。
Javaでは、getterおよびsetter関数を介してクラスプロパティを公開します。
Kotlinを使用すると、フィールドで表現されたクラスのプロパティと、機能で表現された機能、クラスで実行可能なアクションをより適切に区別できます。この場合、Repositoryクラスは非常にシンプルで、アクションを実行しないため、フィールドのみがあります。
`formattedUserNames`Kotlinプロパティのgetterを呼び出すときにJavaでトリガーされたロジックの`getFormattedUserNames()`関数がトリガーされるようになりました。
`formattedUserNames`プロパティに対応するフィールドは明示的にありませんが、
Kotlinは、必要に応じてカスタムgetterおよびsetterからアクセスできるfieldという名前の自動バッキングフィールドを提供します。
ただし、自動バッキングフィールドにはない追加機能が必要な場合があります。 以下の例を見てみましょう。
Repositoryクラス内には、Javaコードから生成されたgetUsers関数で公開されているユーザーの可変リストがあります。

```kotlin
fun getUsers(): List<User>? {
    return users
}
```
ここでの問題は、ユーザーを返すことにより、Repositoryクラスのすべてのコンシューマーがユーザーのリストを変更できることです。 バッキングプロパティを使用してこれを修正しましょう。
まず、ユーザーの名前を_usersに変更しましょう。
次に、ユーザーのリストを返すパブリックの不変のプロパティを追加します。 それをユーザーと呼びましょう：

```kotlin
private val _users = mutableListOf<User>()
val users: List<User>
      get() = _users
```

この変更により、プライベート`_users`プロパティがパブリック`users`プロパティのバッキングプロパティになります。`Repository`クラスの外部では、`_users`リストは変更できません。クラスのコンシューマーは`users`を介してのみリストにアクセスできるためです。

> バッキングプロパティの規則では、先頭にアンダースコアを使用します。
> [公式ドキュメント](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields)からプロパティの詳細をご覧ください。

Full code:

```kotlin
object Repository {

    private val _users = mutableListOf<User>()
    val users: List<User>
        get() = _users

    val formattedUserNames: List<String>
        get() {
            return _users.map { user ->
                if (user.lastName != null) {
                    if (user.firstName != null) {
                        "${user.firstName} ${user.lastName}"
                    } else {
                        user.lastName ?: "Unknown"
                    }
                }  else {
                    user.firstName ?: "Unknown"
                }
            }
        }

    init {

        val user1 = User("Jane", "")
        val user2 = User("John", null)
        val user3 = User("Anne", "Doe")

        _users.add(user1)
        _users.add(user2)
        _users.add(user3)
    }
}
```

# 10.トップレベルおよび拡張機能とプロパティ
現在、`Repository`クラスは、`User`オブジェクトのフォーマットされたユーザー名を計算する方法を知っています。ただし、他のクラスで同じフォーマットロジックを再利用する場合は、コピーして貼り付けるか、`User`クラスに移動する必要があります。
Kotlinは、クラス、オブジェクト、またはインターフェースの外部で関数とプロパティを宣言する機能を提供します。たとえば、リストの新しいインスタンスを作成するために使用した`mutableListOf()`関数は、標準ライブラリの[Collections.kt](https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/collections/Collections.kt#L90)で直接定義されます。
Javaでは、ユーティリティ機能が必要な場合はいつでも、`Util`クラスを作成し、その機能を静的関数として宣言する可能性が高くなります。Kotlinでは、クラスを持たずにトップレベルの関数を宣言できます。Kotlinはまた、拡張機能を作成する機能も提供します。これらは特定の型を拡張する関数ですが、型の外部で宣言されています。そのため、それらはそのタイプに類似しています。

> クラスを所有していないか、継承に対して開かれていないため、クラスの機能を拡張するには、Kotlinは、拡張機能と呼ばれる特別な宣言を作成します。Kotlinは、拡張機能と拡張プロパティをサポートしています。

拡張機能とプロパティの可視性は、可視性修飾子を使用して制限できます。これらは、拡張を必要とするクラスにのみ使用を制限し、名前空間を汚染しません。

Userクラスの場合、フォーマットされた名前を計算する拡張関数を追加するか、フォーマットされた名前を拡張プロパティに保持できます。リポジトリクラスの外部の同じファイルに追加できます。

```kotlin
// extension function
fun User.getFormattedName(): String {
    return if (lastName != null) {
        if (firstName != null) {
            "$firstName $lastName"
        } else {
            lastName ?: "Unknown"
        }
    } else {
        firstName ?: "Unknown"
    }
}

// extension property
val User.userFormattedName: String
    get() {
        return if (lastName != null) {
            if (firstName != null) {
                "$firstName $lastName"
            } else {
                lastName ?: "Unknown"
            }
        } else {
            firstName ?: "Unknown"
        }
    }

// usage:
val user = User(...)
val name = user.getFormattedName()
val formattedName = user.userFormattedName
```

その後、拡張機能とプロパティを`User`クラスの一部であるかのように使用できます。
フォーマットされた名前はユーザーのプロパティであり、`Repository`クラスの機能ではないため、拡張プロパティを使用しましょう。`Repository`ファイルは次のようになります。

```kotlin
val User.formattedName: String
    get() {
        return if (lastName != null) {
            if (firstName != null) {
                "$firstName $lastName"
            } else {
                lastName ?: "Unknown"
            }
        } else {
            firstName ?: "Unknown"
        }
    }

object Repository {

    private val _users = mutableListOf<User>()
    val users: List<User>
      get() = _users

    val formattedUserNames: List<String>
        get() {
            return _users.map { user -> user.formattedName }
        }

    init {

        val user1 = User("Jane", "")
        val user2 = User("John", null)
        val user3 = User("Anne", "Doe")

        _users.add(user1)
        _users.add(user2)
        _users.add(user3)
    }
}
```

[Kotlin標準ライブラリ](https://kotlinlang.org/api/latest/jvm/stdlib/index.html)は、拡張関数を使用していくつかのJava APIの機能を拡張します。`Iterable`および`Collection`の多くの機能は、拡張機能として実装されています。たとえば、前の手順で使用したマップ関数は、`Iterable`の拡張関数です。

# 11.スコープ関数：let、apply、with、run、also
`Repository`クラスコードでは、いくつかのユーザーオブジェクトを`_users`リストに追加しています。これらの呼び出しは、スコープ関数の助けを借りてより慣用的にすることができます。
名前に基づいてオブジェクトにアクセスする必要なく、特定のオブジェクトのコンテキストでのみコードを実行するために、Kotlinは5つのスコープ関数`let`、`apply`、`with`、`run`、`also`を作成しました。短く強力なこれらの関数はすべて、レシーバー（`this`）を持ち、引数（`it`）を持ち、値を返すことがあります。達成したい内容に応じて、どれを使用するかを決定します。

これを覚えるのに役立つ便利なチートシートを次に示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170755/38c29e88-7f50-c6ad-be4b-6d41e7239095.png)

> [ここ](https://medium.com/androiddevelopers/kotlin-standard-functions-cheat-sheet-27f032dd4326)からスコープ機能のチートシートをダウンロードしてください。

`Repository`で`_users`オブジェクトを構成しているため、`apply`関数を使用してコードをより慣用的にすることができます。

```kotlin
init {
    val user1 = User("Jane", "")
    val user2 = User("John", null)
    val user3 = User("Anne", "Doe")
   
    _users.apply {
       // this == _users
       add(user1)
       add(user2)
       add(user3)
    }
```

> [公式ドキュメント](https://kotlinlang.org/docs/reference/scope-functions.html)からスコープ関数の詳細をご覧ください。

# 12.まとめ
このコードラボでは、JavaからKotlinへのコードのリファクタリングを開始するために必要な基本について説明しました。このリファクタリングは開発プラットフォームに依存せず、記述するコードが慣用的であることを保証するのに役立ちます。
慣用的なKotlinを使用すると、コードを短く簡潔に書くことができます。Kotlinが提供するすべての機能を使用すると、コードをより安全で簡潔で読みやすくするための方法がたくさんあります。たとえば、`_users`リストを宣言で直接ユーザーでインスタンス化し、`init`ブロックを削除することで、`Repository`クラスを最適化することもできます。

```kotlin
private val users = mutableListOf(User("Jane", ""), User("John", null), User("Anne", "Doe"))
```

nullability、シングルトン、文字列、コレクションの処理から、拡張機能、トップレベル機能、プロパティ、スコープ機能などのトピックまで、幅広いトピックを取り上げました。2つのJavaクラスから、次のような2つのKotlinクラスに移行しました。

```User.kt
class User(var firstName: String?, var lastName: String?)
```

```Repository.kt
val User.formattedName: String
    get() {
       return if (lastName != null) {
            if (firstName != null) {
                "$firstName $lastName"
            } else {
                lastName ?: "Unknown"
            }
        } else {
            firstName ?: "Unknown"
        }
    }

object Repository {

    private val _users = mutableListOf(User("Jane", ""), User("John", null), User("Anne", "Doe"))
    val users: List<User>
        get() = _users

    val formattedUserNames: List<String>
        get() = _users.map { user -> user.formattedName }
}
```

Java機能のTL; DRと、Kotlinへのマッピングを次に示します。

| Java | Kotlin | 
| :--- | :--- |
| final object | val object |
| equals() | == |
| == | === |
| Class that just holds data | data class |
| Initialization in the constructor | Initialization in the init block |
| static fields and functions | fields and functions declared in a companion object |
| Singleton class | object |

Kotlinの詳細とプラットフォームでのKotlinの使用方法については、次のリソースをご覧ください。

- [Kotlin Koans](https://play.kotlinlang.org/koans/overview)
- [Kotlin Tutorials](https://kotlinlang.org/docs/tutorials/)
- [Developing Android apps with Kotlin](https://www.udacity.com/course/developing-android-apps-with-kotlin--ud9012) - free course
- [Kotlin Bootcamp for Programmers](https://developer.android.com/courses/kotlin-bootcamp/overview)
- [https://www.coursera.org/learn/kotlin-for-java-developers](https://www.coursera.org/learn/kotlin-for-java-developers) - free course in Audit mode