Print Friendly, PDF & Email

この記事では、弊社の新人エンジニア研修の参考にJava8を解説します。

前回はコレクションとジェネリクスについて解説しました。

今回は日付/時刻と列挙型について解説します。

※この章は研修時間の都合により丸ごとスキップすることがあります。

 

Javaには過去の経緯から日付/時刻するクラスはたくさんあります。

しかし、当社の新人研修ではjava.timeパッケージの中のクラスの特定の機能に限定してお伝えします。

詳しい使い方は必要に応じて調べてください。

 

1.現在日時の取得

今現在を表すインスタンスはLocalDateTimeクラス(標準API)のnowメソッドで取得できます

package chap16;

import java.time.LocalDateTime;

public class Example01 {

    public static void main(String[] args) {

        LocalDateTime date = LocalDateTime.now();
        System.out.println(date);
    }
}

<結果の例>

2021-02-10T13:37:43.995

結果は「西暦-月-日T時:分:秒」の形で表示されました。

Tは単なる区切り文字で意味はありません。

インスタンスから年だけ、月だけ、日だけ、、、のように一部の要素を取り出すには以下のようにgetで始まるメソッドを使用します。

package chap16;

import java.time.LocalDateTime;

public class Example02 {

    public static void main(String[] args) {

        LocalDateTime date = LocalDateTime.now();
        System.out.println(date.getYear() + "年");
        System.out.println(date.getMonth() + "月");
        System.out.println(date.getDayOfMonth() + "日");
        System.out.println(date.getDayOfWeek() + "曜日");
        System.out.println(date.getHour() + "時");
        System.out.println(date.getMinute() + "分");
        System.out.println(date.getSecond() + "秒");
        System.out.println(date.getNano() + "ナノ秒");
    }
}

<結果の例>

2021年
FEBRUARY月
10日
WEDNESDAY曜日
13時
51分
55秒
41000000ナノ秒

ところでここで出てきた「FEBRUARY」、「WEDNESDAY」といった文字列は何でしょうか?

実はこれらは列挙型と呼ばれるJavaの型の一つです。

列挙型は複数の定数をひとつにまとめておくことができる型です。

月はJANUARYから始まって12個しかありません。

曜日はMONDAYから始まって7個しかありません。

このように限定的なものは列挙型にすると色々と便利なのです。

列挙型については本章でこの後学んでいきます。

 

2.特定の日付の扱い

特定の日付のインスタンスを作成するにはLocalDateクラス(標準API)のクラスメソッドofを使います。

以下は1995年4月19日生まれの人の誕生日を表示しているソースコードです。

package chap16;

import java.time.LocalDate;
import java.time.Month;

public class Example03 {

    public static void main(String[] args) {

        LocalDate birthday= LocalDate.of(1995, Month.APRIL, 19);
        System.out.println(birthday);
    }
}

<結果>

1995-04-19

 

なお、ありえない日付を指定すると例外が発生します。

package chap16;

import java.time.LocalDate;
import java.time.Month;

public class Example04 {

    public static void main(String[] args) {

        LocalDate birthday= null;
        try {
            birthday= LocalDate.of(1995, Month.APRIL, 31);
        } catch (Exception e) {
            System.out.println(e);
        }
        System.out.println(birthday);
    }
}

<結果>

java.time.DateTimeException: Invalid date 'APRIL 31'
null

4月31日というのはありえないため例外が発生しました。

 

3.日付の書式を指定する

日付の書式を指定するには、クラスDateTimeFormatter(標準API)を使います

先にサンプルコードを見てみます。

package chap16;

import java.time.LocalDate;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Example05 {

    public static void main(String[] args) {

        LocalDate birthday = LocalDate.of(1995, Month.APRIL, 19);

        System.out.println(DateTimeFormatter.ofPattern("uuuu/M/d(E)", Locale.JAPANESE).format(birthday));
    }
}

クラスDateTimeFormatterのofPatternメソッドは引数として書式とロケールという同じ言語を共有する区域を指定します。

