ブログ アーカイブ

自己紹介

本ブログをご覧いただき、ありがとうございます。
株式会社ヒューマンインタラクティブテクノロジー(HIT)の技術グループ担当者です。

弊社ホームページ
ラベル java8 の投稿を表示しています。 すべての投稿を表示
ラベル java8 の投稿を表示しています。 すべての投稿を表示

2014年4月17日木曜日

[Java8]ParallelStream内で例外が発生した時スレッドは終了するのか?

どうも、トムです。

そろそろ世間(?)でも徐々にJava SE8の話題が増えてきた今日この頃
Web上を彷徨っているとチラッとこんな記事↓を見かけました。

もしもラムダの中で例外が発生したら(前編)
この記事の中でParallelStreamについての検証があるのですが
発生した例外は誰が受け取るのか?どこまで伝播するのか?
例外が発生したスレッド全てでcatch処理が行われるのか?
例外が発生しなかった他のスレッドはどのような影響を受けるのか?
そもそもちゃんと全部のスレッド処理が終了するのか?
皆さんも気になりますよね?
すごく気になりますね。

ParallelStream例外時のスレッドの動きを観察

引用記事の中ではParallelStream内で例外が発生した場合の結果として
幾つかのスレッドが残ったままになっているように見えますが
例外が発生するたびスレッドがどんどん増え続けるなんて事にならないのかちょっと確かめてみます。

コードは引用記事の内容を拝借しました。
parallelStreamで並列処理中に"ERROR"という文字列が出てきたらRuntimeExceptionをthrowするという処理を10回繰り返しスレッド数の変化を確認します。
        List<String> lines = Arrays.asList("A", "B", "C", "D", "ERROR", "F", "G", "ERROR", "I", "J");

        // 取り敢えず10回繰り返して様子見
        for (int i=0; i<10; i++) {
            System.out.println("スレッド数: " + String.valueOf(Thread.activeCount()));
            System.out.println("親スレッド Thread=" + Thread.currentThread().getId());
            Set<String> threads = new CopyOnWriteArraySet<>();
            try {
                lines.parallelStream().forEach(s -> {
                    System.out.println("=>開始[" + Thread.currentThread().getId() + "] 文字[" + s + "]" + ", スレッド数=" + String.valueOf(Thread.activeCount()));
                    threads.add(String.valueOf(Thread.currentThread().getId()));
                    try {
                        Thread.sleep(100L);
                        if (s.equals("ERROR")) {
                            System.out.println("◇◇◇◇ラムダ内で例外発生◇◇◇◇ Thread=" + Thread.currentThread().getId() + ", スレッド数=" + String.valueOf(Thread.activeCount()));
                            System.out.println("<=エラー終了[" + Thread.currentThread().getId() + "] 文字[" + s + "]" + ", スレッド数=" + String.valueOf(Thread.activeCount()));
                            threads.remove(String.valueOf(Thread.currentThread().getId()));
                            throw new RuntimeException();
                        }
                    } catch (InterruptedException e) {
                        System.out.println("InterruptedException in lambda. Thread=" + Thread.currentThread().getId() + ", スレッド数=" + String.valueOf(Thread.activeCount()));
                    }
                    System.out.println("<=終了[" + Thread.currentThread().getId() + "] 文字[" + s + "]" + ", スレッド数=" + String.valueOf(Thread.activeCount()));
                    threads.remove(String.valueOf(Thread.currentThread().getId()));
                });

            } catch (Exception ex) {
                System.out.println("◆◆◆◆ラムダの外で例外キャッチ◆◆◆◆ Thread=" + Thread.currentThread().getId() + ", スレッド数=" + String.valueOf(Thread.activeCount()));
                System.out.println("ラムダ内で終わっていないように見えるスレッド: [" + String.join(",", threads) + "]" + ", スレッド数=" + String.valueOf(Thread.activeCount()));
            }
            System.out.println("スレッド数: " + String.valueOf(Thread.activeCount()));
            System.out.println("----------------------------------------------------------------------");
        }


