CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第5章 日付と時刻の新たな API : 問題 12 : 約束の通知

問題

異なるタイムゾーンにある約束を読み込んで、ローカル時刻で1時間前に約束があることをユーザーに通知せよ

例えば、ニューヨークで午前10時に電話会議があったときも、今いる東京で正しいローカル時間に通知を受けることができる

解答

約束とは、タイトルと開始時間(ZonedDateTime)を持つオブジェクトとする

■ 約束クラス

public class Appointment {
    /** タイトル */
    public final String title;
    /** 開始時間 */
    public final ZonedDateTime time;

    public Appointment(String title, ZonedDateTime time) {
        this.title = title;
        this.time = time;
    }
}

約束を読み込んでSortedSetに保持する
ソート順は、当然のことながら開始時間の昇順である

■ 約束のコレクション

Set<Appointment> appointments = new TreeSet<Appointment>(
    (a, b) -> a.time.compareTo(b.time)
);
appointments.add(new Appointment("電話会議",~);
appointments.add(new Appointment("銀座で接待",~);
appointments.add(new Appointment("テレビ会議",~);
    :

通知のスケジューリングだが、ここでは簡便に

  1. SingleThreadScheduledExecutorが一定周期で通知スレッドを起動
  2. 通知スレッドはappointmentsをチェックし、1時間後の約束がなければ終了
  3. 1時間後の約束があれば、ひとつだけ通知してappointmentsから削除
    通知は、標準出力に約束の内容を表示するだけとする

■ 通知スレッドのスケジューリング

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(
    () -> {
        Optional<Appointment> firstAppo = appointments.stream().findFirst();
        if (!firstAppo.isPresent())
            return;
        Appointment appo = firstAppo.get();
        if (appo.time.isAfter(ZonedDateTime.now().plusHours(1)))
            return;
        System.out.println(appo.title + ": " + appo.time);  // 通知
        appointments.remove(appo);
    },
    0, 30, TimeUnit.SECONDS
);
service.awaitTermination(1, TimeUnit.DAYS);