2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Java Programmer Gold SE 8 資格まとめ(Java に慣れてる人向け)

Last updated at Posted at 2020-08-23

記事の目的

Java Programmer Gold SE 8 試験に出題される内容をまとめました。
「昔から Java をやっているけど SE8 のことは微妙に知らない」というニッチな層向けです。

この記事を書いたきっかけ

先日 Java SE 8 Programmer II (1Z0-809) を受験して合格し、Oracle Certified Java Programmer, Gold SE 8 をゲットしました。
Java2 の時に一度取得しましたが、今の世間で必要とされている知識レベルとは明らかに乖離していたので、自分の知識をアップデートする意味でも勉強し直した次第です。Android 開発でも SE8 の知識は必須となりつつありますしね。
受験にあたって試験範囲を自分なりにまとめたものがあるのですが、試験終了とともにそのままお蔵入りさせるのも忍びないので、記事というかたちで残しておこうと思いました。どなたかのためになれば、大変嬉しく思います。

要点まとめ

Java の基本

数値リテラルの接頭辞

数値の先頭に付加される接頭辞によって何進数の数値かが決定する

  • "0b"…2進数
  • "0"…8進数
  • なし…10進数
  • "0x"…16進数

final変数を初期化するタイミング

final 修飾子を付与したインスタンス変数は、コンストラクタで初期化されていなくてはならない

イニシャライザやコンストラクタによる初期化の順番

オブジェクトの初期化に関わる処理は以下の順番で実行される

  1. static イニシャライザ
    クラスのロード時
  2. インスタンスイニシャライザ
    インスタンス生成時、コンストラクタ実行前
    変数を宣言しただけでは実行されない。インスタンス化が必要
  3. コンストラクタ

列挙値の継承とインターフェイスの実装

  • 列挙型のメソッドである name()toString() は自身の文字列表現を返す
  • name() は final なのでオーバーライド不可。toString() は可
  • 列挙型はインターフェイスの実装と、抽象メソッドの定義ができる。これらをした場合、各列挙値でオーバーライドする必要がある
  • 文字列から列挙値を得る場合、valueOf() メソッドが利用できる

列挙値についての注意点

  • 列挙値にはコンストラクタを定義できるが、new によるインスタンス化は許可されていないので、コンストラクタに public や protected をつけるとコンパイルエラーになる
    何もつけなければコンパイルは通るが、new することはできない(コンパイルエラーになる)
  • final 宣言のないフィールドを定義すると、そのフィールドの値は任意のタイミングで変更することができる
enum Direction {
    North(0), South(1);

    // final 宣言しなければ、利用する側でこの値を変更できる
    int index;
    private Direction(int index) { this.index = index; }
}

// Direction の index フィールドを変更してみた例
Direction d = Direction.North;
System.out.println(d.index);    // 0
d.index = 10;
System.out.println(d.index);    // 10

hashCode() と equals()

  • 複数のオブジェクトを同値とする条件は下記2点
    • hashCode() の戻り値(ハッシュ値)が同じ
    • equals() が true
  • コレクションでの重複チェックは以下の通り。両者が成立したら同値とみなされる
    1. ハッシュ値が同じかチェック
    2. ハッシュ値が同じものだけを対象に equals() で比較
  • hashCode() を実装する場合、同値のオブジェクトからは値が返るよう実装する
  • equals() の引数は Object。レシーバと同じ型にするとオーバーライドは成立せず、オーバーロードが成立してしまう。コンパイルエラーにはならない

インターフェイスのメソッド

  • インターフェイスに定義するインスタンスメソッドは public な抽象メソッドであればよい。abstract などの記述があってもコンパイルは通る
  • 複数のインターフェイスに同名の default メソッドが定義されている状況で、両方を継承または実装すると default メソッドが競合してコンパイルエラーになる
    ただし、継承または実装する側で default メソッドをオーバーライドするとエラーは解消する
interface Sample {
    // "public abstract"が有っても無くてもコンパイルは通る
    public abstract void execute();
}

interface A { default void execute() { System.out.println("A"); } }
interface B { default void execute() { System.out.println("B"); } }
interface C extends A, B {
    // このコメントを外すとコンパイルエラーが解消する
    // default void execute() { System.out.println("C"); }
}

オーバーライドが成立するための条件

  • メソッドをオーバーライドする際、戻り値はスーパークラスの型と同じかそのサブクラスでなければいけない
  • メソッドのオーバーライドは、以下が一致しなければ成立しない。順番が一致しなくてもオーバーロードとなる
    1. メソッド名
    2. 引数の型
    3. 引数の順番
  • static メソッドや static フィールドもサブクラスで再定義できる
    ただしオーバーライドではなく「隠蔽」なので、super キーワードを使って親の static メソッドを呼び出すことはできない

メソッドローカルのクラス

  • メソッドローカルなクラスからメソッド内の変数を直接参照できるが、変数は実質的に final でないとダメ。final 宣言が無くても、メソッドローカルクラスから参照すると自動的に final 扱いになる。これはラムダも同様
  • コンストラクタでメソッドの変数をメソッドローカルなクラスに与える場合は、元の変数を直接参照しないので final にしなくてもよい
  • メソッドローカルなクラスからメソッドの外側のクラスのメンバ変数を参照する場合も、そのメンバ変数を変更して構わない

ラムダ式

  1. 引数のデータ型は省略可
  2. 引数が1つなら『()』が省略可
  3. 右辺の式が1つなら、右辺からの戻り値があっても無くても『{}』が省略可
  4. 右辺の式が1つで、かつ戻り値を返すなら return が省略可

関数型インターフェイス

Function 関連

インターフェイス メソッド 戻り値の型
Function<T, R> apply(T t) R
UnaryOperator<T> apply(T t) T
BinaryOperator<T> apply(T t1, T t2) T
BiFunction<T, U, R> apply(T t, U u) R

Consumer 関連

インターフェイス メソッド 戻り値の型
Consumer<T> accept(T t) void
BiConsumer<T, U> accept(T t, U u) void

Predicate 関連

インターフェイス メソッド 戻り値の型
Predicate<T> test(T t) boolean
BiPredicate<T, U> test(T t, U u) boolean

Supplier

インターフェイス メソッド 戻り値の型
Supplier<T> get() T

プリミティブ型を受け取る関数型インターフェイス

  • int、long、double の3つにはそれぞれ専用の関数型インターフェイスが存在する
    boolean にも BooleanSupplier だけ は存在する
  • SupplierUnaryOperatorBinaryOperator のメソッド名は下記に従う
    ルール:【メソッド名】As【データ型】
    例:applyAsIntgetAsBoolean など
