[Java8〜]日付の曜日を簡潔に取得する方法（ビフォーアフターあり）

先日コードレビューをしていると、日付の曜日を取得するUtilクラスを実装してもらったところがありました。

共通処理をUtilクラスに切り出していることはとても良いことでしたが、コードを見るともう少し簡潔に書ける方法がありそうだなと思いました。

調べたところ、非常に簡潔に記述できる方法がありましたので、備忘録のためにも記述しておきます！

※一部抜粋コードで説明します。

# 修正前のコード
```java:プロダクションコード
import java.time.DayOfWeek;
import java.time.LocalDate;

public class DateUtil {

  /**
   * 曜日を取得する
   *
   * @param baseDate 基準日
   * @return 基準日の曜日
   */
  public static String getDayOfWeek(LocalDate baseDate) {
    if (baseDate == null) {
      return "";
    }

    DayOfWeek dayOfWeek = baseDate.getDayOfWeek();
    switch (dayOfWeek) {
      case SUNDAY:
        return "日";
      case MONDAY:
        return "月";
      case TUESDAY:
        return "火";
      case WEDNESDAY:
        return "水";
      case THURSDAY:
        return "木";
      case FRIDAY:
        return "金";
      case SATURDAY:
        return "土";
      default:
        return "";
    }
  }
}
```
switch文のところが何やら臭いますね🤔

もっと簡潔に書ける方法がありそう・・

```java:テストコード
public class DateUtilTest {

  @ParameterizedTest
  @MethodSource("providerGetDayOfWeek")
  void getDayOfWeek(LocalDate baseDate, String expected) {
    var actual = DateUtil.getDayOfWeek(baseDate);
    Assertions.assertEquals(expected, actual);
  }

  private static Stream<Arguments> providerGetDayOfWeek() {
    return Stream.of(
        Arguments.of(LocalDate.of(2023, 5, 21), "日"),
        Arguments.of(LocalDate.of(2023, 5, 22), "月"),
        Arguments.of(LocalDate.of(2023, 5, 23), "火"),
        Arguments.of(LocalDate.of(2023, 5, 24), "水"),
        Arguments.of(LocalDate.of(2023, 5, 25), "木"),
        Arguments.of(LocalDate.of(2023, 5, 26), "金"),
        Arguments.of(LocalDate.of(2023, 5, 27), "土")
    );
  }
}
```

現状のプロダクションコードでも、テストは期待値どおりきちんと成功します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630308/e49cfc91-23c8-981c-9f75-8b3ae5990db1.png)

# 修正後のコード（パート１）
Java17以降であれば、switch文を拡張switch文に切り替えることができます。

```diff_java:プロダクションコード
import java.time.DayOfWeek;
import java.time.LocalDate;

public class DateUtil {

  /**
   * 曜日を取得する
   *
   * @param baseDate 基準日
   * @return 基準日の曜日
   */
  public static String getDayOfWeek(LocalDate baseDate) {
    if (baseDate == null) {
      return "";
    }

     DayOfWeek dayOfWeek = baseDate.getDayOfWeek();
-    switch (dayOfWeek) {
-      case SUNDAY:
-        return "日";
-      case MONDAY:
-        return "月";
-      case TUESDAY:
-        return "火";
-      case WEDNESDAY:
-        return "水";
-      case THURSDAY:
-        return "木";
-      case FRIDAY:
-        return "金";
-      case SATURDAY:
-        return "土";
-      default:
-        return "";
-    }

+    return switch (dayOfWeek) {
+      case SUNDAY -> "日";
+      case MONDAY -> "月";
+      case TUESDAY -> "火";
+      case WEDNESDAY -> "水";
+      case THURSDAY -> "木";
+      case FRIDAY -> "金";
+      case SATURDAY -> "土";
+      default -> "";
+    };
  }
}
```
これでもちょっとは簡潔になりましたよね。

ちなみにテストも成功のままです（リファクタリング成功🙌）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630308/361a8f8c-27db-f864-86e6-9489baa9dcab.png)

# 修正後のコード（パート2）
さらに簡潔に書ける方法を見ていきましょう。

```diff_java:プロダクションコード
import java.time.DayOfWeek;
import java.time.LocalDate;

public class DateUtil {

  /**
   * 曜日を取得する
   *
   * @param baseDate 基準日
   * @return 基準日の曜日
   */
  public static String getDayOfWeek(LocalDate baseDate) {
    if (baseDate == null) {
      return "";
    }

     DayOfWeek dayOfWeek = baseDate.getDayOfWeek();
-    switch (dayOfWeek) {
-      case SUNDAY:
-        return "日";
-      case MONDAY:
-        return "月";
-      case TUESDAY:
-        return "火";
-      case WEDNESDAY:
-        return "水";
-      case THURSDAY:
-        return "木";
-      case FRIDAY:
-        return "金";
-      case SATURDAY:
-        return "土";
-      default:
-        return "";
-    }
   
+   return dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.JAPANESE); 
  }
}
```
たった１行です！

コードの説明をすると、

`DayOfWeek dayOfWeek = baseDate.getDayOfWeek();`

ここで、getDayOfWeek()メソッドを使用して、baseDateというLocalDateオブジェクトから曜日を取得してdayOfWeekに格納しています。

dayOfWeekにはenumのDayOfWeek型が入っています。このenumには、MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAYといった値が定義されています。

`dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.JAPANESE);`

enumのDayOfWeek型のインスタンスは、getDisplayName()メソッドを持っており、このメソッドは、指定したTextStyleとLocale（ロケール、地域設定）に基づいて曜日の名前を取得します。

ここでは、TextStyle.SHORTとLocale.JAPANESEを指定しているため、曜日の日本語の短い名前（例えば、"月"、"火"、"水"など）を取得します。

TextStyle.FULLだと、"日曜日"や"月曜日"となります。
※詳しくは[参考]へ

最後にテストも確認しておきましょう！

きちんと成功のままリファクタリングできています🙌
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630308/e7f184a9-2dea-f88e-3252-f47a989214c8.png)

以上です！

# 参考
https://docs.oracle.com/javase/jp/8/docs/api/java/time/DayOfWeek.html
https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/TextStyle.html
https://docs.oracle.com/javase/jp/8/docs/api/java/util/Locale.html