絶賛Java Gold取得に向けて勉強中です。アウトプットの一環ということで、躓いたところ、気になったところ、重要だと思ったところを随時更新したいと思います。
クラスとインターフェース
- ネストしたクラスにはインナークラス、staticインナークラス、ローカルクラス、匿名クラスがある。
- ローカルクラスは、メソッド内で定義されるクラスのことで、abstract, finalで修飾できる。
- 匿名クラスはあらゆる修飾子を使用することはできない。
- インナークラスのインスタンスを生成するには、エンクロージングクラスのインスタンスを先に生成する必要がある。
new Outer().new Inner() - staticインナークラスはエンクロージングクラスのインスタンス化は不要。
new Inner(), new Comparator()など - ローカルクラスから参照するローカル変数は、ローカルクラスよりもあとにローカル変数を宣言するとコンパイルエラー。また、その時のローカル変数は実質的にfanalでなければならない。(値を変更しようとするとコンパイルエラー)
- 匿名クラスには名前がないため、コンストラクタは定義できない。匿名クラスを初期化したいときは初期化子{}を使う
- クラスやインターフェースで定義したstaticメソッドはオーバライドできない。@Overrideアノテーションを付けたりするとコンパイルエラー。
- スーパークラスとインターフェースが同一のシグニチャのメソッドを持っている場合、スーパークラスのメソッドが優先される。
- EnumクラスのvaluesメソッドはそのEnumに定義されている列挙子を配列に入れて返却する。
- EnumクラスのvalueOfメソッドはStringの引数を渡し、そのインスタンスを返却する。
- Enumに定義するコンストラクタのアクセス修飾子はprivateでなければならない。省略した場合は暗黙的にprivateとなる。
関数型インタフェースとラムダ式
・主な関数型インタフェースは以下の通り
インターフェース | 戻り値型 | メソッド |
Supplier<T> | T | get() |
Consumer<T> | void | accept(T) |
BiConsumer<T,U> | void | accept(T,U) |
Predicate<T> | boolean | test<T> |
BiPredicate<T,U> | boolean | test<T,U> |
Function<T,R> | R | apply(T) |
BiFunction<T,U,R> | R | apply(T,U) |
UnaryOperator<T> | T | apply(T) |
BinaryOperator<T> | T | apply(T) |
Runnable | void | run() |
Callable<V> | V | call() |
・Biがつくと引数を2つ取る
・Functionの合成は、andThenメソッドで順次実行、composeで逆順実行。
a.andThen(b): aを実行後、bを実行
a.compose(b): bを実行後、aを実行
並列処理
- 並行処理:シングルコアで処理対象を切り替えて実行する
- 並列処理:マルチコアで同時に実行する
- ExecutorフレームワークはExecutorServiceまたはScheduledExecutorServiceを使ってExecutorsを使いインスタンス化する。
ExecutorService exec = Executors.newSingleThreadExecutor(); - ExecutorServiceのsubmitメソッドを使うことでタスクの実行できる。
- ScheduledExecutorServiceのscheduleメソッドを使うことでタスクの遅延実行ができる。引数には初期遅延時間を指定する。
exec.schedule(task, 1, TimeUnit.SECINDS); - ScheduledExecutorServiceのscheduleAtFixedRateメソッドを使うことでタスクの定期的な遅延実行ができる。引数には初期遅延時間とインターバル時間を指定する。
- ScheduledExecutorServiceのscheduleWithFixedDelayメソッドを使うことでタスクの遅延実行を決まった時間間隔でできる。引数には初期遅延時間とインターバル時間を指定する。
exec.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECINDS); - Executorsクラスには下記のようなメソッドがある
newSingleThreadExecutor: 新しいスレッドを1つ生成し、プールしている
newFixedThreadExecutor: 引数に指定された数字の個数分だけスレッドを生成し、保持するプールを作成する
newCashedThreadExecutor: 必要に応じてスレッドを増減させる。一度生成されたスレッドは60秒間利用がなければ破棄される。
newSingleThreadScheduledExecutor: 遅延実行用の、新しいスレッドを1つ生成し、プールしている。
newScheduledThreadPool: 引数に指定したスレッドの数で、遅延実行ができる。(これだけExecutorsクラスなので注意!) - Futureインタフェースを使うことで新しく作ったスレッドの結果を知ることができる。
- submitメソッドやscheduleメソッドの返り値として受け取れる。
- Future型で受け取ったあと、getメソッドで値を取り出せる
- ただし、タスクがRunnableの場合はnullとなる。
- null以外の値を戻したい場合は、submitメソッドの第2引数に戻したい値を渡す。
- Callableは処理結果を戻したり、必要に応じて例外をスローできる。
- スローされた例外はFutureで一旦受け取り、getメソッド使用時にExecutionExceptionをスローする。
- synchronizedはメソッド宣言に使う場合と、ブロックで囲んで使うパターンが有る。
- デッドロックを回避するにはロックする順番をスレッド間で揃える。
- 原子性を担保したAtomicパッケージには下記クラスがある。
AtomicBoolean
AtomicInteger
AtomicLong
AtomicReference
ストリームAPI
- Optionalクラスはメソッドの処理結果を扱うためのクラスで、処理結果が正常か異常かに関わらず同じ型で扱える。(可読性向上)
- Optionalクラスのインスタンス生成には下記のようなメソッドがある
static <T> Optional<T> empty(): 空のOptionalインスタンスを生成
static <T> Optional<T> of(T value): null以外のvalueを持ったOptionalインスタンスを生成(nullを渡すとぬるぽ)
static <T> Optional<T> ofNullable(T value): valueを持つ、もしくはnullのときは空のOptionalインスタンスを生成 - Optionalクラスのgetメソッドは、値が入っていることが前提のため、空のインスタンスに対してgetするとNoSuchElementExceptionが出る
- この例外の発生を回避するために、isPresentメソッドやisEmptyメソッドで値の確認をする必要がある。
- orElseメソッドを使えば、空だった時に戻す値を指定することができる。また、orElseThrowにすると任意の例外を戻せる。
- ifPresentメソッドは値を持っていれば、値を取り出さずにその後の処理を記載できる。
- ifPresentOrElseメソッドを使えば、第1引数に値があったときのラムダ式(Consumer)、第2引数に値がなかったときのラムダ式(Runnable)を指定することでどちらのパターンでも対応可能
- mapメソッドはOptionalのインスタンスがからの場合には空のOptionalインスタンスを返却する。
- flatMapメソッドは戻り値を新しいOptionalインスタンスに入れず、そのまま戻す。
- forEachメソッドはコレクションから要素を順に取り出し、Cosumer型のラムダ式の引数に渡し実行する。メソッド参照を利用することも可能。
list.forEach*1
list.forEach(System.out::println) - 中間操作には下記のような種類がある。
メソッド 概要 distinct 重複を除いた外ストリームを返却 filter 引数に指定した条件に合致した要素で構成されたストリームを返却 limit ストリームの要素を指定された数に絞ったストリームを返却 map 指定されたかmン数を要素に適用したストリームを返却 peek 新しい結果のストリームを生成し、指定された関数を適用して返却 skip 引数で指定された数分だけ」要素を破棄し、残った要素のみで構成されたストリームを返却 sorted ストリームの要素を自然順序順で並び替えたストリームを返却 - 終端操作には下記のような種類がある。
メソッド 概要 allMatch すべての要素が条件に一致するか anyMatch いずれかの要素が条件に一致するか collect ストリームの要素を持つコレクションを返却 count 要素数を返却 findAny 要素が残っているかの結果をOptionalを返却 findFirst 最初の要素を持ったOptionalを返却 max 最大の要素を返却 min 最小の要素を返却 reduce 累積的に結合していくリダクション処理を実行 toArray 配列を返却 - 配列からストリームを作るには下記のとおりである
Stream<String> stream = Arrays.stream(array) - parallelStreamメソッドを使うことで並列ストリームを生成でき、マルチスレッドをサポートする
- forEachOrderedメソッドを使うことで、マルチスレッド環境下であっても処理順はシングルスレッドの時と変わらない。
- Collectorインタフェースはストリームのリダクション操作のためのインタフェースで、処理中のオブジェクトを適切に取り扱うことができる(要復習)
- Collectorインタフェースは3つの型パラメータを受け取る。
1つ目:ストリーム内の要素の型
2つ目:処理途中の値を保持するためのオブジェクト
3つ目:最終的な結果の型 - Collectorには5つの抽象メソッドはあり、すべてを実装しなければならない
supplierメソッド:処理途中の値を生成するためのメソッド
accumulatorメソッド:実行したい処理を記述したBiConsumer型のラムダを返却するメソッド。
combinerメソッド:並列処理時、個々に作られた処理中の値を保持するためのオブジェクトを結合すること
finisherメソッド:処理結果を戻すラムダ式を提供するメソッド
characteristicsメソッド;下記のようなEnumセットを返却するメソッド
列挙子 概要 CONCURRENT このCollectorが並列処理であることを示す IDENTITY_FINISH このCollectorのfinisherメソッドが省略可能であることを示す UNORDERED コレクションの操作において順序の維持を保証しないことを示す
EnumSet.noneOf(Characterisitics.class) - Collectorsは要素をコレクションに蓄積したり、条件に従って要素を要約するクラス
- groupingByメソッドは引数にストリームの要素の型を受け取り、グループごとのリストなどを返却する
- summingIntメソッドはInteger型のメソッドを返し、要素の合計を返却する。(averagingIntメソッドなどもある)
- partitioningByメソッドは条件を指定して、その上家に合致するか(true, false)でグループ分けをする
- 終端操作のメソッドは一つのストリームにつき、1回しか呼び出せないため、2回めを呼び出そうとすると、IllegalStateExceptionが出る。
*1:x) -> System.out.println(x