データ型 Function Consumer Predicate Supplier UnaryOperator BinaryOperator
int IntFunction<R> IntConsumer IntPredicate IntSupplier IntUnaryOperator IntBinaryOperator
long LongFunction<R> LongConsumer LongPredicate LongSupplier LongUnaryOperator LongBinaryOperator
double DoubleFunction<R> DoubleConsumer DoublePredicate DoubleSupplier DoubleUnaryOperator DoubleBinaryOperator
boolean - - - BooleanSupplier - -

プリミティブ型を返す関数型インターフェイス

インターフェイス名 メソッド 説明
ToIntFunction<T> applyAsInt(T t) T型の値から int を返す
ToIntBiFunction<T, U> applyAsInt(T t, U u) T型とU型の値から int を返す
ToLongFunction<T> applyAsLong(T t) T型の値から long を返す
ToLongBiFunction<T, U> applyAsLong(T t, U u) T型とU型の値から long を返す
ToDoubleFunction<T> applyAsDouble(T t) T型の値から double を返す
ToDoubleBiFunction<T, U> applyAsDouble(T t, U u) T型とU型の値から double を返す

メソッド参照

  • 関数型インターフェイスの中だけで使える
  • 引数を取る場合は static メソッド参照と同じ書き方にする

コレクション

Arrays#asList

  • Arrays#asList で生成されるリストは、引数に与えられた配列を参照しているだけ。元の配列に加えた変更もリストに反映される
  • Arrays#asList で生成されるリストは ArrayList<E>互換性がない。 キャストしても失敗する

コレクションクラスの性質と見分け方

  • List は原則インデックスの順番
  • SetMap はクラス名のプレフィクスによって性質を見分ける
    • Linked で始まるクラスは、挿入した順序が保たれる
    • Tree で始まるクラスは自然順などによってソートされる。自然順で並べると 数字→英字(大)→英字(小) となる

Queue インターフェイスの性質

  • 挿入/削除/検査のメソッドが2種類あり、メソッドの実行に失敗した時の挙動が違う
    • 例外が発生
      • 挿入 … add(E)
      • 削除 … remove()
      • 検査 … get()
    • null を返却
      • 挿入 … offer(E)
      • 削除 … poll()
      • 検査 … peek()
  • インデックスで要素にアクセスできない

Deque インターフェイスの性質

  • Queue との違いは、 Double Ended Queue の名前通り、先頭または末尾に要素を挿入または削除できること
    • 例外が発生
      • 挿入 … addFirst(E), push(E) / addLast(E)
      • 削除 … removeFirst() / removeLast()
      • 検査 … getFirst(), pop() / getLast()
    • null を返却
      • 挿入 … offerFirst(E) / offsetLast(E)
      • 削除 … pollFirst() / pollLast()
      • 検査 … peekFirst() / peekLast()
  • Queue と同じで、インデックスでは要素にアクセスできない
  • java.util.concurrent パッケージにある Queue インターフェイスの拡張にはタイムアウトを設定できるメソッドもある
    常に待ち時間が発生する訳ではなく、挿入や削除ができないとき待機が発生する
  • Deque の実装である ArrayDeque には null を入れることができない

ジェネリクス

ジェネリクスと型パラメータ

  • クラスに対して型パラメータを宣言する場合、以下の用途で型パラメータは使用できない
    • static メンバ
    • new 演算子によるインスタンスや配列の生成
    • instanceof による型の検証
    • .class の参照
  • 型パラメータが適用されたメソッドを使うときは型を明示してもしなくてもよい
  • 総称型の構文は以下の通り
    class クラス名<型パラメータ(, 型パラメータn)> {...}
  • クラス宣言で型パラメータを使う場合、extends キーワードは使えるが super キーワードは使えない
  • メソッドの構文は以下の通り
    宣言: <型パラメータ> 戻り値型 メソッド名(型 引数名) {...}
    使用: レシーバ.<型パラメータ>メソッド名(型 引数名) {...}

ワイルドカード

  • ワイルドカードは "*" ではなく "?""*" はKotlin)
  • ワイルドカードを class 宣言の型パラメータに使うことはできない
  • ワイルドカードの型は実行されるまで確定しないので、ワイルドカードを使って中のデータ型を指定したリストに追加するとコンパイルエラーになる
    例外として <? super XXXXX> で宣言されたリストに XXXXX と同じ型のオブジェクトを入れることはできる
  • ワイルドカードを使った場合、宣言されている内容から判断できる範囲で問題がなければコンパイルエラーにはならない。型に互換性がないことが明確になったら、コンパイルエラーになる

型パラメータにワイルドカードを使った場合にコンパイルエラーが起きるところ

  • 型パラメータにワイルドカードを使用すると、 実際にオブジェクトを追加するところ でコンパイルエラーになる

Comparable と Comparator

Comparable インターフェイス

  • java.lang パッケージに所属
  • 比較される対象になるためのインターフェイス
  • Comparable で実装すべきメソッドは compareTo(T o) のみ。比較相手より小さい場合は負の値を返し、等しい場合はゼロを、大きい場合は正の値を返す
  • クラス宣言時に Comparable<T> の型パラメータに与えるのは compareTo が引数に取るオブジェクトの型

Comparator インターフェイス

  • java.util パッケージに所属
  • 比較するためのインターフェイス。なお比較対象は Comparable インターフェイスを実装しているものに限らない
  • Comparator で実装すべきメソッドは以下の2つ(equals は任意)
    • compare(T t1, T t2)
    • equals(T o)
  • compare(T t1, T t2) では、t1がt2より大きい場合は正の値、t1とt2が等しい場合はゼロ、t1がt2より小さい場合は負の値を返す

Stream API

要素数が有限のストリームを生成

  • Collection#stream() -> Stream<E>
  • Arrays#stream(E[] array) -> Stream<E>
  • Arrays#stream(int[] array) -> IntStream
  • Arrays#stream(long[] array) -> LongStream
  • Arrays#stream(double[] array) -> DoubleStream
  • Stream#of(E… values) -> Stream<E>
  • Stream#empty() -> Stream<E>
  • IntStream#of(int… values) -> IntStream
  • LongStream#of(long… values) -> LongStream
  • DoubleStream#of(double… values) -> DoubleStream
  • IntStream#range()IntStream#rangeClosed() -> IntStream
  • LongStream#range()LongStream#rangeClosed() -> LongStream
  • BufferedReader#lines() -> Stream<String>
  • java.nio.file.Files#lines() -> Stream<String>

要素数が無限のストリームを生成

どちらも java.util.stream.Stream のメソッド

  • generate(Supplier<T> supplier)
    supplier から提供される要素を無限に保持する Stream を生成する
  • iterate(T seed, UnaryOperator<T> f)
    seed が最初の要素で、それ以降は前の要素に f をかけ合わせた要素を無限に保持する Stream を生成する

