記事の目的
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 修飾子を付与したインスタンス変数は、コンストラクタで初期化されていなくてはならない
イニシャライザやコンストラクタによる初期化の順番
オブジェクトの初期化に関わる処理は以下の順番で実行される
- static イニシャライザ
クラスのロード時 - インスタンスイニシャライザ
インスタンス生成時、コンストラクタ実行前
変数を宣言しただけでは実行されない。インスタンス化が必要 - コンストラクタ
列挙値の継承とインターフェイスの実装
- 列挙型のメソッドである
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
-
- コレクションでの重複チェックは以下の通り。両者が成立したら同値とみなされる
- ハッシュ値が同じかチェック
- ハッシュ値が同じものだけを対象に
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"); }
}
オーバーライドが成立するための条件
- メソッドをオーバーライドする際、戻り値はスーパークラスの型と同じかそのサブクラスでなければいけない
- メソッドのオーバーライドは、以下が一致しなければ成立しない。順番が一致しなくてもオーバーロードとなる
- メソッド名
- 引数の型
- 引数の順番
- static メソッドや static フィールドもサブクラスで再定義できる
ただしオーバーライドではなく「隠蔽」なので、super キーワードを使って親の static メソッドを呼び出すことはできない
メソッドローカルのクラス
- メソッドローカルなクラスからメソッド内の変数を直接参照できるが、変数は実質的に final でないとダメ。final 宣言が無くても、メソッドローカルクラスから参照すると自動的に final 扱いになる。これはラムダも同様
- コンストラクタでメソッドの変数をメソッドローカルなクラスに与える場合は、元の変数を直接参照しないので final にしなくてもよい
- メソッドローカルなクラスからメソッドの外側のクラスのメンバ変数を参照する場合も、そのメンバ変数を変更して構わない
ラムダ式
- 引数のデータ型は省略可
- 引数が1つなら『()』が省略可
- 右辺の式が1つなら、右辺からの戻り値があっても無くても『{}』が省略可
- 右辺の式が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 だけ は存在する -
Supplier
、UnaryOperator
、BinaryOperator
のメソッド名は下記に従う
ルール:【メソッド名】As【データ型】
例:applyAsInt
、getAsBoolean
など
データ型 | 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
は原則インデックスの順番 -
Set
とMap
はクラス名のプレフィクスによって性質を見分ける-
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#reduce
は Stream
の中身を集約するためのメソッド。第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つ
-
isPresent()
… 値の有無を判定する -
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
パッケージに所属 -
Error
とException
はThrowable
のサブクラス -
RuntimeException
はException
のサブクラス(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
を実装する必要がある -
AutoCloseable
/Closeable
はどちらもclose()
にthrows
宣言があるため、リソースに使う場合もtry
の中で使う場合も、例外を catch しないとコンパイルエラーAutoCloseable#close() throws Exception
Closeable#close() throws IOException
-
AutoCloseable
もしくはCloseable
のclose()
で例外が発生したら、catch で補足される -
try
ブロックとリソースのクローズの両方で例外が発生したら、close()
で起きた例外は抑制された例外として catch された例外オブジェクトにThrowable
の配列で格納され、getSuppressed()
で取得が可能 -
try〜with〜resources
文で例外が起きたときの実行順序は以下-
try
ブロック - 宣言した逆順にリソースをクローズ(下記のコードだと、Nから1へ順番に閉じる)
- catch ブロック
-
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
クラス一覧
-
LocalDate
… 日付 -
LocalTime
… 時刻 -
LocalDateTime
… 日付+時刻 -
OffsetTime
… UTC/GMTからの差分を「+hh:mm」で含む時刻 -
OffsetDateTime
… UTC/GMTからの差分を「+hh:mm」で含む日付&時刻 -
ZonedDateTime
… UTC/GMTからの差分をタイムゾーンIDで含む日付+時刻
- 全て
Temporal
インターフェイスを実装する。更にそのスーパーインターフェイスはTemporalAccessor
- "Local〜" と "Offset〜" と "Zoned〜" の違いは、同じ日時を表現する方式の違い
-
LocalDateTime#toLocalDate()
とLocalDateTime#toLocalTime()
でそれぞれへの変換が可能 - 月を取得できるメソッドは2つ
-
getMonth()
…Month
列挙値で取得 -
getMonthValue()
… int 値で取得
-
列挙型一覧
-
Month
:月を表す
JANUARY
,FEBRUARY
,MARCH
, …,DECEMBER
-
DayOfWeek
:曜日を表す
SUNDAY
,MONDAY
,TUESDAY
, …,SATURDAY
LocalDate / LocalTime / LocalDateTime のインスタンス化
now()
-
of(year, month, dayOfMonth, ...)
それぞれのクラスが扱える値を引数にしてインスタンスを生成する
引数 month には整数でなくMonth
列挙値をセットしてもOK
LocalDateTime
のみLocalDate
とLocalTime
を引数に取るオーバーロードがある。年、月、日、時、分、秒、ミリ秒を引数に取るのもある -
parse(String)
、parse(String, DateTimeFormatter)
文字列からインスタンスを生成
DateTimeFormatter
を併用すると任意のフォーマットの文字列でも可
LocalDate#of および LocalTime#of のオーバーロード
-
LocalDate#of
には2つのオーバーロードメソッドがある。どちらも年月日は指定するが、それ以外の違いは以下の通り- 第2引数が int
- 第2引数が
Month
列挙値
-
LocalTime#of
には3つののオーバーロードメソッドがあり、全て時分は指定するが、それ以外の違いは以下の通り- 時分のみ
- 時分に加えて秒を指定
- 時分に加えて秒とナノ秒を指定
java.time.format.DateTimeFormatter
-
ofPattern(String)
フォーマットパターンを指定 -
ofLocalizedDate(FormatStyle)
日付のフォーマット方式を指定 -
ofLocalizedTime(FormatStyle)
時間のフォーマット方式を指定 -
ofLocalizedDateTime(FormatStyle)
日時のフォーマット方式を指定 -
ofLocalizedDateTime(FormatStyle, FormatStyle)
日時のフォーマット方式を、日付と時間で別々に指定 - 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)
-
Period
やDuration
がTemporalAmount
インターフェイスを実装する -
plusYears
やplusWeeks
など個々のフィールドに対する加減算も可能だが、複数のフィールドをまとめて扱う場合はPeriod
やDuration
を引数にして 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つのLocalDate
やLocalDateTime
の差分を取る -
ofYears(1)
など ofXXXXX メソッドで生成。ただしメソッドチェーンは不可
-
-
Period
は年、月、日、週で加減算できる
加減算のメソッドは plusXXXXX / minusXXXXX。plusYears(1)
など
plusWeeks(3)
で週を加算すると "P21D"。週のPeriod
表現が無い為 -
LocalDate
/LocalDateTime
はplus
/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つのLocalDateTime
やLocalTime
の差分を取る -
ofHours(1)
など ofXXXXX メソッドで生成 -
of(1, ChronoUnit.HOURS)
など of メソッドでChromeUnit
を併用して生成
-
-
Duration
は日、時、分、秒、ミリ秒、ナノ秒で加減算できる
日を加算したら PT24H で、ミリ秒以下だと PT0.13S となる -
LocalTime
/LocalDateTime
はplus
/minus
メソッドでDuration
を引数にして時分秒の加減算ができる
java.time.Instant
- エポック時間からの経過を表現するクラス
- インスタンスを生成する方法はいくつかある
Instant#now()
Instant#ofEposSecond(long)
Instant#ofEpocMilli(long)
LocalDateTime#toInstant(ZoneOffset)
ZonedDateTime#toInstant()
-
LocalDateTime#toInstant
でZoneOffset
が必要なのは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 が対象 -
print
とprintln
以外にformat
を使って文字列のフォーマットが可能 - 自動フラッシュ機能を持つ
- 同じ機能を持つクラスに
PrintStream
がある
JDK1.2でPrintWriter
にとって変わられたが、後方互換のため残っている
java.io.Console
- 標準入力からデータを読み取る
-
System#console()
でシングルトンインスタンスを取得。 利用不可なら null が返る -
readLine()
で、入力された文字列を String で取得 -
readPassword()
で、入力された文字列を char[] で取得。パスワードの読み取りなので、入力時に文字列は表示しない -
writer()
とreader()
で、それぞれコンソールに紐づいているPrintWriter
とReader
を取得できる -
Console
自身にもprintf
とformat
メソッドがあり、コンソールに文字列を出力できる
シリアライズに関する注意点
-
java.io.Serializable
インターフェイスを実装したクラスはシリアライズ可能 - シリアライズ対象外になるのは以下のどちらか
- static 変数
- transient 宣言されているメンバ変数
- スーパークラスがシリアライズ可能なら、サブクラスもシリアライズ可能
- デシリアライズでは、インスタンス初期化ブロックも、コンストラクタも呼び出されない。ただし static 初期化ブロックは呼び出される
また、以下のケースならスーパークラスのコンストラクタだけは呼び出される- 自身は
Serializable
だが、スーパークラスがSerializable
ではない - スーパークラスに引数なしのコンストラクタがある
- サブクラスのコンストラクタで明示的に親のコンストラクタを呼び出していない
- 自身は
- メンバ変数のシリアライズ可否は、フィールドではなく中身のデータ型で決まる
変数の型が何であれ、中身が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
ファイルやディレクトリのコピー- ディレクトリの中身まではコピーされない
- コピー先に同名のファイルが存在する時 CopyOption で上書き指定が無ければ例外
- デフォルトの挙動ではファイルをコピーしても属性はコピーされない
- CopyOption を指定せずにシンボリックリンクをコピーすると、リンクが示す実体がコピーされる
- 引数に与えるパスはコピー/移動をする場所ではなく、移動/コピー後のパス
-
move
ファイルやディレクトリの移動。挙動は copy の1〜5と同じ -
getAttribute(Path, String, LinkOption...)
ファイルの属性値(ファイルサイズや更新日時など)を読み取る Stream<String> lines(Path)
-
List<String> readAllLines(Path)
ファイルの全ての行を返す。メソッドによって戻り値の型が異なる
java.nio.file.Files(ディレクトリの操作)
以下は全て static メソッド
-
createDirectory()
ディレクトリを作成するが、親は作成しない -
createDirectories()
親も含めてディレクトリを作成する -
delete
/deleteIfExists
ファイルを削除する。失敗したら前者は例外、後者は 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
並列処理
並行処理ユーティリティが提供する機能
- スレッドプール
スレッドの生成と再利用 - 並行コレクション
複数スレッドからの並行アクセスを適切に処理できるコレクション - アトミック変数
並行アクセスによって値の不整合を起こさないための分割不可能な一連の操作を実装(synchronized と同じ) - カウウンティング・セマフォ
有限なリソースに対して並行アクセス可能なスレッド数を自由に設定可能
並列コレクション
- 並列処理に関わる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 の継承関係
-
Executor
…execute(Runnabble)
-
ExecutorService
…submit(Runnable)
などThreadPoolExecutor
ForkJoinPool
-
ScheduledExecutorService
…schedule(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.sql
とjavax.sql
- JDBC で DB に接続するための URL フォーマットは以下の通り
jdbc:[DB名]//[host(:port)]/[db-name](?option)
- 基本的な処理の流れは以下の通り
-
DriverManager#getConnection(url,id,pass)
でConnection
取得 -
Connection#createStatement()
でStatement
取得 -
Statement#executeQuery(sql)
でResultSet
取得 -
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
- 更新
updateString
やupdateInt
で変更しupdateRow
で変更を確定させる
Statement
のタイプがTYPE_SCROLL_INSENSITIVE
でもupdateRow
しない限り、DB の中身どころか結果セットさえ変更されないupdateString(int, String)
updateInt(int, int)
updateRow()
- 挿入
moveToInsertRow
で挿入行に移動しupdateString
やupdateInt
で挿入内容を指定してinsertRow
で挿入するmoveToInsertRow()
insertRow()
- 削除
現在行を削除するdeleteRow()
ローカライズとフォーマット
java.util.Locale オブジェクトの取得
-
Locale#getDefault()
Java実行環境のロケール -
new Locale(String)
引数は「言語コード」 -
new Loacle(String, String)
引数は「言語コード, 国コード」 -
new Loacle(String, String, String)
引数は「言語コード, 国コード, バリアント」 - 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 ファイルで用意してクラスパスが張られている場所に置く
- 使い方は以下の通り
-
ListResourceBundle
を継承した public クラスを定義
public Object[][] getContents()
をオーバーライド
このクラスの完全修飾名(パッケージ名+クラス名)が基底名に、このクラスがデフォルトロケール用になる
例:クラス名は "MyResource" とする - 1とは異なるロケール用のクラスを
ListResourceBundle
を継承して定義する
ネーミングルールは 「基底名_言語コード_国コード」
例:英語ロケール用のクラス名は "MyResource_en_US" となる -
ResourceBundle#getBundle(基底名[, ロケール])
でListResourceBundle
オブジェクトを取得 -
ResourceBundle#getXXXXX(キー文字列)
で値を取り出す
-
java.util.PropertyResourceBundle
- リソースを .properties ファイルで用意してクラスパスが張られている場所に置く
- 使い方は以下の通り
- デフォルトロケール用のプロパティファイルを作成
- 拡張子は .properties
- 『キー名 = 値』のフォーマットで複数のプロパティを定義
- ファイルは ISO-8859-1 エンコードされている必要がある
- ファイルの命名規則は
ListResourceBundle
のクラス名と同じ
- 1とは異なるロケール用のファイルを作成
- ファイルの命名規則は
ListResourceBundle
のクラス名と同じ - 英語ロケール用なら MyResource_en_US.properties となる
- ファイルの命名規則は
-
ResourceBundle#getBundle(基底名[, ロケール])
でPropertyResourceBundle
オブジェクトを取得-
ListResourceBundle
を取得するのと同じメソッド
-
- 以下のメソッドで値を取り出す。getInt はない
ResourceBundle#getObject(キー文字列)
ResourceBundle#getString(キー文字列)
ResourceBundle#getStringArray(キー文字列)
- デフォルトロケール用のプロパティファイルを作成
使用されるリソースバンドルの優先順位
- ロケールに対応するリソースバンドルが存在しなければ
MissingResourceException
例外が発生する - 同名のリソースバンドルが複数あっても例外にはならない
- ファイル単位ではなく個々のプロパティ単位でリソースバンドルが検索される。検索の優先順位は以下の通り
- 言語コード、国コードが一致
- 言語コードが一致
- デフォルトロケールが一致
- 指定したキーに対応するプロパティがどのクラス/ファイルにも存在しなければ
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
関数型インターフェイスの一覧を表形式に変更
列挙値に関するサンプルコードを追加