Lombokのよく使うアノテーション一覧（サンプルコードあります）

以前、Java8のStreamAPIに感動した記事を挙げました。そのときStreamAPI以外にも感動したものが、今回記事にしたLombokというライブラリーになります！

https://qiita.com/toranoko92114/items/880206e97289fa18a923

最初は何これ？って思っていたのですが、使ってみると使い勝手が良く、かつコードが見やすくなってとても感動しました。

ということもあり、Lombokを知らないプログラマにこの感動を共有したいということでこの記事を書きました。

どうぞ最後までご覧下さい！

## この記事でわかること
- Lombokの概要・仕組み
- Lombokの導入方法
- Lombokの基本的なアノテーションと使い方

## Lombokとは
アノテーション記述（@xxx）によって、Javaコーディングにおけるボイラープレートコードを排除して、見やすく簡潔に実装することができるライブラリです。

ボイラープレートコードは、省略できない定型的なコードのことを指していて、代表的なところでいうと、以下辺りですかね。

- getter / setter メソッド
- equals / hashCodeメソッド
- toStringメソッド
- コンストラクタ
- リソース(入出力ストリーム等)のクローズ処理
- ロガーインスタンスの生成

Lombokを使用することで、これらのコードを減少させるとともに、可読性や生産性の向上も期待できます！

## 導入方法
IntelliJ IDEAで導入するサンプルをこちらの記事で書いていますので、ご興味がある方はぜひ参考にしてみてください。

https://qiita.com/toranoko92114/items/b839e165a974283ba979

## Lombokの仕組み
### サンプルコード
Lombokを使わないと以下のようなコードになります。

```java:Lombok未使用
public class People {

  // field
  private Integer year; 
  private String name; 

  // getter
  public Integer getYear() {
    return this.year;
  }

  public String getName() {
    return this.name;
  }

  // setter
  public void setYear(final Integer year) {
    this.year = year;
  }

  public void setName(final String name) {
    this.name = name;
  }
}
```

fieldごとにsetterとgetterを書かないといけないのが、かなり面倒くさいですよね。

Lombokを使うと以下のようにスッキリとしたコードになります。

```java:Lombok使用
@Getter
@Setter
public class People {

  // field
  private Integer year; // 歳
  private String name;  // 名前

}
```
@Getter、@Setterアノテーションをつけると、Lombokが勝手にgetterメソッドやsetterメソッドを実装してくれます。

これは便利だし、コードの見やすさも爆上がりですね！


### どういう仕組みで実現されているか
それじゃあ、サンプルのようにスッキリとしたコードになるのは、どういった仕組みで実現されているのでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630308/a23d48a1-72dd-1c52-fa2c-5a3b9ff099d0.png)


コンパイル時のクラスパスにLombokが含まれていると、コンパイル時にLombokがソースファイルを解析して、getterやsetterなどの定型コードを生成したあとにコンパイラに渡します。

ですので、ソースファイルレベルでは定型コードが含まれていなくても、コンパイル後のクラスファイルには定型コードが存在するようになっているんですね~

## 主に使うLombokアノテーション
開発時によく使うLombokのアノテーションと、どういう効果があるかを表にまとめましたので、ご自分の目的にあったアノテーションを使ってみてください。