ストリームの終端操作

  • 同じストリームへの終端操作は1度だけ。複数回行うと IllegalStateException が発生する
  • 中間操作を呼び出しただけでは何も実行されず、終端操作を呼び出さない限り何も行われない。終端操作を呼び出すと全ての処理が実行される
  • パイプライン処理では、ストリーム内の要素が1つずつ順番に全ての中間/終端操作を実行されてから次の要素が処理される
    つまり 「要素1の中間操作×m→要素1の終端操作」⇒「要素2の中間操作×m→要素2の終端操作」⇒…⇒「要素nの中間操作×m→要素nの終端操作」 という順番

Stream#reduce の戻り値

Stream#reduceStream の中身を集約するためのメソッド。第1引数に初期値を設定するほうのメソッドでは、戻り値が Optional じゃない

  • reduce(BinaryOperator op) … 戻り値は Optional<T>
  • reduce(T initial, BinaryOperator op) … 戻り値は T

戻り値が Optional の終端操作

  • 戻り値が Optional になるのは以下のメソッド
    • findAny() … 実行するたびに結果が変わる可能性がある
    • findFirst() … 何度実行しても同じ結果が得られる
    • min()
    • max()
    • reduce(BinaryOperator op)
  • Stream の型によって Optional の型が違う。例えば findAny() なら以下の通り
    • Stream#findAny()Optional<T>
    • IntStream#findAny()OptionalInt
    • LongStream#findAny()OptionalLong
    • DoubleStream#findAny()OptionalDouble

Optional のインスタンスを生成する

  • Optional#of(T value) … valueにnullは入れられない
  • Optional#ofNullable(T value) … valueにnullを入れられる
  • OptionalInt#of(int value)
  • OptionalLong#of(long value)
  • OptionalDouble#of(double value)

Optional#ifPresent と Optional#isPresent

  • 値があるかどうか(null or not null)を判定するためのメソッドは以下の2つ
    1. isPresent() … 値の有無を判定する
    2. ifPresent(Consumer) … 値があれば Consumer を実行する

Optional から値を取り出すためのメソッドは複数存在する

Optional<T> から値を取得するメソッドは以下。値が存在する場合はその値が得られるが、存在しない場合の挙動が異なる

  • get()
    存在しない場合は NoSuchElementException
  • orElse(T)
    存在しない場合は引数を返す
  • orElseGet(Supplier<T>)
    存在しない場合は Supplier から返される値を返す
  • orElseThrow(Supplier<X extends Exception>)
    存在しない場合は Supplier から返される例外をスローする

特定のデータ型に特化した Optional の種類

Optional<T> の関連クラスと値を取り出すためのメソッドは以下

  • Optional<T>#get()
  • OptionalInt#getAsInt()
  • OptionalLong#getAsLong()
  • OptionalDouble#getAsDouble()

Stream と XXXStream の型変換

  • 同じ Stream 型同士の変換は map()
  • Stream<T> 型への変換は mapToObj()
  • IntStream 型への変換は mapToInt()
  • LongStream 型への変換は mapToLong()
  • DoubleStream 型への変換は mapToDouble()

Stream#collect() メソッドと Collector クラス

  • collect()Stream 内の要素を集約して、1つのオブジェクトを取得するメソッド
  • Collectors クラスは用途に合う Collector インターフェイスの実装を提供する
    その性質上、Stream クラスの一部メソッドと役割がかぶる

例外

Error、Exception、 RuntimeException

  • 全て Throwable のサブクラスで、java.lang パッケージに所属
  • ErrorExceptionThrowable のサブクラス
  • RuntimeExceptionException のサブクラス(Throwable の孫クラス)
  • try〜catch が必須となる checked 例外は RuntimeException 以外の Exception のサブクラスだけ

例外を catch する順番

  • 例外はサブクラスから順番に catch すること
  • スーパークラスをサブクラスより先に catch するとコンパイルエラーになる
    ※実行時エラーではない

例外のマルチキャッチ

  • 継承関係のある複数の例外をまとめてキャッチするとコンパイルエラー
  • マルチキャッチしたときの例外オブジェクトは暗黙的に final 扱いになり再代入は不可
    マルチキャッチでない場合は、final 扱いにならない

例外の rethrow

  • 1つのメソッドが複数種類の例外オブジェクトを catch して rethrow する場合、throws および catch メソッドで取る例外は一致しなくてもよい
  • catch で起こりうる全ての例外の親クラスを拾って、そのまま throw する場合など
// SE7以降では、2つの例外をまとめて catch してもよい
// executeからthrowされるのも、Exceptionではなく IllegalAccessExceptionとArighmeticException
private void execute(int number) throws IllegalAccessException, ArithmeticException {
    try {
        switch (number) {
            case 1:
                throw new IllegalAccessException();
            case 2:
                throw new ArithmeticException();
            default:
                System.out.println("No exception");
        }
    } catch (Exception e) {
        throw e;
    }
}

例外をthrowするメソッドのオーバーライド

  • throws 宣言つきのメソッドをサブクラスでオーバーライドする場合、オーバーライドしたメソッドに throws 宣言をするかどうかは自由
  • オーバーライドしたメソッドでも throws を宣言する場合の例外は、元のメソッドと同じかそのサブクラスでなければならない
  • RuntimeException とそのサブクラスは無条件で throws に指定できる。ただし非チェック例外なので、呼び出し元で catch しなくてもコンパイルは通る

try〜with〜resources 文

  • try〜with〜resources 文でのみ try 単体での使用が可能
  • 使用するリソースは java.lang.AutoCloseable か、そのサブインターフェイスである java.io.Closeable を実装する必要がある
  • AutoCloseableCloseable はどちらも close()throws 宣言があるため、リソースに使う場合も try の中で使う場合も、例外を catch しないとコンパイルエラー
    • AutoCloseable#close() throws Exception
    • Closeable#close() throws IOException
  • AutoCloseable もしくは Closeableclose() で例外が発生したら、catch で補足される
  • try ブロックとリソースのクローズの両方で例外が発生したら、close() で起きた例外は抑制された例外として catch された例外オブジェクトに Throwable の配列で格納され、getSuppressed() で取得が可能
  • try〜with〜resources 文で例外が起きたときの実行順序は以下
    1. try ブロック
    2. 宣言した逆順にリソースをクローズ(下記のコードだと、Nから1へ順番に閉じる)
    3. catch ブロック
    4. finally ブロック
