yucatio@システムエンジニア

趣味で作ったものいろいろ

Optional.flatMap()は再帰的かどうか

疑問

Optional.flatMap()は再帰的かどうか(2段以上Optionalがネストされた場合に一番内側の値を取得するか)

結論

再帰的でない。

Optional.flatMap()とは

Optionalのマップの結果がOptionalのとき、その中身を取り出してくれるメソッド

Optional<String> o = Optional.of("a");
    
Optional<Integer> p = o.flatMap(a -> Optional.of(3));
    
p.ifPresent(i -> System.out.println(i));
// 3

OptionalにさらにOptionalをネストしてみる

Optional<String> o = Optional.of("a");

Optional<Optional<Integer>> q =  o.flatMap(a -> Optional.of(Optional.of(5)));

Optional<Integer> r = q.flatMap(Function.identity());

JavaのパラレルストリームでCollectors.toList()は順番に並ぶか

背景

Javaでパラレルストリームを使用すると、forEachでは順番がランダムになる。

List<String> list = List.of("A", "B", "C");
list.parallelStream().forEach(System.out::println); // B C A など

Collectors.toList()で集約したリストは元の配列の順番に並びます。

List<String> list = List.of("A", "B", "C");

List<String> parallelList = list.parallelStream().collect(Collectors.toList());
parallelList.forEach(System.out::println);  // A B C

Collectors.toList()を使用した場合、元の順番どおりに並ぶことは保証されているのか

結論

順番は保証されている

途中、sortedなどを挟んでいる場合はそちらの順番で並ぶ。

Javadocを確認する

Collectors.toList()のJavadocを確認すると、以下のように書いてあります。

すべての入力要素を検出順にList内に集めるCollector

Collectors (Java SE 11 & JDK 11 )

検出順とは何でしょうか。 In what order do the elements of a stream become available? | Maurice Naftalin's Lambda FAQ の記事が分かりやすかったので引用します。

The source has an encounter order : this is the order in which the source itself makes its elements available. For example, the encounter order for an array is defined by the ordering of its elements; for an ordered collection like a List or a NavigableMap, by its iteration order; for a generator function by the function itself, and so on.

訳すと、

入力は検出順序を持つ: 検出順序とは、そのオブジェクトが持っているメンバーを取り出す際の順序のことである。例えば、配列の検出順序はその並びそのものであるし、ListやNavigableMapなどのコレクションの検出順序は、イテレータで取り出される順序のことであるし、ジェネレータであれば、それが生成する順のことである。 ればその順番が保存されるということです。

つまり、Collectors.toList()は入力のListの順番通りに並ぶことが分かります。

参考

JavaのパラレルストリームでforEachは並列実行されるか

結論

javaのパラレルストリームでforEachは並列実行される

コードを書いて確かめてみた

forEach内でsleepして動作を確かめてみた

List<String> list = List.of("A", "B", "C");

list.parallelStream()
    .forEach(s -> {
      System.out.println(s + ": start");
      System.out.println(s + ": " + Thread.currentThread().getName());
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(s + ": end");
    });

実行結果

B: start
C: start
C: ForkJoinPool.commonPool-worker-1
A: start
A: ForkJoinPool.commonPool-worker-2
B: main
B: end
A: end
C: end

Javaでリストの重複しているインデックスを取得する(ストリームAPI使用)

Javaで、リスト内で重複している要素の、インデックスをグルーピングして取得します。ストリームAPIを使用すると簡単に書けます。

List<String> list = List.of("A", "B", "C", "B", "B", "D", "A");
Map<String, List<Integer>> indexGroup = IntStream.range(0, list.size())
    .boxed()
    .collect(Collectors.groupingBy(list::get));
    
indexGroup.forEach((k, v) -> System.out.println(k + ":" + v));
// A:[0, 6]
// B:[1, 3, 4]
// C:[2]
// D:[5]

重複しているインデックスを取得する

単に、重複しているインデックスがほしい場合はこちら。

List<String> list = List.of("A", "B", "C", "B", "B", "D", "A");