上記の例で書式は、uuuuが西暦を、Mが月を、dが日付を、Eが曜日をそれぞれ意味しています。

例えば、月を2桁で表示したければMM、日付を2桁で表示したければddとします。

試してみてください。

ロケールはLocale.JAPANESEとなっています。

DateTimeFormatterのofPatternメソッドの戻り値に対してメソッドチェーンでformatメソッドを呼んで、

引数にクラスLocalDateのインスタンスを渡せば、上記のような結果になります。

 

なお、和暦の表示も可能です。

以下のサンプルコードを御覧ください。

package chap16;

import java.time.chrono.JapaneseDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Example06 {

    public static void main(String[] args) {

        JapaneseDate japaneseDate = JapaneseDate.now();
        System.out.println(DateTimeFormatter.ofPattern("G y年M月d日(E)", Locale.JAPANESE).format(japaneseDate));
    }
}

<結果>

令和 3年2月10日(水)

 

4.時刻の扱い

時刻を表すクラスは、クラスLocalTime(標準API)です。

クラスLocalTimeのofメソッドの引数に時間(0~23)と分(0~59)をカンマで区切って指定します。

以下のサンプルコードを御覧ください。

package chap16;

import java.time.LocalTime;

public class Example07 {

    public static void main(String[] args) {
        LocalTime localTime1 = LocalTime.of(0, 0);
        LocalTime localTime2 = LocalTime.of(23, 59);
        System.out.println(localTime1);
        System.out.println(localTime2);
    }
}

<結果>

00:00
23:59

なお、上記の例では分までしか指定していませんが、秒、ナノ秒まで指定が可能です。

第3、第4引数を使います。

 

時刻の比較も可能です。

クラスLocalTimeのインスタンスメソッドisBeforeやisAfterを使います。

次のサンプルコードをご覧ください。

package chap16;

import java.time.LocalTime;

public class Example08 {

    public static void main(String[] args) {
        LocalTime localTime1 = LocalTime.of(10, 0);
        LocalTime localTime2 = LocalTime.of(15, 0);
        System.out.println(localTime1.isBefore(localTime2));
        System.out.println(localTime1.isAfter(localTime2));
    }
}

<結果>

true
false

このようにたくさんのクラス、メソッドがあります。

とても全ては紹介しきれないので、必要に応じて調べて使ってください。

 

5.Enum(列挙型)とは

Enum(イーナム)型は複数の定数をひとつにまとめることが出来る型のことです。

ここではクラスEnum(標準API)について簡単な説明をします。

さきほどパッケージ java.timeで月や曜日でEnumが使われている例を見ました。

Enumは限定されたものを列挙するのに使うと便利です。

みなさんもオリジナルのEnumを作成して利用することができます。

Enum型の宣言には、クラスのかわりにenumキーワード(先頭小文字)を使います。

以下のサンプルコードを見てください。

イメージとしては、コーヒーショップでカップのサイズが4つある(4つしかない)ということを表現したいとします。

enum CupSize {
    SHORT,
    TALL,
    GRANDE,
    VENTI;
}

定数なのですべて大文字で表記します。また、要素名はカンマで区切って記述します。

 

通常のクラスはインスタンスを作成する際にnew演算子を使いましたが、Enumでは使いません。

以下はサンプルです。

package chap16;

public class Example09 {
    public static void main(String[] args) {
        CupSize cup = CupSize.GRANDE;
        System.out.println(cup);
    }
}

<結果>

GRANDE

 

Enumはデフォルトでメソッドをいくつか持っています。

以下で説明しているvaluesメソッドは、Enumであれば宣言・実装をしなくても使えます。

拡張for文と組み合わせて次のようなコードを書くことができます。

package chap16;

public class Example10 {
    public static void main(String[] args) {
        for (CupSize cup : CupSize.values()) {
            System.out.println(cup);
        }
    }
}

<結果>