// (1) -> ResourceNから1の順番にclose() -> (2) -> (3) の順に実行
try (Resource1; Resource2; ...; ResourceN) {
    (1)
} catch (Exception e) {
    (2)

    // getSuppressed() で撮れるのは Throwable の配列
    for (Throwable th : e.getSuppressed()) { ... }
} finally {
    (3)
}

アサーションとその利用方法

  • アサーションは、assert 文で false が検出されたら AssertionError を投げる機能で、文法は以下の通り
    assert boolean式: エラーメッセージ;
  • boolean 式は括弧で括っても括らなくてもOK
  • エラーメッセージは省略可
  • アサーションはデフォルトでは無効。java コマンドで "-ea" オプション("enable assertion" の略?)を明示的に指定しないと、AssertError はスローされない
  • 明示的に無効にするには、java コマンドで "-da" オプション("disable assertion" の略?)を指定する
  • アサーションの対象だと明示したいなら java -ea:【クラス名】 として、コロン区切りでアサーションの対象(-daなら非対象)を指定する

Date and Time API

クラス一覧

  1. LocalDate … 日付
  2. LocalTime … 時刻
  3. LocalDateTime … 日付+時刻
  4. OffsetTime … UTC/GMTからの差分を「+hh:mm」で含む時刻
  5. OffsetDateTime … UTC/GMTからの差分を「+hh:mm」で含む日付&時刻
  6. ZonedDateTime … UTC/GMTからの差分をタイムゾーンIDで含む日付+時刻
  • 全て Temporal インターフェイスを実装する。更にそのスーパーインターフェイスは TemporalAccessor
  • "Local〜" と "Offset〜" と "Zoned〜" の違いは、同じ日時を表現する方式の違い
  • LocalDateTime#toLocalDate()LocalDateTime#toLocalTime() でそれぞれへの変換が可能
  • 月を取得できるメソッドは2つ
    • getMonth()Month 列挙値で取得
    • getMonthValue() … int 値で取得

列挙型一覧

  1. Month:月を表す
    JANUARY, FEBRUARY, MARCH, …, DECEMBER
  2. DayOfWeek:曜日を表す
    SUNDAY, MONDAY, TUESDAY, …, SATURDAY

LocalDate / LocalTime / LocalDateTime のインスタンス化

  1. now()
  2. of(year, month, dayOfMonth, ...)
    それぞれのクラスが扱える値を引数にしてインスタンスを生成する
    引数 month には整数でなく Month 列挙値をセットしてもOK
    LocalDateTime のみ LocalDateLocalTime を引数に取るオーバーロードがある。年、月、日、時、分、秒、ミリ秒を引数に取るのもある
  3. parse(String)parse(String, DateTimeFormatter)
    文字列からインスタンスを生成
    DateTimeFormatter を併用すると任意のフォーマットの文字列でも可

LocalDate#of および LocalTime#of のオーバーロード

  • LocalDate#of には2つのオーバーロードメソッドがある。どちらも年月日は指定するが、それ以外の違いは以下の通り
    1. 第2引数が int
    2. 第2引数が Month 列挙値
  • LocalTime#of には3つののオーバーロードメソッドがあり、全て時分は指定するが、それ以外の違いは以下の通り
    1. 時分のみ
    2. 時分に加えて秒を指定
    3. 時分に加えて秒とナノ秒を指定

java.time.format.DateTimeFormatter

  1. ofPattern(String)
    フォーマットパターンを指定
  2. ofLocalizedDate(FormatStyle)
    日付のフォーマット方式を指定
  3. ofLocalizedTime(FormatStyle)
    時間のフォーマット方式を指定
  4. ofLocalizedDateTime(FormatStyle)
    日時のフォーマット方式を指定
  5. ofLocalizedDateTime(FormatStyle, FormatStyle)
    日時のフォーマット方式を、日付と時間で別々に指定
  6. static で事前定義されたフォーマッタ
    BASIC_ISO_DATE など

java.time.format.FormatStyle

FormatStyle は4種類

  • FormatStyle.FULL
    タイムゾーンを含む完全な書式。ゾーン情報を持たない LocalDateTime などに適用すると実行時に例外
  • FormatStyle.LONG
    タイムゾーンを含む簡潔な書式。ゾーン情報を持たない LocalDateTime などに適用すると実行時に例外
  • FormatStyle.MEDIUM
    タイムゾーンを含まない簡潔な書式
  • FormatStyle.SHORT
    タイムゾーンを含まない簡潔な日時までの書式
LocalDateTime dateTime = LocalDateTime.of(2020, 8, 14, 9, 54, 30);
ZonedDateTime zDateTime =
    ZonedDateTime.of(dateTime, ZoneId.systemDefault());

// FormatStyle.FULL … 『2020年8月14日 9時54分30秒』
println(fmt1.format(zDateTime));

// FormatStyle.LONG … 『2020/08/14 9:54:30 JST』
println(fmt2.format(zDateTime));

// FormatStyle.MEDIUM … 『2020/08/14 9:54:30』
println(fmt3.format(dateTime));

// FormatStyle.SHORT … 『20/08/14 9:54』
println(fmt4.format(dateTime));

Date and Time API のフォーマット文字列

  • "y" … 年
  • "M" … 月(大文字)
  • "d" … 日
  • "H" … 時(大文字)
  • "m" … 分
  • "s" … 秒
  • "S" … ミリ秒(大文字)
  • "n" … ナノ秒

日付/時刻の加減算

加算 … plus(TemporalAmount amountToAdd)
減算 … minus(TemporalAmount amountToSubtract)

  • PeriodDurationTemporalAmount インターフェイスを実装する
  • plusYearsplusWeeks など個々のフィールドに対する加減算も可能だが、複数のフィールドをまとめて扱う場合は PeriodDuration を引数にして plus を呼び出す

夏時間

  • 夏時間の適用開始日(時間を進める日)と適用終了日(時間を戻す日)は、同じ地域でも毎年異なる。ただし時刻は 02:00 で一定
  • 適用が開始されると、オフセットが1時間減り時刻が1時間進む
    02:00 から1時間進むので、01:59 の1分後は 03:00 になる
    適用開始日に 01:00 と 03:00 の間隔を取ると、2時間ではなく1時間
  • 適用が終了すると、オフセットが1時間増え時刻が1時間戻る
    02:00 から1時間戻るので、01:59 の1分後は 01:00 になる

Period:年月日

  • toString() した Period 表現は "P00Y00M00D" となる
    先頭の "P" は "Period" の頭文字
  • Period のインスタンスを生成する方法はいくつかある
    • between メソッドで2つの LocalDateLocalDateTime の差分を取る
    • ofYears(1) など ofXXXXX メソッドで生成。ただしメソッドチェーンは不可
  • Period は年、月、日、週で加減算できる
    加減算のメソッドは plusXXXXX / minusXXXXX。plusYears(1) など
    plusWeeks(3) で週を加算すると "P21D"。週の Period 表現が無い為
  • LocalDate / LocalDateTimeplus / minus メソッドで Period を引数にして日付の加減算ができる