| アノテーション                                       | 説明                                                                                                                                                                           | 
| :--------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 
| @Getter                                              | getterメソッドを生成します。                                                                                                                                                   | 
| @Setter                                              | setterメソッドを生成します。                                                                                                                                                   | 
| @ToString                                            | toStringメソッドを生成します。                                                                                                                                                 | 
| @NonNull                                             | Nullチェックのコードを生成します。Nullだった場合NullPointerExceptionがスローされます。                                                                                         | 
| @AllArgsConstructor                                  | 全ての引数を使ったコンストラクタを生成します。                                                                                                                                 | 
| @NoArgsConstructor                                   | 引数なしのコンストラクタを生成します。                                                                                                                                         | 
| @RequiredArgsConstructor                             | 必須の引数（final）を持つコンストラクタを生成します。                                                                                                                          | 
| @FieldDefaults(boolean makeFinal, AccessLevel level) | アクセス修飾子やfinal修飾子がない変数に対して、アノテーション引数に指定した形で修飾子を付与します。                                                                            | 
| @EqualsAndHashCode                                   | equals、hashCodeメソッドを生成します。                                                                                                                                         | 
| @Data                                                | @ToString、@Getter、@Setter、@EqualsAndHashCode、@RequiredArgsConstructorの5つのアノテーションをまとめて付与します。                                                           | 
| @Value                                               | @ToString、@Getter、@EqualsAndHashCode、@AllArgsConstructor<br>@FieldDefaultsの5つのアノテーションをまとめ付与します。クラスはfinalに、各フィールドはprivate finalになります。 | 
| @Builder                                             | 対象クラスを生成するためのBuilderクラスを生成します。                                                                                                                          | 
| @Slf4j                                               | slf4jを使ったロギングコードを生成します。その他にもLog4jやCommonsLogなど様々なロガーに対応しています。                                                                         | 
## 各アノテーションのサンプルコード
### @Slf4j
:::note info
これ以降のアノテーションの説明でも@Slf4jを使うケースがあるので先に説明しておきます。
:::
@slf4jを付与することでslf4jを使ったロギングコードを生成します。
```java:@slf4j
@Slf4j
public class DemoSlf4j {
  public static void main(String[] args) {
    log.info("とらのこ");
  }
}
```
コンパイル時に以下のコードを設定してくれます。
```java
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DemoSlf4j.class);
```
```java:実行結果
> Task :DemoSlf4j.main()
13:57:11.449 [main] INFO training.DemoSlf4j - とらのこ
```
### @Getter、@Setter
getterメソッド、setterメソッドを生成します。
```java:@Getter、@Setter
@Slf4j
@Getter
@Setter
public class DemoGetSet {

  private Integer year;
  private String name;

  public static void main(String[] args) {
    DemoGetSet toranoko = new DemoGetSet();
    toranoko.setName("とらのこ");
    log.info(toranoko.getName());
  }
}
```
```java:実行結果
> Task :DemoGetSet.main()
14:04:39.848 [main] INFO training.DemoGetSet - とらのこ
```
### @ToString
toStringメソッドを生成します。
```java:@ToString
@Slf4j
@Getter
@Setter
@ToString
public class DemoToString {

  private Integer year;
  private String name;

  public static void main(String[] args) {
    DemoToString toranoko = new DemoToString();
    toranoko.setName("とらのこ");
    toranoko.setYear(30);
    log.info(toranoko.toString());
  }
}
```
```java:実行結果
> Task :DemoToString.main()
14:16:43.438 [main] INFO training.DemoToString - DemoToString(year=30, name=とらのこ)
```
@ToStringにより、フィールドの状態を文字列で返却してくれます。

### @NonNull
Nullチェックのコードを生成します。Nullだった場合NullPointerExceptionがスローされます。
```java:@NonNull
@Slf4j
@Getter
@Setter
public class DemoNonNull {

  private Integer year;

  @NonNull
  private String name;

  public static void main(String[] args) {
    DemoNonNull toranoko = new DemoNonNull();
    toranoko.setYear(30);
    try {
      toranoko.setName(null);
    } catch (NullPointerException e) {
      log.info("ヌルポですよ");
    }
  }
}
```
```java:実行結果
> Task :DemoNonNull.main()
14:22:18.876 [main] INFO training.DemoNonNull - ヌルポですよ
```

###　@AllArgsConstructor
全ての引数を使ったコンストラクタを生成します。
```java:@AllArgsConstructor
@Slf4j
@Getter
@AllArgsConstructor
public class DemoAllArgsConstructor {

  private Integer year;
  private String name;

  public static void main(String[] args) {
    DemoAllArgsConstructor toranoko = new DemoAllArgsConstructor(30, "とらのこ");
    log.info(toranoko.getName());
  }
}
```

引数付きのコンストラクタが暗黙的に作成されます！

```java:実行結果
> Task :DemoAllArgsConstructor.main()
14:26:58.664 [main] INFO training.DemoAllArgsConstructor - とらのこ
```

:::note warn
@NoArgsConstructorと@RequiredArgsConstructorについては説明を割愛させていただきます。
:::

### @FieldDefaults(boolean makeFinal, AccessLevel level)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630308/467d4fb8-2688-b5ef-ffb0-d103418bc59b.png)

