Double Brace Initialization (DBI)って？

# はじめに
つい先日、SonarQubeを使って他の人のコードを解析してみたとき、次のようなコードに、マイナーだがバグの可能性があることをSonar先生が指摘されていました。

```java
Set<String> myLanguageSet = new HashSet<String>() {
    {
        add("Java");
        add("JavaScript");
        add("PHP");
    }
};
```
ぼく「あれれ〜、おっかしいぞー！括弧が２つもあるよ」
Sonar先生「

> **Double Brace Initialization should not be used**
> Because Double Brace Initialization (DBI) creates an anonymous class with a reference to the instance of the owning object, its use can lead to memory leaks if the anonymous inner class is returned and held by other objects. Even when there's no leak, DBI is so obscure that it's bound to confuse most maintainers.
>For collections, use Arrays.asList instead, or explicitly add each item directly to the collection.

」
ぼく「なるほど、完全に理解した。」

# Double Brace Initializationって？
日本語に訳すと「二重括弧初期化」？そのままカタカナで「ダブルブレースイニシャライゼーション」？知っている方いたら教えてくださいmm
今回はSonar先生と同じく「DBI」と呼ばせてください。

DBIは２つのプロセスの組み合わせです。
まず最初の括弧が**匿名クラス**を生成します。
そして次の括弧が**初期化ブロック**でオブジェクトを初期化しています。
ひとずつ確認していきましょう。

## 匿名クラス
Javaの教材だと、よくインターフェイスのところで出てくるやつですね。例えば一度しか使わないのにインターフェイスを実体化するクラスを作り、コードが管理しにくくなったり可読性が下がったりしてしまいます。その煩わしさを匿名クラスは解決してくれます。
詳しくは他の方が説明されているので、ここでは簡単(で雑)な例を掲載します。

```java
public interface Greeting {
    public void sayHello();
}
```
```java
// 匿名クラスを利用しない場合
public class GreetingImple implements Greeting {
    @Override 
    public void sayHallo() {
        System.out.println("Hello");
    }
}

public class Sample1 {
    public static void main(String[] args) {
        Greeting greeting = new GreetingImple();
        greeting.sayHello();
    }
}
```
```java
// 匿名クラスを利用した場合
public class Sample2 {
    public static void main(String[] args) {
        Greeting greeting = new Greeting() {
            @Override 
            public void sayHallo() {
                System.out.println("Hello");
            }
        };
        greeting.sayHello();
    }
}
```

## 初期化ブロック
初期化ブロックには**オブジェクト初期化ブロック**と**静的初期化ブロック**があります。今回は前者のみとりあげます。
変数の初期化はイメージしやすいと思います。それをただオブジェクトでもやるだけです。書き方は少し変数の初期化とは異なり、`{　}`で処理を囲います。
オブジェクトの初期化はオブジェクト毎に実行され、実行タイミングはコンストラクタより先です。

```java
Public class InitializeSample {
    // 初期化ブロック
    {
        System.out.println("初期化ブロック１");
    }
    // コンストラクタ
    public InitializeSample() {
        System.out.println("コンストラクタ");
    }
    // 初期化ブロック
    {
        System.out.println("初期化ブロック2");
    }

```
```bash:実行結果
初期化ブロック１
初期化ブロック2
コンストラクタ
```

## ようやくDBIのお話。
上の２つを組み合わせます。匿名クラスに初期化ブロックを適用するとDBIになります。通常このように

```java
Set<String> myLanguageSet = new HashSet<>();
myLanguageSet.add("Java");
myLanguageSet.add("JavaScript");
myLanguageSet.add("PHP");
```
というように実装してあげるのですが、DBIだと

```java
Set<String> myLanguageSet = new HashSet<String>() {
    {
        add("Java");
        add("JavaScript");
        add("PHP");
    }
};
```
というように、HashSetを匿名で作成し、`add("Java");` `add("JavaScript");` `add("PHP");`で初期化してあげる形で実装することができます。

### メリット
ではわざわざこのように実装するメリットはなんでしょう。
#### コードの記述量が少なくなる
たしかに、上記の例だと毎回`myLanguageSet.add`は面倒ですよね（コピペしろ）
#### 可読性が上がる
慣れると見やすい気がします。SetとかListのスコープがわかりやすいです。

### デメリット
メリットがあればもちろんデメリットもあります。
#### そこまで広く知られた書き方じゃない
初見だと何が起きてるかよくわからないです。
#### ダイアモンド演算子が使えない
上記の例のように`new HashSet<String>()`と書かなきゃいけません。匿名クラスでは`<>`は使用できません。
#### メモリリークを起こす可能性がある
匿名クラスはそれを内包するインスタンスに対して、見えないthisポインターをもつそうで、これがメモリリークを起こすだけでなく、Serialize系でも支障をきたすようです。

# 結局DBIってどうなの？
上記のように、メリットよりデメリットの方があるので、DBIはけっこうアンチパターンと考えられているそうです。特別、理由がない限りはDBIは避けましょう。
代替案として、Java９以降であれば`List.of`や`Set.of`を使ったり、Java8であればStream APIを使うのが良いみたいです。

```java
// java9
List<String> list = List.of("aaa", "bbb", "ccc");
Set<String> set = Set.of("aaa", "bbb", "ccc");

// java 8
Set<String> countries = Stream.of("aaa", "bbb", "ccc")
      .collect(collectingAndThen(toSet(), Collections::unmodifiableSet));
```

# 参考にしたサイト
https://www.baeldung.com/java-double-brace-initialization
https://javapapers.com/core-java/java-double-brace-initialization/
https://stackoverflow.com/questions/1958636/what-is-double-brace-initialization-in-java