// Period を使った年の加算
LocalDateTime dt = LocalDateTime.now();
Period p = Period.ofYears(1);

// これは以下の2行と同等(メソッドチェーンは意味がない)
// Period p1 = Period.ofDays(1);
// Period p = Period.ofYears(2);
Period p = Period.ofDays(1).ofYears(2);

Duration:時分秒

  • toString() した Duration 表現は "PT00H00M00S" となる
    先頭の "PT" は "Period of Time" の略称
  • Duration のインスタンスを生成する方法はいくつかある
    • between メソッドで2つの LocalDateTimeLocalTime の差分を取る
    • ofHours(1) など ofXXXXX メソッドで生成
    • of(1, ChronoUnit.HOURS) など of メソッドで ChromeUnit を併用して生成
  • Duration は日、時、分、秒、ミリ秒、ナノ秒で加減算できる
    日を加算したら PT24H で、ミリ秒以下だと PT0.13S となる
  • LocalTime / LocalDateTimeplus / minus メソッドで Duration を引数にして時分秒の加減算ができる

java.time.Instant

  • エポック時間からの経過を表現するクラス
  • インスタンスを生成する方法はいくつかある
    1. Instant#now()
    2. Instant#ofEposSecond(long)
    3. Instant#ofEpocMilli(long)
    4. LocalDateTime#toInstant(ZoneOffset)
    5. ZonedDateTime#toInstant()
  • LocalDateTime#toInstantZoneOffset が必要なのは LocalDateTime にタイムゾーンの情報が含まれていない為
  • Instant のタイムゾーンは常にUTC

入出力

java.io.Reader を使った読み込み

  • Reader
    • public int read()
      読み込んだ1文字を返す。末尾に到達したら -1
    • public int read(char[] buffer)
    • public int read(char[] buffer, int offset, int length)
      読み込んだ文字を配列の一部または全部に入れて文字数を返す。末尾に到達したら -1
  • BufferedReader
    • public String readLine()
      読み込んだ1行のテキストを返す。末尾に到達したら null

java.io.Writer を使った書き込み

  • Writer
    • public void write(char[] buffer)
    • public void write(char[] buffer, int offset, int length)
      配列の一部または全部を書き込む
    • public void write(int c)
      1文字書き込む
    • public void write(String str)
    • public void write(String str, int offset, int length)
      文字列の一部または全部を書き込む
  • BufferedWriter
    • public void newLine()
      改行文字を書き込む

java.io.Reader や java.io.InputStream の読み込み位置制御

  • skip(long bytes)
    現在位置から指定したバイト数だけ読み飛ばす
  • mark(int readAheadLimit)
    現在位置をマークして reset() で戻れるようにする。引数は マークを維持しつつ読み込むことができる文字数の上限
  • reset()
    mark() した位置に戻る
// ファイルの中身は "01234567"
// 実行結果は "025676"
try (BufferedReader br =
        new BufferedReader(new FileReader("sample.txt"))) {
    for (int i = 0; i < 3; i++) {
        br.skip(i); // iバイトを読み飛ばす
        System.out.print((char)br.read());
    }
    br.mark(3); // 現在位置("6"のあるINDEX=5の場所)をマーク
    System.out.print(br.readLine());
    br.reset(); // マークした位置(INDEX=5の場所)に戻る
    System.out.println((char)br.read());
} catch (IOException e) {
    e.printStackTrace();
}

java.io.PrintWriter

  • java.io.Writer のサブクラスで、プリミティブ型をそのまま出力できる
    boolean/char/char[]/int/float/long/String/Object が対象
  • printprintln 以外に format を使って文字列のフォーマットが可能
  • 自動フラッシュ機能を持つ
  • 同じ機能を持つクラスに PrintStream がある
    JDK1.2で PrintWriter にとって変わられたが、後方互換のため残っている

java.io.Console

  • 標準入力からデータを読み取る
  • System#console() でシングルトンインスタンスを取得。 利用不可なら null が返る
  • readLine() で、入力された文字列を String で取得
  • readPassword() で、入力された文字列を char[] で取得。パスワードの読み取りなので、入力時に文字列は表示しない
  • writer()reader() で、それぞれコンソールに紐づいている PrintWriterReader を取得できる
  • Console 自身にも printfformat メソッドがあり、コンソールに文字列を出力できる

シリアライズに関する注意点

  • java.io.Serializable インターフェイスを実装したクラスはシリアライズ可能
  • シリアライズ対象外になるのは以下のどちらか
    1. static 変数
    2. transient 宣言されているメンバ変数
  • スーパークラスがシリアライズ可能なら、サブクラスもシリアライズ可能
  • デシリアライズでは、インスタンス初期化ブロックも、コンストラクタも呼び出されない。ただし static 初期化ブロックは呼び出される
    また、以下のケースならスーパークラスのコンストラクタだけは呼び出される
    1. 自身は Serializable だが、スーパークラスが Serializable ではない
    2. スーパークラスに引数なしのコンストラクタがある
    3. サブクラスのコンストラクタで明示的に親のコンストラクタを呼び出していない
  • メンバ変数のシリアライズ可否は、フィールドではなく中身のデータ型で決まる
    変数の型が何であれ、中身が Serializable ならシリアライズ可能

NIO2

java.nio.file.Path(特徴)

  • 以下のメソッドで生成
    • Paths#get(String, String...)
    • FileSystem#getPath(String, String...)
  • 主な特徴は以下の通り。java.io.File にない機能を備える
    • ファイルやディレクトリのパスを扱う
    • ファイル属性(オーナー、パーミッションなど)の取得や変更が可能
    • シンボリックリンクを扱える
    • ファイル作成など、ディレクトリで発生したイベントの変更や監視が可能
  • java.io.File との相互変換が可能
    • File#toPath()
    • Path#toFile()

java.nio.file.Path(メソッド)

  • getRoot()
    パスのルートを返す。相対パスで生成した Path からは null
  • subpath(int start, int end)
    ルートを除く、インデックスで指定された範囲を抜き出した Path を生成する
  • getName(int)
    ルートを除く、インデックスで指定された部分を String で返す
  • relativize(Path)
    引数までの相対パスを返す
  • resolve(String)resolve(Path)
    パスを解決する。引数によって戻り値となる Path は異なる
    • 引数が相対パス … レシーバーに引数を連結して返す
    • 引数が絶対パス … 引数をそのまま返す
    • 引数が空 … レシーバー自身を返す
  • resolveSibling(String)resolveSibling(Path)
    レシーバーの親に対してパスを解決する。引数によって戻り値となる Path は異なる
    • 引数が絶対パス…レシーバーに引数を連結して返す
    • その他…レシーバーに引数を連結して返す
  • normalize()
    「.」や「..」など冗長な部分を除去して適切な形に変換したパスを返す