### @EqualsAndHashCode
equals、hashCodeメソッドを生成します。
```java:@EqualsAndHashCode
@Slf4j
@AllArgsConstructor
@EqualsAndHashCode
public class DemoEqualsAndHashCode {

  private Integer year;
  private String name;

  public static void main(String[] args) {
    DemoEqualsAndHashCode toranoko1 = new DemoEqualsAndHashCode(30, "とらのこ1");
    DemoEqualsAndHashCode toranoko2 = new DemoEqualsAndHashCode(30, "とらのこ2");
    log.info("ハッシュ値：" + toranoko1.hashCode());
    log.info("比較結果：" + toranoko1.equals(toranoko2));
  }
}
```
```java:実行結果
> Task :DemoEqualsAndHashCode.main()
14:53:16.322 [main] INFO training.DemoEqualsAndHashCode - ハッシュ値：-1058173202
14:53:16.325 [main] INFO training.DemoEqualsAndHashCode - 比較結果：false
```

### @Data 
@ToString、@Getter、@Setter、@EqualsAndHashCode、@RequiredArgsConstructorの5つのアノテーションをまとめて付与します。

```java:@Data
@Slf4j
@Data
public class DemoData {

  private Integer year;
  private final String name;

  public static void main(String[] args) {

    // @RequiredArgsConstructor
    DemoData toranoko1 = new DemoData("とらのこ");
    DemoData toranoko2 = new DemoData("とらのこ");

    // @Setter
    toranoko1.setYear(30);

    // @ToString
    log.info("文字列化：" + toranoko1.toString());

    // @EqualsAndHashCode
    log.info("ハッシュ値：" + toranoko1.hashCode());

    // @Getter,@EqualsAndHashCode
    log.info(
        "比較結果：" + toranoko1.getName().equals(toranoko2.getName()));
  }
}
```
```java:実行結果
> Task :DemoData.main()
17:36:41.410 [main] INFO training.DemoData - 文字列化：DemoData(year=30, name=とらのこ)
17:36:41.417 [main] INFO training.DemoData - ハッシュ値：381512457
17:36:41.417 [main] INFO training.DemoData - 比較結果：true
```

### @Value
@ToString、@Getter、@EqualsAndHashCode、@AllArgsConstructor @FieldDefaultsの5つのアノテーションをまとめ付与します。

クラスはfinalに、各フィールドはprivate finalになります。（つまり、@Valueに内包される@FieldDefaultsの引数は、makeFinal = true, level = AccessLevel.PRIVATE ということですね）

```java:@Value
@Slf4j
@Value
public class DemoValue {

  Integer year;
  String name;

  public static void main(String[] args) {

    // @AllArgsConstructor
    DemoValue toranoko1 = new DemoValue(30, "とらのこ");
    DemoValue toranoko2 = new DemoValue(30, "とらのこ");

    // @ToString
    log.info("文字列化：" + toranoko1.toString());

    // @EqualsAndHashCode
    log.info("ハッシュ値：" + toranoko1.hashCode());

    // @Getter,@EqualsAndHashCode
    log.info(
        "比較結果：" + toranoko1.getName().equals(toranoko2.getName()));
  }
}
```
```java:実行結果
> Task :DemoValue.main()
17:43:16.605 [main] INFO training.DemoValue - 文字列化：DemoValue(year=30, name=とらのこ)
17:43:16.611 [main] INFO training.DemoValue - ハッシュ値：381512457
17:43:16.611 [main] INFO training.DemoValue - 比較結果：true
```
###　@Builder
対象クラスを生成するためのBuilderクラスを生成します。

オススメな使い方としては、インスタンスを作りたい対象クラスに@Dataか@Valueと@Builderを併用する形です。

```java:@Builder
@Slf4j
@ToString
@Data
@Builder
public class DemoBuilder {

  private Integer year;
  private String name;
  private String gender;

  public static void main(String[] args) {

    // Builerでインスタンス生成
    DemoBuilder toranoko = DemoBuilder.builder()
        .year(30)
        .name("とらのこ")
        .gender("男性")
        .build();

    log.info(toranoko.toString());

  }
}
```

```java:実行結果
> Task :DemoBuilder.main()
17:51:49.384 [main] INFO training.DemoBuilder - DemoBuilder(year=30, name=とらのこ, gender=男性)
```

かなり、スッキリとしましたよね。インスタンスを生成するときに、setterを使わなくていいのも当然ながら、どの変数に何を詰めるのかが一見して理解できるというのも利点かなと思います。

## さいごに
ここまで、以下を学んできました。
- Lombokの概要・仕組み
- Lombokの導入方法（IntelliJ IDEA）
- Lombokの基本的なアノテーションと使い方
- @Builderは@Dataや@Valueアノテーションと併用するのがオススメ

ぜひLombokを使って快適なプログラミングライフをお過ごし下さい！