動かしてみると………
スレッド数: 2
親スレッド Thread=1
=>開始[1] 文字[G], スレッド数=5
=>開始[12] 文字[I], スレッド数=5
=>開始[11] 文字[C], スレッド数=5
=>開始[13] 文字[ERROR], スレッド数=5
<=終了[1] 文字[G], スレッド数=5
<=終了[11] 文字[C], スレッド数=5
=>開始[11] 文字[ERROR], スレッド数=5
<=終了[12] 文字[I], スレッド数=5
=>開始[12] 文字[J], スレッド数=5
◇◇◇◇ラムダ内で例外発生◇◇◇◇ Thread=13, スレッド数=5
<=エラー終了[13] 文字[ERROR], スレッド数=5
=>開始[13] 文字[B], スレッド数=5
=>開始[1] 文字[F], スレッド数=5
◇◇◇◇ラムダ内で例外発生◇◇◇◇ Thread=11, スレッド数=5
<=エラー終了[11] 文字[ERROR], スレッド数=5
=>開始[11] 文字[D], スレッド数=5
<=終了[1] 文字[F], スレッド数=5
◆◆◆◆ラムダの外で例外キャッチ◆◆◆◆ Thread=1, スレッド数=5
ラムダ内で終わっていないように見えるスレッド: [12,13,11], スレッド数=5
スレッド数: 5
----------------------------------------------------------------------
<=終了[12] 文字[J], スレッド数=5
<=終了[13] 文字[B], スレッド数=5
<=終了[11] 文字[D], スレッド数=5
【↑ここまで前回のラムダ処理のスレッド↑】 ※この部分だけ順番入れ替えています

スレッド数: 5
親スレッド Thread=1
=>開始[12] 文字[A], スレッド数=5
=>開始[1] 文字[G], スレッド数=5
=>開始[13] 文字[C], スレッド数=5
=>開始[11] 文字[B], スレッド数=5
<=終了[1] 文字[G], スレッド数=5
=>開始[1] 文字[F], スレッド数=5
<=終了[13] 文字[C], スレッド数=5
=>開始[13] 文字[ERROR], スレッド数=5
<=終了[12] 文字[A], スレッド数=5
=>開始[12] 文字[D], スレッド数=5
<=終了[11] 文字[B], スレッド数=5
=>開始[11] 文字[A], スレッド数=5
◇◇◇◇ラムダ内で例外発生◇◇◇◇ Thread=13, スレッド数=5
<=エラー終了[13] 文字[ERROR], スレッド数=5
<=終了[1] 文字[F], スレッド数=5
=>開始[1] 文字[I], スレッド数=5
=>開始[13] 文字[ERROR], スレッド数=5
<=終了[12] 文字[D], スレッド数=5
<=終了[11] 文字[A], スレッド数=5
<=終了[1] 文字[I], スレッド数=5
◆◆◆◆ラムダの外で例外キャッチ◆◆◆◆ Thread=1, スレッド数=5
ラムダ内で終わっていないように見えるスレッド: [13], スレッド数=5
スレッド数: 5
----------------------------------------------------------------------
◇◇◇◇ラムダ内で例外発生◇◇◇◇ Thread=13, スレッド数=5
<=エラー終了[13] 文字[ERROR], スレッド数=5
【↑ここまで前回のラムダ処理のスレッド↑】 ※この部分だけ順番入れ替えています

スレッド数: 5
親スレッド Thread=1
=>開始[11] 文字[C], スレッド数=5
=>開始[12] 文字[B], スレッド数=5
=>開始[1] 文字[G], スレッド数=5
=>開始[13] 文字[ERROR], スレッド数=5
<=終了[11] 文字[C], スレッド数=5
=>開始[11] 文字[I], スレッド数=5
<=終了[12] 文字[B], スレッド数=5
=>開始[12] 文字[A], スレッド数=5
<=終了[1] 文字[G], スレッド数=5
=>開始[1] 文字[F], スレッド数=5
◇◇◇◇ラムダ内で例外発生◇◇◇◇ Thread=13, スレッド数=5
<=エラー終了[13] 文字[ERROR], スレッド数=5
=>開始[13] 文字[D], スレッド数=5
<=終了[12] 文字[A], スレッド数=5
=>開始[12] 文字[ERROR], スレッド数=5
<=終了[11] 文字[I], スレッド数=5
<=終了[1] 文字[F], スレッド数=5
◆◆◆◆ラムダの外で例外キャッチ◆◆◆◆ Thread=1, スレッド数=5
ラムダ内で終わっていないように見えるスレッド: [13,12], スレッド数=5
スレッド数: 5
----------------------------------------------------------------------