String sp1 = "/tmp/work1/sample.txt";
String sp2 = "/tmp/work2/dummy.txt";
Path p1 = Paths.get(sp1);
Path p2 = FileSystems.getDefault().getPath(sp2);
println(p1.getRoot());      // "/"
println(p1.subpath(0, 2));  // "tmp/work1"
println(p1.relativize(p2)); // "../../work2/dummy.txt"
println(p1.getName(0));     // "tmp"

Path rp = p1.resolve("../dat");
println(rp);                // "/tmp/work1/sample.txt/../dat"
println(rp.normalize());    // "/tmp/work1/dat"

// Windows の場合
Path wp = Paths.get("C:¥¥temp¥¥work¥¥sample.txt");
println(wp.getRoot());      // "C:¥"

java.nio.file.FileSystem

ファイルシステムへのインターフェイスを提供する。FileSystems クラスの static メソッドで取得

  • FileSystems#getDefault
  • FileSystems#getFileSystem
  • FileSystems#newFileSystem

java.nio.file.Files(ファイル操作)

以下は全て static メソッド

  • copy
    ファイルやディレクトリのコピー
    1. ディレクトリの中身まではコピーされない
    2. コピー先に同名のファイルが存在する時 CopyOption で上書き指定が無ければ例外
    3. デフォルトの挙動ではファイルをコピーしても属性はコピーされない
    4. CopyOption を指定せずにシンボリックリンクをコピーすると、リンクが示す実体がコピーされる
    5. 引数に与えるパスはコピー/移動をする場所ではなく、移動/コピー後のパス
  • move
    ファイルやディレクトリの移動。挙動は copy の1〜5と同じ
  • getAttribute(Path, String, LinkOption...)
    ファイルの属性値(ファイルサイズや更新日時など)を読み取る
  • Stream<String> lines(Path)
  • List<String> readAllLines(Path)
    ファイルの全ての行を返す。メソッドによって戻り値の型が異なる

java.nio.file.Files(ディレクトリの操作)

以下は全て static メソッド

  • createDirectory()
    ディレクトリを作成するが、親は作成しない
  • createDirectories()
    親も含めてディレクトリを作成する
  • deletedeleteIfExists
    ファイルを削除する。失敗したら前者は例外、後者は boolean 型で結果が返る
    どちらもディレクトリの中にファイルがあると削除できず、例外が発生する
  • newDirectoryStream(Path)
    ディレクトリ内のパスを Iterable の実装クラス DirectoryStream<Path> で返す
  • list(Path)
    ディレクトリ内のファイルやディレクトリの一覧を Stream<Path> で返す。引数がディレクトリでない場合は例外が発生する

java.nio.file.Files(ディレクトリの検索)

以下は全て static メソッド

  • walk()
  • walkFileTree()
    サブディレクトリも含めて再帰的に検索する
  • list()
    そのディレクトリだけを検索する
  • find()
    サブディレクトリも含めて再帰的に、条件に合致するものを検索する
  • これらの戻り値は全てストリームなので、パイプライン処理が可能

java.nio.file.attribute

ファイルの属性(作成時間、アクセス時間、所有者など)を表現するクラスが入ったパッケージ。属性情報のセットを示す属性ビューインターフェイスも含む

  • BasicFileAttributes インターフェイス
    基本的な属性情報
  • DosFileAttributes インターフェイス
    DOS系の属性情報
  • PosixFileAttributes インターフェイス
    Unix/Linuxの属性情報
  • AttributeView インターフェイス
    属性情報のセット。サブインターフェイスとして以下が存在する
    • BasicFileAttributeView
    • DosFileAttributeView
    • PosixFileAttributeView

並列処理

並行処理ユーティリティが提供する機能

  1. スレッドプール
    スレッドの生成と再利用
  2. 並行コレクション
    複数スレッドからの並行アクセスを適切に処理できるコレクション
  3. アトミック変数
    並行アクセスによって値の不整合を起こさないための分割不可能な一連の操作を実装(synchronized と同じ)
  4. カウウンティング・セマフォ
    有限なリソースに対して並行アクセス可能なスレッド数を自由に設定可能

並列コレクション

  • 並列処理に関わるAPIは以下。全て java.util.concurrent パッケージ
    • BlockingQueue インターフェイス
    • BlockingDeque インターフェイス
    • ConcurrentMap インターフェイス
    • ConcurrentHashMap クラス
    • CopyOnWriteArrayList クラス
    • CopyOnWriteArraySet クラス
  • 並列処理に対応していないコレクションオブジェクトを複数のスレッドから操作すると java.util.ConcurrentModificationException が発生する
  • 複数のスレッドから操作するときに拡張for文などでイテレータを使うと、イテレータを生成した時点のコレクションの中身が使用される

java.util.concurrent.ConcurrentMap インターフェイス

  • V getOrDefault(Object key, V defaultValue)
    key に紐づく値を返す。無ければ defaultValue を返す
  • V putIfAbsent(K key, V value)
    key に紐づく値がマップにない場合のみ追加
  • boolean remove(Object key, Object value)
    key と value の両方が一致する要素があれば削除
  • V replace(K key, V value)
    key に指定した値がマップにあれば置換
  • V replace(K key, V oldValue, V newValue)
    key と oldValue の両方が一致する要素があれば値を newValue に置換
// map の中身は [1, "One"], [2, "Two.2"], [3, "Three"]
Map<Integer, String> map = new ConcurrentHashMap<>();
map.put(1, "One");
map.putIfAbsent(1, "One.2"); // 追加しない(KEY=1の要素が既存)
map.put(2, "Two");
map.replace(2, "Two.2");           // 置換
map.replace(2, "Two.22", "Two.3"); // 置換しない(第2引数が既存の値と違う)
map.put(3, "Three");     // 削除
map.remove(3, "Three2"); // 削除しない(第2引数が既存の値と違う)

java.util.concurrent.CopyOnWriteArrayList クラス

  • 内部で保持している要素を変更するときは、古い要素が入った配列をコピーしてそれを変更し、差し替える
    そのため、リストのサイズが大きくなるとオーバーヘッドが肥大化する
  • 要素の変更中(新しい配列へのコピー中)に別のスレッドがリストにアクセスすると、古い配列の内容を参照することになる

