Java
java8

JavaのDate and Time APIの設計思想が面白い

これまでJava SE 8から入ったDate and Time API(JSR 310)は使ってこなかったのですが(Joda-Timeで特に不満はなかったので)、先日調べてみたところ、設計思想が面白いと感じたので、書いてみます。

パッケージ概要

和暦などの暦が入っている java.time.chrono が多いのでクラス数は多く見えます。

パッケージ 概要 インタフェース クラス 列挙型 例外
java.time メインAPI 0 15 2 1
java.time.chrono 和暦などの暦1 6 11 4 0
java.time.format 解析・出力 0 3 4 1
java.time.temporal 時刻を調整2 7 6 2 1
java.time.zone タイムゾーン 0 4 1 1
合計 13 39 13 4

java.time以下のクラスは一見多いですが、普段使う言葉と対応してるものが多いので、すんなり飲み込めそうです。

不変

可変のクラスはただ1つ、java.time.format.DateTimeFormatterBuilderだけです。java.time.temporal.TemporalAdjusterなど、不変でなくても構わないものがありますが、不変にしたほうがいいよと親切に(口を酸っぱくして?)教えてくれます。

実装要件:
このインタフェースは実装が可変であることを制限しませんが、不変にすることを強くお薦めします。

メソッドの命名規則

標準的な get, to 以外にも以下のような単語をメソッドの接頭辞として使用しています。 with, plus, minusJoda-Time にもありますね。

  • インスタンス取得
    • of: intなどから
    • from: 他のオブジェクトから
  • 別のインスタンスを作成
    • at: 組み合わせて別のインスタンスを作成(MonthDay + Year → LocalDateなど)
    • with: 一部を変更して別のインスタンスを作成(LocalDate#withYear()で年のみ変更など)
    • plus, minus: 加算、減算して別のインスタンスを作成

継承を可能な限り避ける

例外クラスは除いて、ほとんどのクラスは継承を使ってません(Objectを直接継承)。Joda-Timeが継承を多用していたのとは対照的です。 継承を使っているケースでも、抽象基底クラスはObjectを直接継承し、継承したサブクラスはfinalにし、深い継承を避けています。

既存のクラスを徹底的に排除

Java SE 7から導入されたjava.nio.Pathは、既存のjava.io.FiletoFile(), toPath()で相互変換ができるようになっています。一方で、旧APIとの相互変換は、旧API側のみに実装されています。

自分は、お前ら(既存のクラス)はjava.timeの土を踏むことは許さんという感じを受けました。当初は相互変換は一切用意されていなかったようで4、旧APIに対する怨念すら感じました(ヽ´ω`)

おわりに

Effective Javaに書いてあることでもあるのですが、不変にしないことで思わぬバグを発生したり、finalにしてなかったばかりに勝手に継承されて泣いたり、いろいろ痛い目にあってきたので、共感するところが多いです。今後は積極的に使っていこうと思います。


  1. オールドゲーマーは「クロノ・トリガー」の「クロノ」で覚えるといいかも? 

  2. 音楽の「テンポ」と同じイメージ? 

  3. date - Java 8, why not a ZonedTime class? - Stack Overflow 

  4. 日本人のための Date and Time API Tips (ja) - notepad