SHORT
TALL
GRANDE
VENTI

このようにvaluesメソッドを使えば全要素が配列として取得できるので、拡張For文の条件指定に使えます。

 

また、switch文の中でケースラベルに指定することができます。

Coffee クラスでCupSizeを使用してみます。

コーヒーカップのサイズごとに違った料金を返すようにtoStringメソッドをオーバーライドしています。

package chap16;

public class Coffee {

    private CupSize cupSize;

    public Coffee(CupSize cupSize) {
        this.cupSize = cupSize;
    }

    public String getPrice() {
        switch (this.cupSize) {
            case SHORT:
                return "280円です";
            case TALL:
                return "320円です";
            case GRANDE:
                return "360円です";
            case VENTI:
                return "400円です";
            default:
                return "もう一度ご注文をお願いします。";
        }
    }
}

※今回のswitch文ではreturnしていますのでbreakはありません。

テストクラスを書いてみます。

package chap16;

public class Example11 {

    public static void main(String[] args) {
        Coffee coffee = new Coffee(CupSize.GRANDE);
//        Coffee coffee2 = new Coffee(CupSize.Large);//   列挙された以外のサイズは存在し得ないことになる
//        Coffee coffee3 = new Coffee(CupSize.GRANDEE);//   またスペルミスにも早期に気づくことができる

        System.out.println(coffee.getPrice());
    }
}

<結果>

360円です

列挙された以外の要素(上記の例のCupSize.Large)は存在し得ないというところがEnumの良い点です。

また、スペルミスもIDEが教えてくれます。

これがEnumではなく、単なるStringだとしたらこうはいきません。

バグが入り込む余地が少なくなるわけです。

 

さらに、Enumには、固有のフィールドやメソッド、コンストラクタを持たせることも可能です

以下のサンプルコードを見て下さい。

package chap16;

public enum CupSize2 {
    SHORT(240),
    TALL(350),
    GRANDE(470),
    VENTI(590);

    private final int price;

    private CupSize2(int price) {
        this.price = price;
    }

    int getPrice() {
        return price;
    }
}

ポイントは以下の3点です。

  1. 値の後ろに()を付けてその中にフィールドの値を書く
  2. フィールドをprivate finalとしてコンストラクタ内での初期化を強制する
  3. フィールドの値にアクセスすためのgetterメソッドを作る
 
使用例を以下に示します
 
package chap16;

public class Example11 {

    public static void main(String[] args) {
        CupSize2[] cupsizes = CupSize2.values();

        for (CupSize2 cupsize : cupsizes) {
            System.out.println(cupsize + ":" + cupsize.getPrice());
        }
    }
}

<結果>

SHORT:240
TALL:350
GRANDE:470
VENTI:590

以上、駆け足でEnumを見てきました。

 

<まとめ:隣の人に正しく説明できたらチェックを付けましょう>

□今現在を表すインスタンスはLocalDateTimeクラスのnowメソッドで取得できる

□日付の書式を指定するには、クラスDateTimeFormatterを使う

□Enum型は複数の定数をひとつにまとめることが出来る型のことである

□定数と異なり、Enumには固有のフィールドやメソッド、コンストラクタを持たせることも可能である

 

まとめができたら、アウトプットとして演習問題にチャレンジしましょう。

問題16.日付/時刻と列挙型

java 8 で新たに追加されたjava.timeパッケージに関連した問題です。 目次1.曜日の表示2.何日後の日付3.日付の前後関係4.年齢計算5.日付と曜日のフォーマット6.列挙型を使…

 

【今回の復習Youtube】

059-APIの利用-現在の日付を求める

060-APIの利用-当月の初日の日付を求める

061-APIの利用-当月の末日の日付を求める

062-APIの利用-任意の日付を指定する

063-APIの利用-日付の書式を指定する

064-APIの利用-任意の時刻を指定する

065-APIの利用-時刻を比較する

052-enum型-enum型のサンプル

 

JavaSE8の解説に戻る