java.util.concurrent.CyclicBarrier クラス

  • スレッドパーティー(強調して動作するスレッドの集合)内の各スレッドの足並みを揃えるための機能を提供
  • コンストラクタで協調させるスレッドの数を指定。第1引数は協調させるスレッドの数、第2引数があれば、トリップ(=バリアが解除)したときに実行される処理
    • new CyclicBarrier(int)
    • new CyclicBarrier(int, Runnable)
  • await() を実行したスレッドは CyclicBarrier のコンストラクタで指定した数のスレッドが await するまで待機する
    • await(long timeout)
      タイムアウトなし
    • await(long timeout, TimeUnit unit)
      タイムアウトあり
  • 4つのスレッドに対して new CyclicBarrier(3) とすると、3つのスレッドが await した時点でトリップが発生する
    しかし最後の1つは、さらに2つのスレッドが await するまでバリアを突破できないので、続きの処理は実行できない
// バリアの許容数が2つに対してスレッドが3本なので、
// "wait wait wait finish finish" と出て処理が止まる
ExecutorService service = Executors.newCachedThreadPool();
CyclicBarrier barrier = new CyclicBarrier(2);
for (int i = 0; i < 3; i++) {
    service.execute(() -> {
        try {
            System.out.print("wait ");
            barrier.await();
            System.out.println("finish ");
        } catch (BarrierBrokenException | InterruptedException ignore) {
        }
    });
}
service.shutdown();

ExecutorService の継承関係

  • Executorexecute(Runnabble)
    • ExecutorServicesubmit(Runnable) など
      • ThreadPoolExecutor
      • ForkJoinPool
    • ScheduledExecutorServiceschedule(Runnable,long,TimeUnit)
      • ScheduledThreadPoolExecutor

Executorsのメソッドとそれぞれに対応するExecutorServiceのスペック

  • newSingleThreadExecutor()
    単一のスレッドでタスクを実行
  • newCachedThreadPool()
    必要に応じて新規スレッドを生成、もしくは再利用してタスクを実行
  • newFixedThreadPool(int)
    固定数のスレッドを再利用してタスクを実行
  • newScheduledThreadPool(int)
    固定数のスレッドを再利用してタスクを実行。タスクはスケジュール可能
  • newSingleThreadScheduledExecutor()
    単一のスレッドでタスクを実行。タスクはスケジュール可能

ExecutorService#execute

  • Executors クラスの static メソッドで適切な性質の ExecutorService オブジェクトを取得して execute(Runnable) メソッドで実行
  • タスクの実行状態を確認するには以下のメソッドを使う
    • isShutdown()
      true なら新規タスクは受入不可(未実行か実行中のタスクがある可能性)
    • isTerminated()
      true なら新規タスクは受入不可、かつ全てのタスクが終了した状態
  • isShutdown() が true でなければ、新規タスクの execute が可能。true のときに execute すると例外が発生する

ExecutorService#submit

  • ExecutorService に複数のオーバーロードメソッドがあり、戻り値は Future。メソッドによって Future から get できるものが異なる
    • Future<T> submit(Runnable)
      タスクを実行。get できるのはタスクの成否
    • Future<?> submit(Runnable, T)
      第1引数のタスクを実行し、第2引数の値を返す。get できるのはタスクの成否
    • Future<T> submit(Callable<T>)
      タスクを実行。get できるのはタスクからの戻り値
  • タスクはすぐ実行されるが、 Future#get() を実行するとタスクが終了した後も値が取得できるまで待機時間が発生する
  • Future<T> からは submit したタスクのキャンセルもできる(可能な場合のみ)

Runnable と Callable

  • Runnable
    • 戻り値を返さない
    • チェック例外をスローできない
    • execute でも submit でも実行できる
  • Callable
    • 戻り値を返すことができる
    • チェック例外をスローできる
    • submit でしか実行できない

java.util.concurrent.Future インターフェイス

  • V get()
    タスクの実行結果を取得できる
  • boolean cancel(boolean)
    タスクのキャンセルを試みる
  • boolean isCancelled()
    タスクがキャンセルされたかを知る
  • boolean isDone()
    タスクが完了しているかどうかを知る

パラレルストリーム

  • 生成
    • Collection#parallelStream()
      コレクションからパラレルストリームを生成
  • 相互変換
    • BaseStream#parallel()
      シーケンシャルストリームからパラレルストリームを生成
    • BaseStream#sequential()
      パラレルストリームからシーケンシャルストリームを生成
  • 判定
    • BaseStream#isParallel()
      自身がパラレルストリームかどうかを判定
// パラレルストリームの生成
Arrays.asList(1, 2, 3).parallelStream().forEach(System.out::println);

// シーケンシャルストリームからパラレルストリームを生成
Stream.of("a", "b", "c").parallel().forEach(System.out::println);

// パラレルストリームからシーケンシャルストリームを生成
Arrays.asList("A", "B", "C").parallelStream().sequential().forEach(System.out::println);

Fork/Joinフレームワーク

※ 私はここを捨てました。真面目な方はちゃんと勉強しましょう

アトミック変数

  • Atomic〜 で始まる名前のクラスは、自身が扱う値への操作がスレッドセーフになることを保証する
  • 主なクラスは以下。Float や Double は存在しない
    • AtomicInteger … int型
    • AtomicLong … long型
    • AtomicBoolean … boolean型
    • AtomicReference … 参照型

JDBC

クエリの実行

  • 使用するクラスが所属するパッケージは java.sqljavax.sql
  • JDBC で DB に接続するための URL フォーマットは以下の通り
    jdbc:[DB名]//[host(:port)]/[db-name](?option)
  • 基本的な処理の流れは以下の通り
    1. DriverManager#getConnection(url,id,pass)Connection 取得
    2. Connection#createStatement()Statement 取得
    3. Statement#executeQuery(sql)ResultSet 取得
    4. ResultSet からクエリの結果を取り出す
  • JDBC3.0 以前では DriverManager#getConnection の前に Class.forName([JDBCドライバクラス名]) を実行する必要があった
  • executeQuery で実行するクエリの結果が0件でも戻り値は null ではなく、空の ResultSet になる
  • 1つの Statement で扱える ResultSet は1つだけ。最初の ResultSet を閉じずに別の ResultSet を取得すると、最初のは自動的に閉じられる。閉じられた ResultSet を操作しようとすると例外
    executeUpdate などを実行したときも自動で閉じる

Statementにあるメソッドの使い分け

  • ResultSet executeQuery(String sql)
    クエリの実行結果を返す
  • int executeUpdate(String sql)
    INSERT/UPDATE/DELETEなどのSQLを実行し、処理件数を返す
  • boolean execute(String sql)
    クエリを含む、あらゆる種類の SQL を実行して処理の結果として ResultSet が得られたかを返す。true なら ResultSet が返ってきており、false ならそうではない
    処理の結果 ResultSet が返ってきたなら Statement#getResultSet() で取得する。 ResultSet でなければ Statement#getUpdateCount() で処理件数を取得する

