Upload
kentaro-maeda
View
1.378
Download
0
Embed Size (px)
DESCRIPTION
2014年10月25日に実施されたJava8勉強会の資料です。
Citation preview
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by
Java8勉強会
ウルシステムズ株式会社
前多賢太郎
2014/10/25
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 1
はじめに
今年3月にJava8がリリースされました。
Java8には、インターフェースデフォルト実装, ラムダ式, Stream APIという設計・コーディングに大きな影響のあるアップデートが含まれます。そのためか、まだ開発の現場で採用になったという声は聞かれません。
6/25にJava8対応版 Eclipse4.4 Luna もリリースされ、 Java8による開発がいよいよ広がっていくと予想されます。
–なおNetBeansの方が完成度高いです。
– Lunaはラムダ式のコードアシストが効かない、コンパイルできないバグがあります。
というわけで、ここら辺でJava8の新機能をおさらいします。
–目玉となるラムダ式,Stream APIについて、オブジェクトとどのように組み合わせるかという事を中心に演習を実施します。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 2
前提事項
本日はJava8の変更点を体感するため、演習を行います。
演習を行うため事前に、jdk8, Eclipse4.4またはNetBeans8 の導入をお願いします
– IntelliJ IDEAでもかまいませんが上記の2つほど念入りに動作検証を行っていません。
演習問題はmavenプロジェクトとして以下に公開しています。
– https://github.com/enterprisegeeks/java8_study
– 上記のページの指示に従って導入をお願いします。
– 解答は上記ページのanswerブランチで、勉強会終了後に公開します。
なお、現状NetBeans8/IntelliJ IDEAの方が使い勝手が良いです。
– eclipseはコンパイラにバグがあります。
– NetBeansで編集中のファイルのmainを実行するには、Shift + F6 です。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 3
Javaによくあるイメージ
コードが長い・冗長
– System.out.println とか
– リストから何かを探すコードとか
– ファイルの入出力とか
– Etc,,,,
確かに、Javaのコードは堅苦しいと思うときがある。
– rubyとかLL言語に手を出すと特にそう思う。
–一方で、Java SE5以降、static import・try-with-resource句、java NIO2など簡潔に書ける言語仕様が取り入れられつつある。
Java8 ではラムダ式・Stream APIの導入により、更なるコードの簡潔さと平行性・(個人的に)楽しさを取り入れることが可能になる。
for (String s : list) {if (s.equals(“100")) {
return s;}
}
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 4
Java8 更新機能一覧
Java8の更新機能一覧は以下で見れます。
– http://openjdk.java.net/projects/jdk8/features
更新機能のサマリは以下を見てください。http://yoshio3.com/2014/03/21/congrats-javase8-launch/
本日はラムダ式、Stream APIなど文法や新APIに焦点を絞ります。
また、Stream APIについては、以下にも詳しい説明があります。
– http://enterprisegeeks.hatenablog.com/category/Java8
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 5
目次
ラムダ式
演習1
Stream API
演習2
演習3
Optional
インターフェース拡張
– staticメソッド実装
–デフォルトメソッド
演習4
その他トピック
–日付API
– JVMまわり
90分
90分
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 6
ラムダ式
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 7
ラムダ式とは
仕様
– JEP126 Lambda Expressions & Virtual Extension Methods
できるようになったこと
– ラムダ式の文法追加による(限定的な)関数型プログラムのサポート
影響
–関数型(ラムダ式)を使うと
特定の処理が、非常に簡単に書ける。
オブジェクト指向よりも、使い勝手の良いAPIを提供できる。
–一方で
Javaしかプログラム経験の無い人には、ラムダ式や関数型を理解するのは難しい。
コーディング規約でラムダ式禁止とかありえそう。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 8
ラムダ式って? 関数型プログラムって?
関数って?
–何らかの値を取り、何らかの値を返すもの。
ラムダ式って?
–関数の表現方法。数学由来で、関数を λx. x+2 のように書くから。
–プログラムでは、匿名関数を生成するリテラルとして使用する。
Javaにしかないの?
– Javaは後発。 Ruby, C#, C++11, javascript, Python なんでもござれ。
関数型プログラムって?
–広義には、関数を値として扱えるプログラムスタイル。(他にも色々あるが割愛)
大雑把にいうと、関数を変数、メソッド引数や戻り値に指定できる事。Javascriptの以下のような書き方が、Javaでも可能になる。
C の関数ポインタも、関数型の一種と言えなくはない。。。
var add2 = function(x){return x + 2;}add2(3) // 5
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 9
ラムダ式の文法と型
文法
–基本書式
–省略形での記述も可能。というよりなるべく省略形を使ったほうが、良い。
引数の型は、省略可能で型は、その場合コンパイラが推測する(後述)。
引数リストは、引数が1つの場合はカッコが省略可能。(ただし引数なしは()とする )
メソッド本体はメソッドが1行の場合、{}とreturn,セミコロンを省略可能。
疑問
– どうしてラムダ式の引数の型を書かなくても良いの?戻り値の型の宣言は?コンパイルエラーや実行時エラーが起きるんじゃないの?
– ラムダ式で作った関数(値)って結局何なの?
//文字列比較の例 int copmareTo(String x, String y)(String x, String y) ->{return x.compareTo(y);}
(型 引数1, 型 引数2、、、) -> {メソッド本体}
//省略形(x,y) -> x.compareTo(y)
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 10
ラムダ式の文法と型
型と型推論
– ラムダ式は、ラムダ式を受け取る変数や引数がセットで必要。
–それらの型は、関数型インターフェースという特定の条件を満たしたインターフェースである必要がある。
関数型インターフェースとは?
– 実装するべきメソッドが1つのみのインターフェース(staticメソッド、デフォルトメソッドは幾つあってもよい。equals等Objectのメソッドも対象外)
– Comparator(compare),Runnable(run)などが対象。
– @FunctionalInterfaceアノテーションが追加。コンパイル時に関数型インターフェースの要件を満たすかチェック可能。(チェックだけなので、アノテーションはあってもなくてもよい。)
–つまり、ラムダ式で生成されたオブジェクトは、関数型インターフェースを実装した匿名クラスのオブジェクト。
– ラムダ式で省略した引数や戻り値の型は、変数・引数の型宣言からコンパイラが推測して、合わない場合はコンパイルエラーとする。このような仕組みを型推論と呼ぶ。
Comparator<String> comp = (x,y) -> x.compareTo(y)comp.compare("aaa", "bbb"); //-1
インターフェースのメソッドがint compare(String, String) なので、x,yをStringと推測し、x,yが実行するメソッド、戻り値がintになるかをチェックする。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 11
ラムダ式の正体
結局のところ、Java8のラムダ式はメソッドが1つしかないインターフェースの匿名クラスを作るシンタックスシュガー
–匿名クラスとラムダ式は(ほとんど※)同じ。→5行が1行に! 5倍の生産性!
–匿名クラスと比較して、ラムダ式のほうが実際の処理のみを記述しておりノイズが少ない。
一方で、メソッド名などがないのでラムダ式に該当する変数名などの命名が重要となる。
–※匿名クラスはコンパイル時にクラスファイルが作られるが、ラムダ式ではクラスファイルは作成されない。
Invoke dynamicという新しく追加されたJVM命令を使って、実行時にインスタンス生成が行われている。
ラムダ式は多用されるので、Invoke dynamicによる最適化の余地を残している。
Comparator<String> comp = new Comparator<String>(){public int compare(String x, String y) {
return x.compareTo(y);}
};
Comparator<String> comp = (x,y) -> x.compareTo(y)
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 12
ラムダ式の利用箇所
使いどころ
–処理の大枠が決まっていて一部の挙動を変えたいという場合、継承やインターフェース実装を使うよりもシンプルに実現できる。
イベントハンドラ、コールバック(Swingとか)
Stream API(後述)
Strategyパターン (Collections#sortとか)
Visitorパターン
–匿名クラスを受け取る前提だったAPIの引数は、ラムダ式に置き換えが可能。5倍の生産性は言いすぎだが、体感で2,3割コードが短くなる事もある。→ NetBeansはラムダ式に置換なコードを教えてくれるできたやつ。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 13
ラムダ式利用サンプル
既存APIや、ラムダを使う例
個人的には3番目の例のような、リソース(ファイル,JDBC)の情報を任意のオブジェクトにマッピングする方法として、ラムダ式が多用されるのではと思う。
–引数ありのコンストラクタや、toString,equals,hashCodeがちゃんと定義されているとベター。
–最後の “System.out::println”は次で解説。
//Collections#sort, Comparator#compare((T,T)->int)List<Integer> list = Arrays.asList(5,4,3,2,1);Collections.sort(list, (x, y) -> x - y);// 1,2,3,4,5
//Swing addEventListner for Button. ActionListener#actionPerformed()JButton b2 = new JButton("B");b2.addActionListener(e -> textField.setText("B clicked."));
// CSVの1行をカンマで分割した配列を、任意のオブジェクトに変換する自作メソッドList<Person> list = CSVReader.read(new File("user.csv"),
array -> new Person(array[0], array[1]));list.forEach(System.out::println);// ←何だこれ?
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 14
メソッド参照
前述の、”System.out::println”はメソッド参照と呼ばれる新しい記法。
既存のメソッドを用いるだけのラムダ式を、関数オブジェクトとしてラムダ式の引数を省略する。
–関数プログラムでは、関数を引数に取る場所に、直接関数名を渡す事ができるので、それと似たようなものを実現している。
–以下のような場合に置き換える事ができる。
ラムダ式の引数をstaticメソッドに渡すだけの場合。
– s -> System.out.println(s) => System.out::println
ラムダ式の引数のインスタンスメソッドを呼ぶだけの場合
– s -> s.lengh() => String::length
– u -> u.getName() => User::getName
(主に)引数なしのラムダ式でコンストラクタを呼ぶだけの場合(supplier,generatorと呼ばれる)
– () -> new ArrayList() => ArrayList::new
メソッド参照を書ける必要は無いが、読める必要はある
– Javadocを見ていると当たり前にメソッド参照のコードが出てくる
メソッド参照が書けるようになると、ラムダ一人前
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 15
メソッド参照の例
以下のラムダ式と同じ意味のメソッド参照の例を示す。
– NetBeansはメソッド参照に置き換え可能なラムダ式を教えてくれるできたやつ。
// 引数あり、戻り値なしの例list.forEach(e -> System.out.println(e));list.forEach(System.out::println);
// 引数なしの例。コンストラクタもメソッド参照可能Supplier<List<String>> s1 = () -> new ArrayList<>();Supplier<List<String>> s2 = ArrayList::new;List<String> l = s2.get(); // ArrayList
// 2引数の例。Integer.sumは加算メソッドだが、メソッド参照ために用意されたみたいだ。BinaryOperator<Integer> add1 = (a,b)-> Integer.sum(a, b);BinaryOperator<Integer> add2 = Integer::sum;add2.apply(5,6);// 11
// オブジェクトのメソッドも実行可能。インスタンスメソッドなのに、Person::となるのは正直キモイFunction<Person, String> p1 = p -> p.getName();Function<Person, String> p2 = Person::getName;
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 16
演習1(20分)
パッケージ practice1
–対象
LambdaLession.java
– ラムダ式の書き換え
– オブジェクトとラムダ式の組み合わせ
LetsMakeHFO.java
– ラムダ式を受け取るメソッドを作ろう。
テストデータ
–テストデータは、部署-課-社員 の階層構造を持つオブジェクトです。
部署は課の一覧を取得できる。(総務部は、総務1課,総務2課などを取得可能)
課は所属する部署を取得できる。
課は課に所属する社員の一覧を取得できる。
社員は所属する課を取得できる。
TestDataは、全ての部署、全ての課、全ての社員を取得するユーティリティです。
部署 課 社員
総務 総務1課
総務2課
田中
山田営業
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 17
標準の関数型インターフェース
既存の多くのインターフェースが関数型インターフェースになりえるが、java.util.functionパッケージに、標準的な関数型インターフェースが追加された。
– (むしろ、既存のインターフェースと関数型インターフェースを別物にできれば、本当の関数型が導入できたかもしれないが、下位互換のために諦めたような気がする)
ラムダ式を扱う前提のAPIを作成する場合に使うと良い。
Stream APIをはじめとして、標準APIにも関数型インターフェースを受け取るものが多くあるので、意味を知っておく必要がある。そうでないと、Stream APIのjavadocが理解できない。
抜粋
関数型インターフェース 引数 戻り値 用途
Function<T,R> T R TからRへの変換を行う。
Consumer<T> T void 任意の副作用を実行する。
Supplier<T> void T値Tを生成する。(型パラメータはRの方が適切だが、JavadocではT)
Predicate<T> T boolean Tから真偽値を判定する。
BiFunction<T,U,R> T,U R2つの引数T,UからRへの変換・計算を行う。 この他、Bixxxは2引数を取るという意味
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 18
ラムダ式まとめ
ラムダ式(関数型)は、オブジェクト指向よりもコンパクトに、コードの再利用を促す
– オブジェクト指向は、フレームワークやモジュールのような大きな粒度に向いている
– 関数型は、共通関数とか簡潔なコードのような小さい部分に向いている
– 両者をバランスよく使っていきましょう。
Java8のラムダ式は、後付けかつ機能が限定的なのでちぐはぐな部分が多い。
– ラムダ式で作った関数オブジェクトの関数を呼ぶ場合に、“変数名.メソッド”とする必要があるのは微妙。(前述の add2.apply(5,6) みたいな。 Javascriptだとadd2(5,6)でいける)
–関数合成ができるが、カリー化、部分適用、遅延評価、多相、末尾再帰みたいな機能はない。
Java8でのラムダ式の使いどころは、引数に関数を渡す時
–変数や戻り値にしたところで前述の問題があるので使いづらい
– Java8で関数型プログラムにこだわりすぎると、逆に失敗する
ラムダ式導入の目的はStream APIのためで、関数型プログラムではありません
関数型プログラムをやりたいなら言語を変えましょう
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 19
ラムダ式補足
例外と相性が悪い– もしチェック例外を投げる必要があるなら、関数型インターフェースのメソッド宣言でthrows句を付ける必要があります。
– Function等デフォルトの関数型インターフェースにはthrows句がありませんので、(Stream API)でチェック例外を扱う必要が出てくると、ラムダ式本体にtryとか書く必要があるので発狂する。
– Java.io.UncheckedIOExceptionとか、Javaの基本スタンスを崩すようなものも出てきた。
ラムダ式の外部の変数参照
–無名クラスではfinal変数に限り外部変数の参照ができた。
– ラムダ式も同様に、final変数ならびに事実上のfinal変数(※)の参照が可能
※ コンパイラが、参照が変わらない変数をfinalとしてみなすように変更された。
参照が変わらないなら、外部のListのaddなど実行できるが、行うべきでない。(後述)
thisの扱い
– ラムダ式中のthisは、ラムダ式を定義したメソッドのインスタンスのthis
ラムダ式でthisを使う事は余り無いが、一応注意。
標準Functionは合成可能
– Functionなど、標準関数インターフェースはandThenなど、関数合成に関するメソッドをdefaultメソッドとして定義している。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 20
コレクションに追加されたメソッド (example.CollectionLambda.java)
コレクションにもラムダ式を取るメソッドが追加されています。
- Iterable#forEach(Consumer)
– List#sort(Comparator)
– Map#forEach(BiConsumer)
– Map#compute(key, Function)
– これらのメソッドは、後述するデフォルトメソッドにてインターフェースに実装がある。
// Listの中身を出力Arrays.asList(1,2,3,4).forEach(System.out::println);// 演習1 ソートの別解List<Emp> list = TestData.allEmployees();list.sort(Comparator.comparing(Emp::getName));list.forEach(e -> System.out.println(e.getId() + ":" + e.getName()));// Mapの値更新、出力Map<Integer, Integer> map = new HashMap<>();map.put(1, 2);map.put(2, 3);// キーが2の値を累乗する。map.compute(2, (k, v) -> v * v);map.forEach(
(k,v)-> System.out.println(String.format("key=%d:value=%d", k,v)));
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 21
Stream API
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 22
Stream APIの概要
仕様
– JEP107 Bulk Data Operations for Collections
– IOストリーム とかあるのに、Stream APIとか言っちゃうんだ、、、
できるようになったこと
– コレクション等一連の要素の集まりに対して,ラムダ式を使用した抽出/演算/変換等の一括操作の提供、および、逐次処理・並列処理(※)の提供
影響
– コレクションに対する操作をfor/whileを使った方式から、Stream APIを使用した新しい方式で書けるようになる。
–利点
宣言的であり、読みやすく、間違いが少ない
並列処理への切り替えが容易
配列・リスト・入出力などが同じ方法で扱える
–欠点
Stream APIを使いこなすには覚える事が多い
実用するには色々と機能が足りてない
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 23
例題
例題
–文字列のリストから整数とみなせる文字列を抽出し、整数に変換し、正の整数のみを抽出し、3倍する。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 24
従来の方法(example.StreamBasic.java)
例題
–整数リストから偶数の要素のみ抽出し、数を2倍した要素を取得する。
– このような手続き型のコードは、条件分岐がネストしだすと、コードをよく見ないと、要件に合致する処理が書いてあるかわからない。
List<String> list = Arrays.asList("A001", "100", "-200", "ABC", "92");
List<Integer> res = new ArrayList<>();for (String s : list) {
if (s.matches("[-+]?\\d+")) {int i = Integer.parseInt(s);if (i > 0) {
res.add(i * 3);}
}}System.out.println(res);//300, 276
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 25
Stream API による解法(example.StreamBasic.java)
例題
–整数リストから偶数の要素のみ抽出し、数を2倍した要素を取得する。
解説
– Streamという一連の要素の集まりに、抽出(filter)・演算(map)のような操作を連結して繰り返し処理の内容を組み立てる。最終的にcollectメソッドで、操作した要素をList等に変換する。よくわからなければ、SQLでイメージしてもらうといいかもしれません。
– 操作の内容はラムダ式で何をするのかを書く。
– なんとなく、例題の処理内容とラムダ式の内容が揃ってる感じがしませんか。
– あと変数も少ないですよね。
List<String> list = Arrays.asList("A001", "100", "-200", "ABC", "92");
List<Integer> res2 = list.stream() // Streamを‚生成.filter(s -> s.matches(“[-+]?\\d+”))//整数のみ抽出.map(s -> Integer.parseInt(s)) //文字列→整数.filter(i -> i > 0) // 正の整数のみ抽出.map(i -> i * 3) // 3倍する.collect(Collectors.toList()); //結果をListとして取得
System.out.println(res2);
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 26
Stream APIとは
大雑把にいうと
– ものすごいイテレーター。
繰り返し処理に、条件抽出や変換、件数指定などの操作を幾らでも設定できる。
–繰り返し処理の方法はStream APIの中に隠蔽される。
今まで繰り返しは、for/while/拡張for文などを選んでいたが、その必要がない。
– 繰り返し処理の最適化をStreamに任す。
プログラマはStreamにどのような操作を行うか中心に書く。(宣言的なプログラム)
性質
– コレクションとは異なるクラス
生成 - Streamを使うには既存のコレクションや配列から、別途変換が必要
– Stream の各種メソッドは大別して以下の2種類に分かれる。
中間操作 – 生成で構築した集合に対する演算を適用する。
終端操作 – ストリームの集合から、コレクション、配列等への変換を行う。
–逐次処理/並列処理
繰り返し処理の方法を簡単に並列処理にできる。(処理の仕方を、プログラマが書く必要がないため。)
–遅延処理
繰り返し処理は最後に一度だけ実行される。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 27
生成・中間操作・終端操作
生成で様々なオブジェクトからStreamを作る
中間操作でStreamに設定を追加する
終端操作でStreamを処理して結果を得る
–繰り返し処理や並列処理の詳細はStreamの中だけで完結する
List
配列
IO
生成 終端操作Stream
中間操作 List
int
Etc..
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 28
Stream の生成
生成
–色々なデータからStreamを生成するメソッドが、多数追加された。
コレクションから – Collection#stream, parallelStreamメソッド
配列 - Arrays#stream
IOストリーム、ファイル – BufferedReader#lines, Files#lines
任意の可変長引数で – Stream#of
文字列から文字のストリーム – String#codePoint
無限数列 – Stream#iterate, Stream#repeat
範囲生成(1から100までとか) – IntStream#range
他多数
–ストリームを構築するコードを書く必要はありますが、逆に、元がコレクション、配列、ファイル、その他、何であっても一旦ストリームにしてしまえば、後は同じ方法で扱う事ができる。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 29
Stream の中間操作
中間操作(抜粋)
– Streamの要素に対する何らかの演算の指定を行うメソッド。中間操作は必ずStreamが戻り値なので、メソッドチェーンで連結できる。
filter – 条件ラムダ式に一致する要素のみを抜き出す。
map – 要素をラムダ式に適用して計算・変換する。
flatMap - 要素をStreamを生成するラムダ式に適用し、要素の増減を行う。
parallel – 繰り返し処理を並列処理で行う指示をする。
limit – 繰り返し処理を行う件数を制限する。
skip - 繰り返し処理を件数分スキップする。
以下は状態がある中間操作と呼ばれ、全ての要素の評価が終わらないと実行できない。そのため、性能に影響を与える可能性がある。
– sort - 要素を並べ替える。
– distinct – 要素の重複を除外する。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 30
Stream の終端操作
終端操作(抜粋)
– Streamから結果を生成する操作。終端操作を行った時点でStreamに設定された中間操作が順次実行され、終端操作の内容で結果が作られる。1つのStreamには、1回だけ終端操作を行うことができる。
anyMatch – ラムダ式の条件に合致する要素があるかbooleanで返す。※
allMatch – 全ての要素がラムダ式の条件に合致するかbooleanで返す。 ※
max, min – Comparatorを渡し、要素の最大・最小値を返す。
reduce – 全ての要素の合計値を出すなど、1つにまとめた結果を返す。
forEach - コンソール出力等、任意の副作用を実行する。
count – 件数取得
findFirst – 最初の1件を返す ※
collect – 汎用的な集積操作。Collectorsユーティリティによく使う操作が定義済み。
– Collectors#toList – 要素をListへ変換する。
– Collectors#joining – 要素を1つの文字列にする。接続句を指定可能。
– Collectors#partitionBy – 要素をラムダ式の条件を満たすものと満たさないものに分割する。
– Collectors#groupingBy – 要素をラムダ式の条件にしたがって複数のグループに分割する。
–※ anyMath, allMath,findFirstなどはショートサーキット評価であり、条件が一致した時点で要素を全て評価せず処理を打ち切る。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 31
Stream コードサンプル (example.StreamSample.java)
今までこういう処理って、似たようなforループを何度も書いていましたよね。
–負数があるか?
–全てaから始まるか?
– ファイルの101行目から200行目だけを出す。
– -文字列の間に”,”をつけて1つの文字列に。
boolean negative = Stream.of(1,2,23,-4,5,-6).anyMatch(n -> n < 0); // true
boolean startsWith_a = Stream.of("angel", "apple", "banana").allMatch(s -> s.startsWith("a"));//false
Files.lines(new File("log.txt").toPath()).skip(100).limit(100).forEach(System.out::println);
String[] sa = new String[]{"AA", "BB", "CC", "DD"};String concat = Arrays.stream(sa)
.collect(Collectors.joining(","));
String concat2 = String.join(“,”, sa);//別解
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 32
Stream コードサンプル2
–整数リストの乗算 (Java8 ではreduceよりcollectを推奨)
–単語リストを始まりの1文字でグループ化したい。
グループ化した要素はデフォルトはリストだが、任意の変換を適用する事も可能
–ユーザーの平均年齢を得たい。
String[] word={"apple", "angel", "banana", "bush", "cross", "dart"};Map<Character, List<String>> group = Arrays.stream(word)
.collect(Collectors.groupingBy(w -> w.charAt(0)));
int sum = Stream.of(1,2,3,4,5).reduce(1, (a, b) -> a * b);//120
double avg = userList.stream().collect(Collectors.averagingDouble(u -> u.getAge()));
1 2 3 4 5
1 1 2 6 24 120
整数リストの要素(b)
集積器 (a)
Reduce(折りたたみ演算)のイメージ
* * * * *
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 33
Stream コードサンプル3 (example.RangeSample)
–範囲生成
IntStreamを用いて、1から10のような数の範囲を作成できる。
–無限ストリーム
Stream#iterateは初期値からラムダ式を適用し、無限に値を生成する。
– そのままforEachなどとすると無限ループとなるが、有限のストリームと組み合わせる(zip)、件数制限を行う(limit等)によって、breakに相当する仕組みを作れる。
// 1から10の合計int sum = IntStream.range(1, 11).sum();
// 0から9の数字のうち、乗算が25を超える数の組み合わせを求める。List<String> comb = IntStream.range(0, 10).boxed()
.flatMap(x -> IntStream.range(x, 10).boxed().filter(y -> x * y >= 25).map(y -> x + "," + y))
.collect(Collectors.toList());
// 無限数を用いて、自然数のうち3または5で割れる100番目の数を求める。Optional<Integer> num = Stream.iterate(1, i -> i + 1) //無限ループ?
.filter(i -> i % 3 == 0 || i % 5 == 0)
.skip(99).findFirst();
num.ifPresent(System.out::println);//215
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 34
演習2(20分)
オブジェクトを対象として、Stream APIの各種操作を行います。
パッケージ: practice2
– LetsStream
ポイント
– filter, map, collect(Collectors.toList())が基本。
–包含判定は、anyMatch,allMatch,noneMatchが使える。
– collect,CollectorsにはtoList以外に色々便利機能がある。
joinging – 文字列集合に接続句(オプションで接頭句、接尾句)もつけて1つの文字列に。
Sepalateby – 集合を2つに分ける。分け方はbooleanを返すラムダ式で指定
groupingBy - ↑を一般化。集合をラムダ式の演算結果によって分ける。
avaraging, sumarying, summing – 平均、サマリ、合計の算出。
– flatMapが最初はわかりにくいと思います。これは2重ループに相当すると思ってください。(TestData.javaのallSection()とflatMapの演習を比較してみてください)
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 35
休憩
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 36
並列処理への対応
繰り返し処理を並列で行うには?
– forループをマルチスレッドにするには多大な労力が伴う。
– Stream APIでは、parallelメソッドを呼ぶだけ
example.TryParalle.java
–並列処理でも要素の順番は保証される。(一部例外あり)
分割して処理した要素を、1つにまとめ、元の順番に復元する。
逐次並列・並列どちらで行っても同じ結果
ただし、以下の場合は例外
– forEachメソッド (順序が必要ならforEachOrderedを使う)
– 中間操作 unordered(順序保証をなくす)を実行した場合。
List<Integer> list = IntStream.range(1, 1000).boxed()
.parallel().peek(i -> System.out.println(“N=" + i)).map(i -> i * 100 + i).collect(Collectors.toList());
System.out.println(list);
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 37
並列処理への対応2
–一部の中間操作や終端操作と併用する場合、非効率となる事があるので、注意が必要。更に、場合によっては無限ループになることがある。
skipは先頭N件の読み飛ばす、findFirstは先頭1件を取り出す、このような処理は並列処理の場合全ての要素の評価が終わって順序付けしないとどれが最初のN件だったかがわからない
– 逐次処理だとforループの読み飛ばしなどで簡単にできるが、並列だと効率が悪くなってしまう例
– 要素が無限の場合は評価が終わらないので、無限ループになってしまう!
並列をやめるか、unorderedを指定する。
–外部変数の状態に依存するラムダ式を書くと不正な結果になる。
forEachで、外部の変数に要素を追加するような処理は並列処理で順番がずれる。
– 概ね、そのような処理は終端操作で実現できる。
–並列化のコストがかかるので、何でも並列にすれば良いわけではない。
効果が大きいのは以下が両立する場合
– 繰り返し処理1回あたりの処理時間が長い
– 要素数が多い
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 38
遅延処理
問題 ファイルlog.txtがオープンするのはどこ?
– ファイル”log.txt”の”error”が含まれる行に”Error = “を付けて10件まで表示する。
Files.lines(new File("log.txt").toPath()).filter(line -> line.contains("error")).map(line -> "Error = " + line).limit(10).forEach(line -> System.out.println(line));
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 39
遅延処理 2
答 – 終端操作(forEach)が実行されるとき。
–中間操作は操作の予約をするだけ。
–終端操作で、要素ごとに中間操作を適用していく。
以下のような処理が実行される。
繰り返し処理は1度だけ行われる。(中間操作ごとに繰り返し処理を行ったりしない)
そのため、無限のストリームも問題なく扱える。
try(BufferedReader br = Files.newBufferedReader(new File("log.txt").toPath())) {
String line;int i = 0;while((line = br.readLine()) != null) {
if (i == 10) break;if (line.contains("error")) {
String line2 = "Error= " + line;System.out.println(line2);
}i++;
}}
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 40
Stream APIと上手く付き合うコツ
ラムダ式は複雑にしない。
– filter, map等の操作を重ねる事で、ラムダ式自体は単純にする。
テストが簡単になる。操作の順番の入れ替えが容易。
– Filterは要素の判定、 mapは変換、forEachは順次処理という様に、決まった役割があるので、それ以外の処理をラムダ式で行わないようにする。
以下は、filteで行うべき処理がforEachに全て書かれてしまっている悪い例。
外部変数は参照だけする。決して状態を変更しない。
– 参照の変わらない変数であれば、外部変数のメソッドは実行できるが、並列実行すると順序が変わるので行うべきでない。
Stream の処理結果を終端操作の戻り値以外の手段で取得するのは、悪手。
– 外部状態に関わらず、同じ引数なら同じ結果を常に返す関数を、javaではステートレス操作と呼ぶ(純粋関数とも)。可能な限りステートレスなラムダ式を作成すること。
Stream.of(1,2,3,4).forEach(i -> {if (i % 2 == 0) {
System.out.println(i);}});
List<Integer> list = new ArrayList<>();Stream.of(1,2,3,4,5).map(i -> i * 2).parallel()
.forEach(i -> list.add(i)); //listの順番がめちゃくちゃList<Integer> list2 = Stream.of(1,2,3,4,5).map(i -> i * 2).parallel()
.collect(Collectors.toList()); //OK
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 41
Streamがいけてるところ
リストの詰め替えや、条件判定なんかはStreamの方が簡単に書けるし、どんどん使っていい。
– 変数の状態を更新する処理が減るので、バグが少なくなる(かも)
中間操作の順序を変えることで、処理内容を変えることが簡単にできる。
普通のforループの方が性能が良いんじゃないかと思うかもしれません。多分事実ですが、そういうことは性能的な問題が出てから考えましょう。
– forループとStreamの処理速度の違いは感じない。
– コード1箇所での最適化なんで、全体から見れば微々たる物。
– 最悪、並列処理にするという選択肢も取れる。
なおStreamのラムダ式を短く書くには以下を工夫すると良い。
– 引数ありのコンストラクタやオブジェクト生成のstaticメソッドを作る。
mapでオブジェクト生成を1行で書ける。
– equals,hashCode,toStringのオーバーライドや、判定メソッドなどの追加。
groupingByなどの集約条件や、filterの条件などが短く書ける。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 42
Streamがいけてないところ (私見)
正直何度も .stream(), .colletct(Collectros.,,,,) を書くのは飽きる。
–下位互換と並列処理の境界を設ける為にしょうがないとは思うけど、anyMatchとか、groupingByとかぐらいは、Listにあってもいいじゃんとは思う。(そんな事言ったら、コレクションと配列に同じメソッド作らんといけないし無理なんだろうけど)
–ついでに言うと、ラムダ式の変数名、変数宣言が必須なのもどうにかなりませんか。
map(i -> i * 3) を、 map(i * 3) と書きたい!
– 今の仕様なら、メソッド作ってメソッド参照にするしかない、、、、scalaなら。。。
StreamのJavadocを読むにはかなりの修行がいる。
–関数型インタフェースの種類と型の対応が理解しないと、どんなラムダ式が書けるか解らない。
ex) BiFunction<T,U,R> は、 (T, U) -> R というラムダ式。
–説明に当然のように出てくるメソッド参照。
– Stream全般もそうだが、Stream#collectの仕組みも複雑。
–ついでに言うと、コンパイルエラーのメッセージもひどい。
終端操作で結果をファイル出力するには、どうするのが正解なのか。
BufferedReader#lines,Files#linesから作ったStreamはcloseしないとリソースが解放されない(try-with-resource句も使える)。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 43
Streamがいけてないところ (私見)2
デバッグは困難。
–ブレークポイントと相性悪い。
中間操作にブレークポイント入れても、繰り返し処理中に止まるわけではない。
途中の結果を見るのが難しい。
–対策
Peekを上手く使う(デバッグ用途で使うなら、toStringを定義してあるとシンプルになるので良い)
複雑なラムダ式を書くより、1行のラムダ式で中間操作を重ねるようにしよう。
ユニットテスト
他の言語のStream API相当の機能には、zipと呼ばれる機能があるが、Stream APIにはなく、自作する必要がある。
– インデックスアクセスとか、前後の要素をみたい というような処理を行うにはzipが必要。
– zipを使うとなると、タプルのようなオブジェクトを組み合わせにできるものがリテラルとして欲しくなる。
– zipの概要はこちらをどうぞ。
– http://enterprisegeeks.hatenablog.com/entry/2014/05/19/100422
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 44
演習3(20分)
Zipを使ってみよう
パッケージ:practice3
– ソース :ZipPractice.java
Zipとは?
– 2つの集合を組み合わせ、要素同士のペアを作る操作。
– zipによって既存のforループで行う様々な処理を置き換え可能になる。
– Stream API相当の機能を持つ他の言語には大抵あるが、javaには無い。
途中までありましたが、リリース時に消えました。。。
clojureにもrubyにもC#にもscalaにもあるのに。。。。
1 2 3 4 5
a b c d
zip 1,a 2,b 3,c 4,d
要素の数が合わない場合は短い方に合わせる。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 45
演習3-補足
前後の要素比較
–通常のリストと、1つ要素をずらしたリストを用意することで、前後の要素が比較可能となる。
1 2 3 4 5
2 3 4 5
zip 1,2 2,3 3,4 4,5
1
Stream#skip(1)
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 46
インターフェース拡張
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 47
インターフェース拡張
仕様
– JEP126 Lambda Expressions & Virtual Extension Methods
できるようになったこと
– インターフェースに、staticメソッドが定義可能になった。
– インターフェースに、実装が持てるようになった。(デフォルトメソッド)
部分的な多重継承の実現
影響
– Java8では、ラムダ式やStream APIが注目されているが、デフォルトメソッドの方がクラス設計に与える影響は大きい。
–デザインパターン、フレームワークも再考されるのでは。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 48
インターフェース static メソッド
概要
– インターフェースにstaticメソッドを書く事ができる。(そのまんま)
– 呼び出す場合は、 インタフェース.メソッド名 で良い。
– staticメソッドがあるインターフェースを継承したインターフェースや実装したクラス名で、インターフェースのstaticメソッドを呼ぶ事は当然できない。
– mainメソッドも書けるし、実行できるよ!(だからどうした)
例
使いどころ
– 正直あまり思い浮かばない。ユーティリティメソッドの置き場とか?
Java APIでの使用箇所
– java.util.Comparator – ラムダ式を使ったComparator作成など色々増えた。
コンパレータの生成が簡単にできるものがある。
public interface TestIF {static void print(){System.out.println("test");}static void main(String[] args){TestIF.print();}//testと表示
}
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 49
デフォルトメソッド
概要
– インターフェースに内容有りのメソッドを定義可能。(default キーワード使用)
– 実装したクラスは、デフォルトメソッドを実装しなくてもよい。(オーバーライド可能)
– インターフェースなので複数実装可能。限定的な多重継承の実現。
メソッドが被ったら? →コンパイルエラー。オーバーライドして解決する。
– 抽象クラスとは異なる点は以下の2つ。
1. 抽象クラスは継承できるのは1つ。インターフェースは複数実装可能。
2. 抽象クラスはフィールドを持てる。インターフェースは持てない。(thisを上手く使おう)
なぜ導入されたか?
– ラムダ式、Stream APIの導入で、List等既存のAPIに相当数のメソッド追加があり、実装クラスのメソッド追加が半端なかったため。デフォルトメソッドでインターフェースにメソッドを追加しても、実装クラスのソースを修正する必要がない。
使いどころ
– 色々ありそう。ログ出力とか。
– AOPとかDIとか、今までリフレクション、アノテーション、設定ファイル、黒魔術な手段で解消してきた事が簡単になりそうな気配はある。
– が、これだ!というのは思いつかないですね。実例が揃うのを待ちたい。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 50
デフォルトメソッド – 使用例1
単純な例
interface ConsoleLogger {default void log(String msg) {
System.out.println("message = " + msg);}
}public class DefaultTest implements ConsoleLogger {
// ConsoleLoggerのlogメソッドは上書き不要public void test() {
log("user");}
public static void main(String[] args) {new DefaultTest().test();// message = user
} }
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 51
デフォルトメソッド – 使用例2
デフォルトメソッドが重複する例
interface Bar {default void print(){System.out.println("Bar");}default void p(){System.out.println("p");}
}
interface Foo {default void print(){System.out.println("Foo");}
}// printが衝突public class DefaultTest2 implements Bar,Foo {
@Override public void print() {// インターフェース.super.メソッドで参照可能Bar.super.print();
}}
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 52
デフォルトメソッド – 使用例3-1(紹介のみ)
実践的な例
– 参考 : http://yojik.hatenablog.jp/entry/2013/11/02/172132
– 実装するインターフェースを変えるだけで、エラーログの出力をコンソール/ファイルに切り替える。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 53
デフォルトメソッド – 使用例3-2
(続き) 具象クラスの継承するときにデフォルトメソッド有りのインターフェースを選択する。具象クラスの実装は不要。– 欲を言うと、匿名クラス作成時にインターフェースも指定できると、具象クラスの宣言も不要でいいんだけど、、、例) Process p = new Process implemets InfoConsoleLog, ErrorConsoleLog(){};
実装はこちら: – https://gist.github.com/kencharos/1518df9e660e2873b5fb
// エラーログをコンソールに出す場合。class ProcessImpl extends Process
implements InfoConsoleLog, ErrorConsoleLog{}// こう定義するとエラーログはファイルに出る。class ProcessImpl extends Process
implements InfoConsoleLog, ErrorFileLog{}
public class DefaultExample {public static void main(String[] args) {
Process p = new ProcessImple();p.go();
}}
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 54
Optional
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 55
Optional
Optional型って?
–失敗するかもしれない計算(nullを返すかもしれないメソッド)の結果を表す。
– nullを扱えないHaskellで nullのような概念を表す型、Maybe a(Nothing | Just a) から由来。
– Stream APIのmaxなど、Streamの一部のメソッドはOptionalを返す。(要素が0個のStreamから最大値なんて探せないから)
利点
– メソッドの戻り値が例えば、Stringだと、そのメソッドがnullを返すかどうかは、メソッド宣言からだけでは一切解らない。
– もし戻り値が、 Optional <String> なら、 メソッドはStringの結果を返すかもしれないが、返さないかもしれないということが読み取れる。また、同時にOptionalから結果があるかを判定するコードを書かざるを得ないので、NullPointerExceptionの発生を抑制する。
– というわけで、nullを返すようなメソッドを作るときには、代わりにOptionalを使う事を検討しても良いかもしれません。
DAOのfindByPkとか。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 56
サンプル
Optional型のオブジェクトから、計算結果を取得する各種サンプル。他にも色々なメソッドがあるので、javadocを参照。
// Optionalを返すメソッドを実行Optional<String> res = someMethod();// isPresentは結果があるか判定。getは値がある場合のみ成功する。if(res.isPresent()) {
System.out.println(res.get());}
// 値がある場合のみラムダ式を実行する。(上と同じ動作をする)res.ifPresent(r -> System.out.println(r));
// 値があれば取得し、なければ引数の値を使う。String s = res.orElse("nothing");
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 57
演習4(25分)
デフォルトメソッドを使って、Mapにキーから取得した値をOptionalでラップした値を返す機能を追加します。
パッケージ : practice4
– OptionalMap(Mapを継承)
インターフェース。デフォルトメソッドgetByOptの中身を記述してください。
– キーに紐づく値が無い場合空のOptional、そうでない場合値をOptionalに包んで返す。
– OptionalHashMap
HashMapを継承し、OptionalMapを実装します。
継承クラスをHashMapからLinkedHashMapに変更する事も容易だということが解ると思います。
– Test
OptionalHashMapを使用したテストです。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 58
OptionalにもあるflatMap
Optionalには、Stream同様、 map, flatMapメソッドがあり、Optionalの中の結果に対して、演算が適用できる。
– さらに、Optionalに結果がない場合は何もしないという性質がある。
– この性質を生かすと、flatMapでは段階的な取得のような処理が簡単に書ける。
例) Mapから取得した値をキーとしてMapから再度値を取得を3回行う。
– flatMapは”モナド”と言う計算パターンの一種。
//mapからの取得値をOptionalに包むprivate static <T> Optional<T> get(Map<T,T> map, T key) {
return Optional.ofNullable(map.get(key));}
// “A”を起点にmapから3度段階的に取得を行う。// どの時点でmapから取得できなくなっても、エラーにならない。get(map, "A")
.flatMap(k -> get(map, k)) //kはmapから”A”で取得した値。
.flatMap(k -> get(map, k))
.ifPresent(System.out::println);//値があれば表示。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 59
その他トピック
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 60
新日付API(java.time) -example.TimeTest
java.timeパッケージ(JEP150 Date&Time API)の主なクラスは以下の通り。
– 日付・時間を表す - LocalDate(日付), LocalTime(時間), LocalDateTime/ZonedDataTime(日時)
– 時間の量を表す - Duration(時間の量), Period(日付の量)
– 日付・時間の計算メソッドに上記の量を渡して計算を行う。
Date,Calendarよりも簡単・高機能。あとスレッドセーフ。
– 1つの日時オブジェクトで時間の表現、時間計算、文字列変換ができる。(Data/Calendar間の変換不要)
– 日時オブジェクトを様々な方法で作成できる。
– 月が1オリジン(1が1月)である。(Calendarは0が1月)
– 和暦のようなロケールに応じた年代を表示できる。
– 日時オブジェクトは不変。計算結果は別オブジェクトになる。
Date/Calendarの置き換えを狙っているため、Date/Calendarとの変換メソッドは提供されない。
– 新APIを使うのなら、Date/Calendarを一切使うなという意思表示。保守案件には無用の代物かもしれない。
その割には、JDBCでは新APIにまた対応していない。– 普及には時間がかかりそう。
LocalDateTime may = LocalDateTime.of(2014, 5, 8, 13, 0, 0);
LocalDateTime calcDate = may.minusMonths(1).plus(Period.ofYears(2));
System.out.println(calcDate.format(DateTimeFormatter.ofPattern("yyyy/MM/dd hh:mm:ss")));
Chronology jp = Chronology.of("Japanese");
ChronoLocalDate wareki = jp.date(may);
System.out.printf(
"%d年は%s %d年\n",wareki.get(ChronoField.YEAR), wareki.getEra(), wareki.get(ChronoField.YEAR_OF_ERA));
使用例 年,月,日,時間,分,秒を指定して日時を生成
日付の計算は新しい日時を生成する
2014年はHeisei 26年 と出力和暦の出力例
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 61
JVMまわり
Java8には、JVMや周辺ツールの変更もある。
例えば
– Sun JVM(Hotspot)と Oracle JVM(jRockit)の統合
–パーマネント領域の廃止(-XX:PermSizeオプションが無効)
JVMオプションが色々と変更
– Javascirptエンジンの変更 (Rhino → Nashorn)
– APTの廃止
– Javadocツールの強化(コメントチェック、構文木生成)
Java8へのアップデート案件では、プログラムの稼動確認だけでなく、JVMの起動パラメータやパフォーマンスなんかも確認しておきましょう。
他にも
– javacコマンド のバージョン指定(-source, -target)は3世代前までのみをサポートするようになります。
–現在のJDK8でもjava1.5以前向けのコンパイルは可能ですが、将来削除されるという警告が発生します。
ULSCopyright © 2011-2014 UL Systems, Inc. All rights reserved.
Proprietary & Confidential Powered by 62
まとめ
Java8は、Java5のジェネリクス追加に匹敵するアップデート
インターフェース実装、ラムダ式、Stream API 全て役に立ちます。
–使いこなせる必要は無いですが、これらの要素はAPIのいたる所に出てくるので、概要や使い方くらいは知っておくべき。
–詳しく知るならJavadocを読むか、enterprisegeeksで。
是非、「何だかわからないからラムダ禁止」みたいな風潮と戦いましょう。
Java8採用にむけて訴求できそうなポイント
– Stream APIで並列処理による高速化が容易になる。
– Stream APIを使って、省コードかつバグリにくく保守性が高いプログラムが作れる
– Java7 のEOLは2015年4月