~~~(中略)~~~

スレッド数: 5
----------------------------------------------------------------------
はい、スレッドは増えてはいないですね。
例外でスレッド数がもりもり増える事はないようです。
他に、気になる点は3点
  • ParallelStream内のスレッドでは親スレッドと同じスレッドも使用する…らしい
  • ParallelStream内で例外が発生しても正常処理のスレッドは継続する…らしい
  • ParallelStreamでの同時実行可能スレッド数は5スレッド…らしい
  • ※同時実行可能スレッド数に関してはJVMの設定や環境によるかもしれません

    う~ん……ここら辺はもっと検証してみないと何とも言えないですね。
    ただ、親スレッドと同じスレッドで並列処理が走るのは何とも奇妙な……



    サーバサイドアプリでの検証

    念のためサーバサイドで実装した場合にも同じ動きをするのか検証してみましょう。

    今回検証に利用したのはPlay Framework 2.2.2
    Play Frameworkは、J2EEを完全に排除し複雑なサーバサイドの構築やらTomcatのようなサーブレットコンテナを必要とせずにRubyのRailsやPHPのCakePHPのようにお手軽にMVCアーキテクチャを利用したアプリを作成できる生産性を重視するWebアプリ開発に特化した次世代フレームワークです。

    Play Frameworkの構築記事はまた次の機会という事で、さっそく検証してみましょう。


    何回か実行してみます。


    ~~~(中略)~~~

    サーバサイドでも特に動きに変わりはないようです。
    スレッド数に関しては安心ですが、ParallelStreamの例外時には正常処理のスレッドが残ってしまうので気を付けた方がよさそうです。
    やる人はいないと思いますがParallelStreamでDB操作とかは絶対やっちゃダメですね。

    2014年4月2日水曜日

    Java8 Date and Time API 変換メモ

    トムです。
    少し話題は遅いですが、日本時間で3月19日にJava8が正式に公開されました。

    Java8では多くのAPIが追加され、概ね使いやすくなっているのですが
    新規に追加されたDate and Time APIに関しては今までの日付型と比べ使い方に癖があり使用の際に躓く方も多いと思います。
    今回はメモ書きとしてJava8のDate and Time APIについて動作確認した内容を書いていきます。




    型変換サンプル

    java.util.Date から型変換

    java.util.Date から java.time.ZonedDateTime に変換

            Date d1 = new Date();
            ZonedDateTime date2zd = d1.toInstant().atZone(ZoneId.systemDefault());
    


    java.util.Date から java.time.OffsetDateTime に変換

            Date d2 = new Date();
            // UTC
            OffsetDateTime date2odt1 = d2.toInstant().atOffset(ZoneOffset.UTC);
    
            // System offset
            OffsetDateTime date2odt2 = d2.toInstant().atOffset(ZoneId.systemDefault().getRules().getOffset(d2.toInstant()));
    
            // System offset (一度java.time.ZonedDateTimeに変換)
            OffsetDateTime date2odt3 = d2.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime();
    

    java.util.Date から java.time.OffsetTime に変換

            Date d3 = new Date();
            //UTC
            OffsetTime date2ot1 = d3.toInstant().atOffset(ZoneOffset.UTC).toOffsetTime();
    
            // System offset
            OffsetTime date2ot2 = d3.toInstant().atOffset(ZoneId.systemDefault().getRules().getOffset(d3.toInstant())).toOffsetTime();
    
            // System offset (一度java.time.ZonedDateTimeに変換)
            OffsetTime date2ot3 = d3.toInstant().atZone(ZoneId.systemDefault()).toOffsetDateTime().toOffsetTime();
    

    java.util.Date から java.time.LocalDateTime に変換

            Date d4 = new Date();
            LocalDateTime date2ldt1 = d4.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
            // または
            LocalDateTime date2ldt2 = LocalDateTime.from(d4.toInstant().atZone(ZoneId.systemDefault()));
    

    java.util.Date から java.time.LocalDate に変換

            Date d5 = new Date();
            LocalDate date2ld1 = d5.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            // または
            LocalDate date2ld2 = LocalDate.from(d5.toInstant().atZone(ZoneId.systemDefault()));
    

    java.util.Date から java.time.LocalTime に変換

            Date d6 = new Date();
            LocalTime date2lt1 = d6.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
            // または
            LocalTime date2lt2 = LocalTime.from(d6.toInstant().atZone(ZoneId.systemDefault()));
    

    java.util.Date から java.time.chrono.JapaneseDate に変換

            Date d7 = new Date();
            JapaneseDate date2jd = JapaneseDate.from(d7.toInstant().atZone(ZoneId.systemDefault()));
    




    java.time.ZonedDateTime から型変換

    java.time.ZonedDateTime から java.util.Date に変換

            ZonedDateTime zd1 = ZonedDateTime.now(ZoneId.systemDefault());
            Date zd2date = Date.from(zd1.toInstant());
    

    java.time.ZonedDateTime から java.time.LocalDateTime に変換

            ZonedDateTime zd2 = ZonedDateTime.now(ZoneId.systemDefault());
    
            LocalDateTime zd2ldt1 = zd2.toLocalDateTime();
            // または
            LocalDateTime zd2ldt2 = LocalDateTime.from(zd2);
    

    java.time.ZonedDateTime から java.time.LocalDate に変換

            ZonedDateTime zd3 = ZonedDateTime.now(ZoneId.systemDefault());
    
            LocalDate zd2ld1 = zd3.toLocalDate();
            // または
            LocalDate zd2ld2 = LocalDate.from(zd3);
    

    java.time.ZonedDateTime から java.time.LocalTime に変換

            ZonedDateTime zd4 = ZonedDateTime.now(ZoneId.systemDefault());
    
            LocalTime zd2lt1 = zd4.toLocalTime();
            // または
            LocalTime zd2lt2 = LocalTime.from(zd4);
    

    java.time.ZonedDateTime から java.time.OffsetDateTime に変換

            ZonedDateTime zd5 = ZonedDateTime.now(ZoneId.systemDefault());
    
            OffsetDateTime zd2odt1 = zd5.toOffsetDateTime();
            // または
            OffsetDateTime zd2odt2 = OffsetDateTime.from(zd5);
    

    java.time.ZonedDateTime から java.time.OffsetTime に変換

            ZonedDateTime zd6 = ZonedDateTime.now(ZoneId.systemDefault());
            OffsetTime zd2ot = OffsetTime.from(zd6);
    

    java.time.ZonedDateTime から java.time.chrono.JapaneseDate に変換

            ZonedDateTime zd7 = ZonedDateTime.now(ZoneId.systemDefault());
            JapaneseDate zd2jd = JapaneseDate.from(zd7);
    




    文字列フォーマット変換サンプル



    java.time.ZonedDateTime の文字列変換

            // System.out.println()のメソッド参照
            Consumer<Object> pl = System.out::println;
    
           //----------------------------------------------------------------------------------------------
           // ZonedDateTime methods
           //----------------------------------------------------------------------------------------------
            ZonedDateTime datetime = ZonedDateTime.now(ZoneId.systemDefault()); // Asia/Tokyo
            pl.accept("[getYear] 年");
            pl.accept(datetime.getYear());
            // 2014
            
            pl.accept("[getMonth] 月(Month型)");
            pl.accept(datetime.getMonth().name());
            // APRIL
            
            pl.accept("[getMonthValue] 月");
            pl.accept(datetime.getMonthValue());
            // 4
            
            pl.accept("[getDayOfMonth] 日");
            pl.accept(datetime.getDayOfMonth());
            // 2
    
            pl.accept("[getDayOfWeek] 曜日(DayOfWeek型)");
            pl.accept(datetime.getDayOfWeek().name());
            // WEDNESDAY
    
            pl.accept("[getDayOfYear] 1/1からの経過日");
            pl.accept(datetime.getDayOfYear());
            // 92
    
            pl.accept("[getHour] 時");
            pl.accept(datetime.getHour());
            // 19
    
            pl.accept("[getMinute] 分");
            pl.accept(datetime.getMinute());
            // 37
    
            pl.accept("[getSecond] 秒");
            pl.accept(datetime.getSecond());
            // 15
    
            pl.accept("[getMillis] ミリ秒");
            pl.accept(datetime.get(ChronoField.MILLI_OF_SECOND));
            // 798
    
            pl.accept("[getMicros] マイクロ秒");
            pl.accept(datetime.get(ChronoField.MICRO_OF_SECOND));
            // 798000
    
            pl.accept("[getNano] ナノ秒");
            pl.accept(datetime.getNano());
            // 798000000
    
            pl.accept("[The aligned day-of-week within a month] 月初から月末まで1からカウントアップして8日で1にリセットされる1~7の整数");
            pl.accept(datetime.get(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH));
            // 2
    
            pl.accept("[The aligned day-of-week within a year] 年初から年末まで1からカウントアップして8日で1にリセットされる1~7の整数");
            pl.accept(datetime.get(ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR));
            // 1
    
            pl.accept("[The clock-hour-of-am-pm] AM/PMを考慮した時間");
            pl.accept(datetime.get(ChronoField.CLOCK_HOUR_OF_AMPM));
            // 7
    
            pl.accept("[The am-pm-of-day] 0=AM/1=PM");
            pl.accept(datetime.get(ChronoField.AMPM_OF_DAY));
            // 1
    
            pl.accept("[Era] 0=紀元前(B.C.)/1=西暦(A.D.)");
            pl.accept(datetime.get(ChronoField.ERA));
            // 1
    
            pl.accept("[InstantSeconds] エポック秒(Unix時間/秒) 1970-01-01T00:00Zからの経過秒");
            pl.accept(datetime.toEpochSecond());
            // 1396435035
    
            pl.accept("[InstantSeconds] エポック日(Unix時間/日) 1970-01-01からの経過日");
            pl.accept(datetime.getLong(ChronoField.EPOCH_DAY));
            // 16162
    
    
           //----------------------------------------------------------------------------------------------
           // format use DateTimeFormatter Constant
           //----------------------------------------------------------------------------------------------
            pl.accept("[toString]");
            pl.accept(datetime.toString());
            // 2014-04-02T19:37:15.798+09:00[Asia/Tokyo]
            
            pl.accept("[BASIC_ISO_DATE]");
            pl.accept(datetime.format(DateTimeFormatter.BASIC_ISO_DATE));
            // 20140402+0900
            
            pl.accept("[ISO_LOCAL_DATE]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_LOCAL_DATE));
            // 2014-04-02
    
            pl.accept("[ISO_OFFSET_DATE]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_OFFSET_DATE));
            // 2014-04-02+09:00
            
            pl.accept("[ISO_DATE]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_DATE));
            // 2014-04-02+09:00
    
            pl.accept("[ISO_LOCAL_TIME]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_LOCAL_TIME));
            // 19:37:15.798
            
            pl.accept("[ISO_OFFSET_TIME]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_OFFSET_TIME));
            // 19:37:15.798+09:00
    
            pl.accept("[ISO_TIME]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_TIME));
            // 19:37:15.798+09:00
    
            pl.accept("[ISO_LOCAL_DATE_TIME]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
            // 2014-04-02T19:37:15.798
    
            pl.accept("[ISO_OFFSET_DATE_TIME]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
            // 2014-04-02T19:37:15.798+09:00
    
            pl.accept("[ISO_ZONED_DATE_TIME]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
            // 2014-04-02T19:37:15.798+09:00[Asia/Tokyo]
    
            pl.accept("[ISO_DATE_TIME]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T19:37:15.798+09:00[Asia/Tokyo]
    
            pl.accept("[ISO_ORDINAL_DATE]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_ORDINAL_DATE));
            // 2014-092+09:00
    
            pl.accept("[ISO_WEEK_DATE]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_WEEK_DATE));
            // 2014-W14-3+09:00
    
            pl.accept("[ISO_INSTANT]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_INSTANT));
            // 2014-04-02T10:37:15.798Z
    
            pl.accept("[RFC_1123_DATE_TIME]");
            pl.accept(datetime.format(DateTimeFormatter.RFC_1123_DATE_TIME));
            // Wed, 2 Apr 2014 19:37:15 +0900
    
    
           //----------------------------------------------------------------------------------------------
           // format use DateTimeFormatter ofLocalizedDate()
           //----------------------------------------------------------------------------------------------
            pl.accept("[ofLocalizedDate] [DateStyle=FULL]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)));
            // 2014年4月2日
    
            pl.accept("[ofLocalizedDate] [DateStyle=MEDIUM]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)));
            // 2014/04/02
    
            pl.accept("[ofLocalizedDate] [DateStyle=SHORT]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)));
            // 14/04/02
    
            pl.accept("[ofLocalizedDate] [DateStyle=LONG]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)));
            // 2014/04/02
    
    
           //----------------------------------------------------------------------------------------------
           // format use DateTimeFormatter ofLocalizedTime()
           //----------------------------------------------------------------------------------------------
            pl.accept("[ofLocalizedTime] [TimeStyle=FULL]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL)));
            // 19時37分15秒 JST
    
            pl.accept("[ofLocalizedTime] [TimeStyle=MEDIUM]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM)));
            // 19:37:15
    
            pl.accept("[ofLocalizedTime] [TimeStyle=SHORT]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)));
            // 19:37
    
            pl.accept("[ofLocalizedTime] [TimeStyle=LONG]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.LONG)));
            // 19:37:15 JST
    
    
           //----------------------------------------------------------------------------------------------
           // format use DateTimeFormatter ofLocalizedDateTime()
           //----------------------------------------------------------------------------------------------
            pl.accept("[ofLocalizedDateTime] [DateTimeStyle=FULL]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL)));
            // 2014年4月2日 19時37分15秒 JST
    
            pl.accept("[ofLocalizedDateTime] [DateTimeStyle=MEDIUM]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));
            // 2014/04/02 19:37:15
    
            pl.accept("[ofLocalizedDateTime] [DateTimeStyle=SHORT]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)));
            // 14/04/02 19:37
    
            pl.accept("[ofLocalizedDateTime] [DateTimeStyle=LONG]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG)));
            // 2014/04/02 19:37:15 JST
    
    
            pl.accept("[ofLocalizedDateTime] [DateStyle=FULL] [TimeStyle=FULL]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.FULL)));
            // 2014年4月2日 19時37分15秒 JST
    
            pl.accept("[ofLocalizedDateTime] [DateStyle=FULL] [TimeStyle=MEDIUM]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM)));
            // 2014年4月2日 19:37:15
    
            pl.accept("[ofLocalizedDateTime] [DateStyle=FULL] [TimeStyle=SHORT]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.SHORT)));
            // 2014年4月2日 19:37
    
            pl.accept("[ofLocalizedDateTime] [DateStyle=LONG] [TimeStyle=MEDIUM]");
            pl.accept(datetime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.MEDIUM)));
            // 2014/04/02 19:37:15
    
    
           //----------------------------------------------------------------------------------------------
           // format use DateTimeFormatter ofPattern()
           //----------------------------------------------------------------------------------------------
            pl.accept("[ofPattern] era 暦:型により異なる");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("G")));
            // 西暦
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("GGGG")));
            // 西暦
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("GGGGG")));
            // A
    
            // java.time.chrono.JapaneseDate の場合
            pl.accept(JapaneseDate.now().format(DateTimeFormatter.ofPattern("G")));
            // 平成
            pl.accept(JapaneseDate.now().format(DateTimeFormatter.ofPattern("GGGG")));
            // 平成
            pl.accept(JapaneseDate.now().format(DateTimeFormatter.ofPattern("GGGGG")));
            // H
    
            pl.accept("[ofPattern] year 年");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("uuuu")));
            // 2014
    
            // java.time.chrono.JapaneseDate の場合
            pl.accept(JapaneseDate.now().format(DateTimeFormatter.ofPattern("uuuu")));
            // 2014
    
            pl.accept("[ofPattern] year-of-era (暦を考慮した)年");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("yyyy")));
            // 2014
    
            // java.time.chrono.JapaneseDate の場合
            pl.accept(JapaneseDate.now().format(DateTimeFormatter.ofPattern("yy")));
            // 26
    
            pl.accept("[ofPattern] day-of-year 1/1からの経過日数");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("D")));
            // 92
    
            pl.accept("[ofPattern] month-of-year 月");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("M")));
            // 4
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("MM")));
            // 04
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("MMM")));
            // 4
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("MMMM")));
            // 4月
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("MMMMM")));
            // A
    
            pl.accept("[ofPattern] day-of-month 日");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("d")));
            // 2
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("dd")));
            // 02
    
            pl.accept("[ofPattern] quarter-of-year クオーター");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("Q")));
            // 2
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("QQ")));
            // 02
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("QQQ")));
            // Q2
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("QQQQ")));
            // 第2四半期
    
            pl.accept("[ofPattern] week-based-year 週基準年");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("YYYY")));
            // 2014
    
            // 例えば2014/1/1は水曜日なので2013/12/31は2014に組み込まれます
            pl.accept(ZonedDateTime.of(2013,12,31,0,0,0,0,ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("YYYY")));
            // 2014
    
            pl.accept("[ofPattern] week-of-week-based-year 年を通しての週基準年の週 (1~52 or 53)");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("w")));
            // 14
    
            // 2013/12/31(火)は2014年の1週目
            pl.accept(ZonedDateTime.of(2013,12,31,0,0,0,0,ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("w")));
            // 1
    
            // 2013/12/28(日)は2013年の52週目
            pl.accept(ZonedDateTime.of(2013,12,28,0,0,0,0,ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("w")));
            // 52
    
            pl.accept("[ofPattern] week-of-month 週");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("W")));
            // 1
    
            pl.accept("[ofPattern] day-of-week 曜日");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("E")));
            // 水
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("EE")));
            // 水
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("EEE")));
            // 水
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("EEEE")));
            // 水曜日
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("EEEEE")));
            // 水
    
            pl.accept("[ofPattern] localized day-of-week");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("e")));
            // 4
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("ee")));
            // 04
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("eee")));
            // 水
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("eeee")));
            // 水曜日
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("eeeee")));
            // 水
    
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("c")));
            // 4
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("ccc")));
            // 水
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("cccc")));
            // 水曜日
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("ccccc")));
            // 3
    
            pl.accept("[ofPattern] week-of-month");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("F")));
            // 2
    
            pl.accept("[ofPattern] am-pm-of-day");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("a")));
            // 午後
    
            pl.accept("[ofPattern] clock-hour-of-am-pm (1-12)");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("h")));
            // 9
    
            pl.accept("[ofPattern] hour-of-am-pm (0-11)");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("K")));
            // 9
    
            pl.accept("[ofPattern] clock-hour-of-am-pm (1-24)");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("k")));
            // 21
    
            pl.accept("[ofPattern] hour-of-day (0-23) 時");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("H")));
            // 21
    
            pl.accept("[ofPattern] hour-of-day (00-23) 時");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("HH")));
            // 21
    
            pl.accept("[ofPattern] minute-of-hour 分");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("mm")));
            // 20
    
            pl.accept("[ofPattern] second-of-minute 秒");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("ss")));
            // 58
    
            pl.accept("[ofPattern] fraction-of-second ミリ秒");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("SSS")));
            // 094
    
            pl.accept("[ofPattern] nano-of-second ナノ秒");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("n")));
            // 94000000
    
            pl.accept("[ofPattern] milli-of-day 1日の経過ミリ秒");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("A")));
            // 76858094
    
            pl.accept("[ofPattern] nano-of-day 1日の経過ナノ秒");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("N")));
            // 76858094000000
    
            pl.accept("[ofPattern] time-zone ID タイムゾーンID ZonedDateTime以外では使用不可");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("VV")));
            // Asia/Tokyo
    
            pl.accept("[ofPattern] time-zone name タイムゾーン名 ZonedDateTime以外では使用不可");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("z")));
            // JST
    
            pl.accept("[ofPattern] localized zone-offset");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("0")));
            // 0
    
            pl.accept("[ofPattern] zone-offset オフセット UTC(+0000)の場合 +0000の代わりにZを表示");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("XXXX")));
            // +0900
    
            // UTCの場合
            pl.accept(ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.ofPattern("XXXX")));
            // Z
    
            pl.accept("[ofPattern] zone-offset オフセット");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("xxxx")));
            // +0900
    
            // UTCの場合
            pl.accept(ZonedDateTime.now(ZoneId.of("GMT")).format(DateTimeFormatter.ofPattern("xxxx")));
            // +0000
    
            pl.accept("[ofPattern] zone-offset オフセット");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("Z")));
            // +0900
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("ZZ")));
            // +0900
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("ZZZ")));
            // +0900
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("ZZZZ")));
            // GMT+09:00
    
            pl.accept("[ofPattern] escape for text / [] # {} 次の文字列はシングルクォートでエスケープが必要です(/[]#{})");
            pl.accept(datetime.format(DateTimeFormatter.ofPattern("'['yyyy'/'MM'/'dd']' '{'HH'#'mm'#'ss'}'")));
            // [2014/04/02] {21#20#58}
    
            pl.accept("[withZoneSameInstant] タイムゾーン変換");
            pl.accept(datetime.withZoneSameInstant(ZoneId.of("America/Los_Angeles")).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T05:20:58.094-07:00[America/Los_Angeles]
    
    




    java.time.chrono.JapaneseDate の文字列変換

            Consumer<Object> pl = System.out::println;
    
            JapaneseDate jd = JapaneseDate.now();
            pl.accept("[Japanese Era Name List] 和暦名一覧");
            jd.getChronology().eras().forEach(pl);
            // Meiji
            // Taisho
            // Showa
            // Heisei
    
            pl.accept("[toString]");
            pl.accept(jd.toString());
            // Japanese Heisei 26-04-02
    
            pl.accept("[Japanese Era Name] 和暦(名)");
            pl.accept(jd.getEra());
            // Heisei
    
            pl.accept("[Japanese Era Year] 和暦(年)");
            pl.accept(jd.get(ChronoField.YEAR_OF_ERA));
            // 26
    
            pl.accept("[Era] -1=明治/0=大正/1=昭和/2=平成");
            pl.accept(jd.get(ChronoField.ERA));
            // 2
    
            pl.accept("[InstantSeconds] エポック日(Unix時間/日) 1970-01-01からの経過日");
            pl.accept(jd.getLong(ChronoField.EPOCH_DAY));
            // 16162
    
            pl.accept("[ofPattern]");
            pl.accept(jd.format(DateTimeFormatter.ofPattern("Gyy年 MM月dd日")));
            // 平成26年 04月02日
    
    




    日時操作サンプル



    java.time.ZonedDateTime の日時操作

            Consumer<Object> pl = System.out::println;
    
           //----------------------------------------------------------------------------------------------
           // 日時操作
           //----------------------------------------------------------------------------------------------
            pl.accept("[original]");
            pl.accept(datetime.format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T21:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Years] +1年");
            pl.accept(datetime.plusYears(1).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2015-04-02T21:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Months] +1ヶ月");
            pl.accept(datetime.plusMonths(1).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-05-02T21:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Days] +1日");
            pl.accept(datetime.plusDays(1).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-03T21:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Hours] +1時間");
            pl.accept(datetime.plusHours(1).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T22:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Minutes] +1分");
            pl.accept(datetime.plusMinutes(1).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T21:21:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Seconds] +1秒");
            pl.accept(datetime.plusSeconds(1).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T21:20:59.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Millis] +1ミリ秒");
            pl.accept(datetime.plus(1, ChronoUnit.MILLIS).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T21:20:58.095+09:00[Asia/Tokyo]
    
            pl.accept("[+1Micros] +1マイクロ秒");
            pl.accept(datetime.plus(1, ChronoUnit.MICROS).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T21:20:58.094001+09:00[Asia/Tokyo]
    
            pl.accept("[+1Nanos] +1ナノ秒");
            pl.accept(datetime.plusNanos(1).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-02T21:20:58.094000001+09:00[Asia/Tokyo]
    
            pl.accept("[+1Weeks] +1週");
            pl.accept(datetime.plusWeeks(1).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-09T21:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1HalfDays] +12時間");
            pl.accept(datetime.plus(1, ChronoUnit.HALF_DAYS).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2014-04-03T09:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Decades] +10年");
            pl.accept(datetime.plus(1, ChronoUnit.DECADES).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2024-04-02T21:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Centuries] +100年");
            pl.accept(datetime.plus(1, ChronoUnit.CENTURIES).format(DateTimeFormatter.ISO_DATE_TIME));
            // 2114-04-02T21:20:58.094+09:00[Asia/Tokyo]
    
            pl.accept("[+1Millennium] +1000年");
            pl.accept(datetime.plus(1, ChronoUnit.MILLENNIA).format(DateTimeFormatter.ISO_DATE_TIME));
            // 3014-04-02T21:20:58.094+09:00[Asia/Tokyo]
    
    

    他に有用なものがあり次第追加していきます。