ResultSet の取得と性質

  • Connection#createStatement(type, concurrency)ResultSet の「スクロール可否」と「テーブルデータの更新可否」を順番に指定する
  • スクロール可否は以下の3種類で、全て ResultSet クラスの定数
    • TYPE_FORWARD_ONLY … 順方向にのみ移動可
    • TYPE_SCROLL_INSENSITIVE … 双方向に移動可。カーソルへの変更は反映しない
    • TYPE_SCROLL_SENSITIVE … 双方向に移動可。カーソルへの変更を反映する
  • テーブルデータの更新可否は以下の2種類で、全て ResultSet クラスの定数
    • CONCUR_READ_ONLY … 読み込みのみ
    • CONCUR_UPDATABLE … 更新可能
  • Statement#createStatement(..., ResultSet.CONCUR_UPDATABLE) で更新可能な ResultSet を取得する時、更新対象とするカラムを executeQuery の select 文に指定しておかなくてはならない

ResultSet のスクロール用メソッド

  • boolean absolute(int)
    指定した行(絶対位置を指定)へ移動。先頭行は1。0はbeforeFirst
  • boolean relative(int)
    相対位置を指定して移動。正の値なら次の行へ、負の値なら前の行にゆく
  • boolean next()
    ひとつ次の行に移動
  • boolean previous()
    ひとつ前の行に移動
  • boolean first()
    先頭行に移動
  • void beforeFirst()
    先頭行の直前に移動
  • boolean last()
    最終行に移動
  • void afterLast()
    最終行の直後に移動

更新可能な ResultSet

  • 更新
    updateStringupdateInt で変更し updateRow で変更を確定させる
    Statement のタイプが TYPE_SCROLL_INSENSITIVE でも updateRow しない限り、DB の中身どころか結果セットさえ変更されない
    • updateString(int, String)
    • updateInt(int, int)
    • updateRow()
  • 挿入
    moveToInsertRow で挿入行に移動し updateStringupdateInt で挿入内容を指定して insertRow で挿入する
    • moveToInsertRow()
    • insertRow()
  • 削除
    現在行を削除する
    • deleteRow()

ローカライズとフォーマット

java.util.Locale オブジェクトの取得

  1. Locale#getDefault()
    Java実行環境のロケール
  2. new Locale(String)
    引数は「言語コード」
  3. new Loacle(String, String)
    引数は「言語コード, 国コード」
  4. new Loacle(String, String, String)
    引数は「言語コード, 国コード, バリアント」
  5. new で生成した Locale.Builder に適切な値を設定して build() で生成

java.util.Properties

  • サポートするファイルフォーマットはテキストとXML
  • テキストファイルの場合、キーと値を = もしくは : で区切って列挙する
  • ファイルからプロパティリストをロード
    • load(InputStream)
    • load(Reader)
    • loadFromXML(InputStream)
  • プロパティリストを出力
    • list(OutputStream)
    • list(Writer)
    • entrySet()
    • forEach(BiConsumer)
  • プロパティの取得
    • getProperty(String)
      該当するKeyが無ければ null を返す
    • getProperty(String, String)
      該当するKeyが無ければ第2引数を返す

java.util.ListResourceBundle

  • リソースを .class ファイルで用意してクラスパスが張られている場所に置く
  • 使い方は以下の通り
    1. ListResourceBundle を継承した public クラスを定義
      public Object[][] getContents() をオーバーライド
      このクラスの完全修飾名(パッケージ名+クラス名)が基底名に、このクラスがデフォルトロケール用になる
      例:クラス名は "MyResource" とする
    2. 1とは異なるロケール用のクラスを ListResourceBundle を継承して定義する
      ネーミングルールは 「基底名_言語コード_国コード」
      例:英語ロケール用のクラス名は "MyResource_en_US" となる
    3. ResourceBundle#getBundle(基底名[, ロケール])ListResourceBundle オブジェクトを取得
    4. ResourceBundle#getXXXXX(キー文字列) で値を取り出す

java.util.PropertyResourceBundle

  • リソースを .properties ファイルで用意してクラスパスが張られている場所に置く
  • 使い方は以下の通り
    1. デフォルトロケール用のプロパティファイルを作成
      • 拡張子は .properties
      • 『キー名 = 値』のフォーマットで複数のプロパティを定義
      • ファイルは ISO-8859-1 エンコードされている必要がある
      • ファイルの命名規則は ListResourceBundle のクラス名と同じ
    2. 1とは異なるロケール用のファイルを作成
      • ファイルの命名規則は ListResourceBundle のクラス名と同じ
      • 英語ロケール用なら MyResource_en_US.properties となる
    3. ResourceBundle#getBundle(基底名[, ロケール])PropertyResourceBundle オブジェクトを取得
      • ListResourceBundle を取得するのと同じメソッド
    4. 以下のメソッドで値を取り出す。getInt はない
      • ResourceBundle#getObject(キー文字列)
      • ResourceBundle#getString(キー文字列)
      • ResourceBundle#getStringArray(キー文字列)

使用されるリソースバンドルの優先順位

  • ロケールに対応するリソースバンドルが存在しなければ MissingResourceException 例外が発生する
  • 同名のリソースバンドルが複数あっても例外にはならない
  • ファイル単位ではなく個々のプロパティ単位でリソースバンドルが検索される。検索の優先順位は以下の通り
    1. 言語コード、国コードが一致
    2. 言語コードが一致
    3. デフォルトロケールが一致
  • 指定したキーに対応するプロパティがどのクラス/ファイルにも存在しなければ MissingResourceException が発生する
  • ListResourceBundle クラスとプロパティファイルの両方が同じ名前で存在すると、ファイルよりクラスのほうが優先される

NumberFormatを使って数値をフォーマット

  • NumberFormat クラスの static メソッドを使って目的に応じたオブジェクトを取得
    • getInstance()
      デフォルトロケールの数値フォーマット
    • getInstance(Locale)
      任意のロケールの数値フォーマット
    • getCurrencyInstance(Locale)
      任意のロケールの通貨フォーマット
    • getIntegerInstance(Locale)
      任意のロケールの整数フォーマット
  • format(long) もしくは format(double) でフォーマット済み文字列を取得
  • parse(String) で文字列から数値を取得。戻り値は Number

更新履歴

  • 2020/08/23
    Qiita に公開
  • 2020/08/24
    関数型インターフェイスの一覧を表形式に変更
    列挙値に関するサンプルコードを追加
2
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?