Map<String, Long> countMap = list.stream().collect(
    Collectors.groupingBy(
        Function.identity(),
        Collectors.counting()));

List<Integer> duplicatedList = IntStream.range(0, list.size())
    .filter(i -> countMap.get(list.get(i)) > 1)
    .boxed()
    .collect(Collectors.toList());

duplicatedList.forEach(System.out::println);
// 0
// 1
// 3
// 4
// 6

こちらもどうぞ

yucatio.hatenablog.com

Javaでリストの重複をカウントする(ストリームAPI使用)

Javaでリストの重複をカウントする方法です。ストリームAPIを使用すると簡単に書けます。

重複をカウントする

List<String> list = List.of("A", "B", "C", "B", "B", "D", "A");

Map<String, Long> countMap = list.stream().collect(
    Collectors.groupingBy(
        Function.identity(),
        Collectors.counting()));

countMap.forEach((k, v) -> System.out.println(k + ":" + v));
// A:2
// B:3
// C:1
// D:1

重複が多い順に並び変える

さらに、重複数が多い順に並び変えます

List<String> list = List.of("A", "B", "C", "B", "B", "D", "A");

Map<String, Long> countMap = list.stream().collect(
    Collectors.groupingBy(
        Function.identity(),
        Collectors.counting()));

List<Map.Entry<String, Long>> sortedCountList = countMap.entrySet().stream()
    .sorted(Map.Entry.<String, Long> comparingByValue().reversed())
    .collect(Collectors.toList());

sortedCountList.forEach(e -> System.out.println(e.getValue() + ":" + e.getKey()));
// 3:B
// 2:A
// 1:C
// 1:D

Java歴13年がJava Gold(SE 11)を受けてみた

無事Java Silverの資格を取得したので(過去記事: Java歴13年がJava Silver (SE 11)を受けてみた【勉強編】 - yucatio@システムエンジニア を参照)、本命のJava Goldを受験しました。

受験のきっかけ

  • TwitterJava Silverを受験する人を見かけて興味を持った
  • 自分自身がJavaを勉強したときのバージョンが5で、それ以降のバージョンは適宜勉強してきたつもりだが、この機会にちゃんと勉強しようと思った
  • 将来的にプログラミングの先生になるのもよいと思っているので、資格があるとよいと思った

私について

  • Web系システムエンジニア。歴13年
  • Javaは業務で使うもののばりばり書くというより、調査・設計からリリースまでの一環でコードを書くといったイメージ

勉強期間

3週間。 勉強時間は1日1-2時間程度。

ざっくりしたスケジュールは以下です

  • 1-7日目: 黒本1周目(模試以外)
  • 8-14日目: 黒本2周目(模試含む)
  • 15-試験本番: 黒本3周目、黒本で苦手分野の復習、Qiita記事を読む、Oracle公式サンプル問題を解く

勉強方法

勉強をする際に購入した書籍は『徹底攻略Java SE 11 Gold問題集[1Z0-816]対応』通称「黒本」です。Silverのときと同様、問題に対し解説が豊富でかつ読みやすいです。Java Gold関連の書籍は、このほかにも「紫本」「白本」とよばれる書籍も存在しますが、私の場合は黒本のみで合格することができました。

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

徹底攻略Java SE 11 Gold問題集[1Z0-816]対応 [ 志賀 澄人 ]
価格:4400円(税込、送料無料) (2022/10/8時点)


黒本1周目(模試以外)

試験の出題範囲と出題傾向を確認するため、はじめに黒本を1周しました。このときは1問ずつ問題を解いて、解答を確認しました。

1周目にあまり時間をかけないことは試験の概要の把握にはとてもよかったです。

ちなみに最初の正答率は20%くらいでした。しかし、各章のトピックは実務で扱ったものが多く、勉強すれば何とかなるという気がしました。(逆に、黒本1周して扱ったことがない分野が多いと感じるなら、紫本など読んだほうがよいのかもしれません)

黒本2周目(模試以外)

2周目は1周目の確認と、より理解を深めるように学習しました。本のコードを実際に書いたり、Javadocを確認しました。正答率は87%でした。

