Effective Java を Kotlin で読む（１）：第2章 オブジェクトの生成と消滅

![effectivekotlin.png](https://qiita-image-store.s3.amazonaws.com/0/191059/5d874c04-211c-ebca-da5e-5d1a4746517d.png)

# はじめに
対象読者は以下の想定。

- Java, Kotlin をなんとなく使える
- Effective Java の内容をなんとなく知っている

勉強中なので、つっこみ大歓迎です。

# 概要
- 良い Kotlin コードが書きたい！
- Kotlin は _"100% interoperable with Java"_
 - Javaの良いコード = Kotlinの良いコード？
- Javaエンジニアの必読書 _Effective Java_
 - Kotlin Language Documentation でも度々言及されてる
 - https://kotlinlang.org/docs/kotlin-docs.pdf

Kotlin を知った上で Effective Java の各項目を総復習する👆 

# 基本方針

Effective Java 第2版（[目次](http://www001.upp.so-net.ne.jp/yshibata/ej2e_toc.pdf)）を元にする。

- 全11章78項目一通り触れる（第1章「はじめに」は除く）
- 項目毎に概要をまとめる
- Kotlin で良い手段が提供されていれば紹介
- 特になければ Kotlin でのサンプルコードを載せる

# 章目次

[Effective Java を Kotlin で読む（１）：第2章 オブジェクトの生成と消滅](https://qiita.com/ref3000/items/7c896b45c54f1086f0a9) 👈この記事
[Effective Java を Kotlin で読む（２）：第3章 すべてのオブジェクトに共通のメソッド](https://qiita.com/ref3000/items/0dba04cdcb32b7debdb6)
[Effective Java を Kotlin で読む（３）：第4章 クラスとインタフェース](https://qiita.com/ref3000/items/a6eaf0fb8740ac2aebd3)
[Effective Java を Kotlin で読む（４）：第5章 ジェネリックス](https://qiita.com/ref3000/items/4e0c57f67c905a81fa0a)
[Effective Java を Kotlin で読む（５）：第6章 enum とアノテーション](https://qiita.com/ref3000/items/8ea7008007b8eea315dc)
[Effective Java を Kotlin で読む（６）：第7章 メソッド](https://qiita.com/ref3000/items/9a588356dd8a8879d6a6)
[Effective Java を Kotlin で読む（７）：第8章 プログラミング一般](https://qiita.com/ref3000/items/2d458044fc5a4309de06)
Effective Java を Kotlin で読む（８）：第9章 例外
Effective Java を Kotlin で読む（９）：第10章 並行性
Effective Java を Kotlin で読む（１０）：第11章 シリアライズ

# 第2章 オブジェクトの生成と消滅

## 項目1 コンストラクタの代わりに static ファクトリーメソッドを検討する

### 概要
インスタンス生成に static ファクトリーメソッドを使えないか検討すると良い。
なぜなら以下のような長所があるから。

- 名前をつけられる為可読性が良くなる
- オブジェクトを新たに生成しなくて良い場合がある
- 任意のサブタイプのオブジェクトを返せる

### Kotlin で読む

Java の static メソッドは、 Kotlin において [top level function](https://kotlinlang.org/docs/reference/functions.html#function-scope) や [object 宣言](https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations) などに相当する。

ファクトリーメソッドである、標準ライブラリの [listOf](https://github.com/JetBrains/kotlin/blob/1.2.60/libraries/stdlib/src/kotlin/collections/Collections.kt#L76) の実装を見てみる。

```kotlin
public fun <T> listOf(vararg elements: T): List<T>
  = if (elements.size > 0) elements.asList() else emptyList()
```

top level function として実装されており、サイズ 0 以下の時は生成済みの空のリストを使いまわす事でオブジェクトを不要に生成しない工夫が見て取れる。

任意のサブタイプのオブジェクトを返すクラスは Kotlin ならこのように書ける。

```kotlin
interface Service {
    val name: String
}
class HogeService : Service {
    override val name = "hoge"
}
class FugaService : Service {
    override val name = "fuga"
}

object Services {
  fun newHogeInstance(): Service = HogeService()
  fun newFugaInstance(): Service = FugaService()
}
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/psfiqnvrk9q4lskevcf8aolqj3)

Kotlin はインタフェースがプロパティ持てて良いですね。

## 項目2 数多くのコンストラクタパラメータに直面した時にはビルダーを検討する

### 概要
Javaでのインスタンス作成では、伝統的に **テレスコーピングコンストラクタ・パターン** や **JavaBeansパターン** が使われるが、パラメータ数が多くなると問題が出てくる。そこで、**ビルダーパターン**を使うか検討すると良い。

それぞれのパターンについて Java での例を挙げる。

**【テレスコーピングコンストラクタ・パターン】**

```java
public class Hoge {
  private int a, b, c;

  Hoge(int a) {
    this(a, 222, 333);
  }
  Hoge(int a, int b) {
    this(a, b, 333);
  }
  Hoge(int a, int b, int c) {
    this.a = a; this.b = b; this.c = c;
  }
  // getter 省略
}
```

- コードが冗長
- コンストラクタの意味が分かり辛い

**【JavaBeans パターン】**

```java
public class Hoge {
  private int a;
  private int b = 222;
  private int c = 333;

  public setA(int a) { this.a = a; }
  public setB(int b) { this.b = b; }
  public setC(int c) { this.c = c; }
  // getter 省略
}
```

- 生成途中で不整合な状態になる場合がある
- イミュータブル（不変）である可能性を排除してしまう

**【ビルダーパターン】**

```java
public class Hoge {
  private int a, b, c;

  public static class Builder {
    private int a;
    private int b = 222;
    private int c = 333;

    public Builder(int a) {
      this.a = a;
    }
    public Builder B(int b) {
      this.b = b; return this;
    }
    public Builder C(int c) {
      this.c = c; return this;
    }
    public Hoge build() {
      return new Hoge(this);
    }
  }

  private Hoge(Builder builder) {
    a = builder.a;
    b = builder.b;
    c = builder.c;
  }
  // getter 省略
}

// こう使う
Hoge hoge = new Hoge.Builder(1).B(2).build();
hoge.getB() // 2
hoge.getC() // 333
```

ビルダーパターンにより

- 可読性の向上
- 中間状態の排除

のような利点が得られるが

- コードが冗長
- ビルダー生成にコストがかかる

のような欠点も持っている。

Java では、これらのパターンを場合によって使い分けていた。

### Kotlin で読む

Kotlin の場合、

- デフォルト引数
 - テレスコーピングパターンの冗長性を排除
- 名前付き変数
 - 可読性向上！

以上の構文を用いて、簡潔に可読性の高いインスタンス生成が可能になっている。

```kotlin
class Hoge(
  val a: Int,
  val b: Int = 222,
  val c: Int = 333
)

// 例1: Hoge(1, 2, 3)
// 例2: Hoge(1)
// 例3: Hoge(a = 1, b = 22)
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/5tv4jpaunue13nsov26ockiqdt)

Java から呼び出す場合も `@JvmOverloads` を利用することで、コードの冗長性を排除しつつテレスコーピングパターンを実現可能。

```kotlin
class Hoge @JvmOverloads constructor(
  val a: Int,
  val b: Int = 222,
  val c: Int = 333
)
```

```java
// java からはこう呼べる
Hoge h1 = new Hoge(1);
Hoge h2 = new Hoge(11, 22);
Hoge h3 = new Hoge(111, 222, 333);
```

また、既存のJavaBeans パターンのクラスに対しても `apply` を用いることで、Builder パターンのように利用することができる。

```kotlin
val hoge = Hoge().apply {
  a = 1
  b = 2
  c = 3
}
```

Kotlin では、旧来の Builder パターンのクラスを自分で書く事は無さそうに思う。

## 項目3 private のコンストラクタか enum 型でシングルトン特性を強制する


### 概要
[シングルトン](https://ja.wikipedia.org/wiki/Singleton_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)：一度しかインスタンスが作成されないクラス

Java では言語機能としてシングルトンが提供されている訳ではないので、工夫して実装する事が求められる。

書籍では、単一要素の enum 型を利用する事が最善の実装であると結論付けている。

### Kotlin で読む
Kotlin では object を使おう。

```kotlin
object Singleton {
  fun hello() {
    println("hello")
  }
}

// こう使う
Singleton.hello()
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/7rnr03k3d2eijau1ns34b2og7k)

```java
// java から呼ぶ場合
Singleton.INSTANCE.hello();
```

（`@JvmStatic` を付ければ `INSTANCE` は省略可能）
[Calling Java code from Kotlin#Static Methods](https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#static-methods)

## 項目4 private のコンストラクタでインスタンス化不可能を強制する

### 概要
時折、ユーティリティクラスのような static なメソッドとフィールドのみのクラスを作りたくなる事がある。

このようなクラスはインスタンス化する必要はないが、Java ではコンストラクタを明示しない場合デフォルトコンストラクタが作成されインスタンス化可能になってしまう。

private コンストラクタを明示的に書き、インスタンス不可能を強制すべし。

### Kotlin で読む
[object 宣言](https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations) でシングルトンにするか
[top level function](https://kotlinlang.org/docs/reference/functions.html#function-scope) を使おう。

```kotlin

object UtilityClass {
  fun hoge() = "hoge"
}

fun fugaUtilityFunc() = "fuga"

// こう使う
UtilityClass.hoge()
fugaUtilityFunc()
```

_Kotlinの関数はクラスに属する必要はない_

また、[拡張関数](https://kotlinlang.org/docs/reference/extensions.html#extension-functions)を用いて特定のクラスのインスタンスに紐づくユーティリティを表現するのも良さそう。

```kotlin
fun String.print() = print(this)

// こう使う
"hoge".print()
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/i3505eotounjfcb9sqkpqg2hj4)

## 項目5 不必要なオブジェクトの生成を避ける

### 概要
オブジェクト生成にはコストがかかるので、可能であれば同じオブジェクトを使い回すべき。

大きく以下の点を意識する。

- 不変オブジェクトの再利用
- 変更されない可変オブジェクトの再利用
- （意図しない）オートボクシング

### Kotlin で読む
**【不変オブジェクトの再利用】**

`項目 1 コンストラクタの代わりに static ファクトリーメソッドを検討する`
で行ったように、不変オブジェクトを再利用する事ができる。

```kotlin
public fun <T> listOf(vararg elements: T): List<T>
  = if (elements.size > 0) elements.asList() else emptyList()
```

**【変更されない可変オブジェクトの再利用】**

メソッド呼び出し毎に可変オブジェクトを利用する場合、再利用できるか検討する。

- 悪い例

メソッド呼び出し毎にオブジェクトが生成される

```kotlin
/** date が2000年以降であるか判定する */
fun isAfterMillennium(date: Date): Boolean {
  val gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")).apply {
    set(2000, Calendar.JANUARY, 1, 0, 0, 0)   
  }
  return date > gmtCal.time
}
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/fil69b4hmigarhb9rdgno0ks5v)

- 良い例

```kotlin
private val gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")).apply {
  set(2000, Calendar.JANUARY, 1, 0, 0, 0)
}

/** date が2000年以降であるか判定する */
fun isAfterMillennium2(date: Date): Boolean {
  return date > gmtCal.time
}
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/9rmirkj4btvjk0gqh41bacm62l)

**【（意図しない）オートボクシング】**

Kotlin で数値型は[基本的に原型、必要な場合のみ参照型として扱われる](https://kotlinlang.org/docs/reference/basic-types.html#representation)為、意図しないオートボクシングによる不要なオブジェクトの生成は行われない！

- Java の場合

```java
Long sum = 0L;
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
  sum += i // ここでオートボクシングが発生！
}
System.out.println(sum);
```

- Kotlin の場合

```kotlin
var sum: Long = 0L
for (i in 0..Integer.MAX_VALUE.toLong()) {
  sum += i // primitive 型同士
}
println(sum)
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/vmnlnt7v8atudgajar8ito1fpk)

ところで具体的には

- Nullable 型
- ジェネリクスの型引数

等のように、原型が利用できない場合にのみ参照型として扱われる。
そのため以下のようにすると Kotlin でもボクシングを起こす事が可能。

```kotlin
var sum: Long? = 0L
for (i in 0..Integer.MAX_VALUE.toLong()) {
  sum = sum?.plus(i)
}
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/8dhjoekmofkffan5fqgpdgraic)

ちなみに Try Kotlin 上でボクシングしない場合と比較してみた所、こちらが5倍ほど遅かった。

## 項目6 廃れたオブジェクト参照を取り除く

### 概要

メモリリークを回避するため、廃れたオブジェクト参照を取り除く事で GC が適切に働くようにすべき。

- 不要な参照に null　を設定する
- 弱参照を利用する

等を意識する必要がある。

### Kotlin で読む
**【不要な参照に null　を設定する】**

Kotlin でも Java 同様メモリリークは起こる。独自のメモリ管理機構を作る場合は要注意。

```kotlin
class StringStack {
  val elements = Array<String?>(1024) { null }
  var size = 0
    
  fun push(e: String?) {
    elements[size++] = e
  }
  fun pop() = elements[--size]
}
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/v8snunuoca9bh0g8o0gs07eq9k)

例えばこれだと、 `pop()` してもメモリは開放されない。
不要な参照に null を設定する事で回避できる。

```kotlin
fun pop(): String? {
  val e = elements[--size]
  elements[size] = null
  return e
}
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/n3m2esmn6tn4lc7ndfjchuquvh)

**【弱参照を利用する】**

弱参照 is 何？
-> [参照先のオブジェクトをGCから守れない参照](https://ja.wikipedia.org/wiki/%E5%BC%B1%E3%81%84%E5%8F%82%E7%85%A7)
Java では `java.lang.ref` パッケージで実装されている。
Kotlin で `WeakReference` を使った例 ↓

```kotlin
class HeavyObject

var strongRef: HeavyObject? = HeavyObject()
val weakRef = WeakReference<HeavyObject>(strongRef)

fun printWeakRef() = println(weakRef.get())

fun main(args: Array<String>) {
	printWeakRef()
	strongRef = null // 弱参照のみ存在している状態にする
	printWeakRef()
	System.gc()      // 弱参照のみなのでGCされる
	printWeakRef()   // ここで null
}
```
[Try Kotlin で確認](https://try.kotlinlang.org/#/UserProjects/mh5r5j9l413hdu0b9ms1abu140/gqrfkldlhhp52hg87ppl9at0ih)

書籍では、コールバックやリスナー等で `WeakHashMap` を利用することを推奨している。

## 項目7 ファイナライザを避ける

### 概要

- ファイナライザは基本的に使うべきでない
 - パフォーマンス低下、移植性の問題等の為
- 代わりに明示的終了メソッドを提供する
 - 例： `InputStream.close()`

書籍では、ファイナライザを利用する場合の注意点等も述べられている。

### Kotlin で読む

Java では `Object.finalize()` をオーバーライドする事で実装できた。
が、`kotlin.Any` は `finalize()` を持っていない。
故に、単に `override` 修飾子なしに宣言するだけで良い。
[Calling Java code from Kotlin#finalize](https://kotlinlang.org/docs/reference/java-interop.html#finalize)

```kotlin
class C {
    protected fun finalize() {
        // finalization logic
    }
}
```

一応、明示的終了メソッドが呼ばれなかった際のセーフティなどには使える。
が、繰り返しだが基本的に `finalize()` は使う必要ない。

# おわり

- 前： ないよ
- 次： [Effective Java を Kotlin で読む（２）：第3章 すべてのオブジェクトに共通のメソッド](https://qiita.com/ref3000/items/0dba04cdcb32b7debdb6)

# 参考資料等

- [Kotlin Reference](https://kotlinlang.org/docs/reference/)
- [Kotlin Language Documentation](https://kotlinlang.org/docs/kotlin-docs.pdf)
- Effective Java 第2版
- Kotlin イン・アクション
- [(Blog)The King's Museum / Effective Java](https://www.thekingsmuseum.info/archive/category/Effective%20Java)
- [(Qiita)弱い参照とな] (https://qiita.com/yyyske/items/daa5c844647604e27e4f)
- [(Slide)How "Effective Java" influenced Kotlin](https://speakerdeck.com/lukle/how-effective-java-influenced-kotlin)