1周目では「がんばればいけそう」と思っていましたが、2周目では「覚えることが多すぎて覚えきれない」とややネガティブになりました。

黒本(模試)

Goldの黒本には模試が1回しかついていないので(Silverは2回ついていた)、黒本を2周してある程度理解した後に模試に挑みました。このことはよかったと思っています。

正答率が82%でした。ここで受験日を決めました。

黒本3周目以降

3周目以降は苦手分野を中心に復習していきました。JDBC、モジュール、セキュアコーディングが苦手だったのでそちらを何度か読みました。ほかの分野は流し読みしました。覚えていないAPIについてはJavadocを確認しました。

Qiita記事を読む

黒本、Oracle公式ドキュメント以外では、Qiitaで"Java Gold"と検索して、出てきた記事を1つずつ読みました。

試験の要点をまとめている記事は、黒本に書かれていない項目もあり、勉強になりました。

合格体験記は、勉強の方法や、問題の出題傾向、難易度を知るのに役立ちました。

Oracle公式サンプル問題

"Java Gold サンプル"で検索すると公式のサンプル問題を見るとこができます。SE 8 ですが、試験範囲はほぼ同じなので解きました。

受験の申し込みと受験

受験の流れはSilverの時と同じです。

yucatio.hatenablog.com

出題内容

出題される内容は、ほとんどが黒本かOracle公式サンプルと同じか類題でした。体感では、黒本(もしくは公式サンプル)とほぼ同じ・類題・初見の割合は、40:50:10でした。

出題される分野は、ストリームAPIに関連する問題が全体の50%以上だったように思います。ほかの分野はまんべんなく出題されました。アノテーション関連は私のときは出題されませんでした。

結果

試験時間は180分でしたが、90分程度で終了しました。 89%で合格しました。

感想

受験してよかったか?

よかった。当初の目的である、Java 5より後の機能について知ることができました。特に、ストリームAPIでは、便利なAPIを知ることができました。Javaでgroupbyができないと思い込んでいましたが、あることが知れてよかったです。

デメリットは高い受験料くらいです。

ほかの人に受験を勧める?

受験料がネックですが、勧めます。

試験範囲は、実務でよく使う機能が中心となっています。新人にとっては、これから使う機能の予習になりますし、ベテランにとっては新しいバージョンの機能を学ぶ機会となると同時に実力の証明にもなります。

終わりに

難しいと思われているJava Goldですが、黒本と公式のサンプル問題が解けるようになれば受かります。機会があれば受験をおすすめします。

Java歴13年がJava Silver (SE 11)を受けてみた【総評】

試験を受けてみての感想です。

勉強編

yucatio.hatenablog.com

受験編

yucatio.hatenablog.com

試験を受けてよかった?

良かった。

当初の目標の1つであった、Java5より後に追加された機能について知ることができました。特に、関数型インターフェース(Consumer, Supplier, Predicate, Function)について整理できたのは良かったです(今までなんとなくでstreamAPI内でこれらを使っていたので)。 また、モジュールシステムについても概要を知れました(モジュールシステムはまだ現場で使ってないので)。 他にもインターフェースのdefaultメソッドなど知らなかったことがあり、この機会に知れてよかったです。

ほかの人に受験を勧める?

受験料が高いので、簡単には勧めません。会社負担であればありかな。(ちなみに私は自己負担で受験してます)

もちろん、取って損をすることはないです。取っていればJavaの基本的なルールを理解しているということが証明されます。 未経験者がJava Silverを持っていたら、勉強熱心な印象を受けます。

個人的には、Java Silverを受ける前にデザインパターンの本を先に読んでおいてほしいなと思います。この本自体読むのはとても大変なのですが、インターフェースやクラスの拡張&ポリモーフィズムの使いどころを学ぶのにとてもよい書籍です。

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

Java言語で学ぶデザインパターン入門第3版 [ 結城 浩 ]
価格:4290円(税込、送料無料) (2022/9/18時点)


次はJava Gold

がんばります