Eclipse Oxygen.1a (4.7.1a) でJava9+JUnit5を試したよ
導入
このツィートを見たので早速試してみた。
最近のeclipseはトップページからだとインストーラをダウンロードさせようとするが、以下ツィートのリンク先は昔からのユーザーにはおなじみの選択制zipなので嬉しい。
New Release - #Eclipse Oxygen.1a is now available with #Java9 and #JUnit5 https://t.co/Idn5S408Md pic.twitter.com/cdO1SGlvAA
— Java (@java) 2017年10月11日
JUnit5のチュートリアルはこれを見ながらやる。
でも、全編英語なので(当たり前)これも見ながらの方がいいかもしれない。
当たり前だけど、特にはまるポイントもなく環境は作れた。
JUnit 5 User Guide の注意点
- mavenで何を書けばいいかが初見だとわかりにくいので、"2.3. JUnit Jupiter Sample Projects"内にリンクされている、githubのサンプルからコピペした方が楽かも。
- あるいは、前述したきしださんのブログに書かれているpom.xmlをコピーするか。
- 基本は書かれているコード例をコピペで試せるが、"3.4. Assertions"だけコンパイルエラーが出る。該当メソッドはコメントアウトが無難。
- 5章のコードをコピペしてね、とか、github上のサンプルコードを持ってきてね(意訳)というサンプルがちらほらあるので柔軟に対応しよう。
- MockItoが唐突に出てくるが、導入の方法は書かれていないので以前に書いたpom.xmlが無ければググる必要がある。(ベータ版を使う?)
JUnit5を試した感想
- JUnit4で動いているテストは今すぐ書き換えなくていいかな。
- 新規で作るプロジェクトはJUnit5で書くのを視野に入れてもいいかも。
- Parameterized Testsは便利そう。
JavaOne2017に日本から参加した方々のブログ記事まとめ
個人的なメモです。
gihyo.jp に掲載されているレポート
http://gihyo.jp/news/report/01/JavaOne2017
Publickey(@Publickey)
http://www.publickey1.jp/blog/17/javaone_2017_keynote.html http://www.publickey1.jp/blog/17/javaproject_amberjavaone_2017.html
Takaaki Sugiyama さん(@zinbe)
http://nebuta.hatenablog.jp/entry/2017/10/02/161954 http://nebuta.hatenablog.jp/entry/2017/10/04/233841 http://nebuta.hatenablog.jp/entry/2017/10/07/205217
きしださん(@kis)
http://d.hatena.ne.jp/nowokay/20171002#1507028477 http://d.hatena.ne.jp/nowokay/20171003#1507163551 http://d.hatena.ne.jp/nowokay/20171004#1507329281 http://d.hatena.ne.jp/nowokay/20171005#1507599558
新・小僧さん(@toastkidjp)
https://reminiscencesoftoastkid.tumblr.com/post/165957550938/javaone-2017-day-1-flash-report https://reminiscencesoftoastkid.tumblr.com/post/165993641483/javaone-2017-day2-flash-report https://reminiscencesoftoastkid.tumblr.com/post/166028869458/javaone-2017-day3-flash-report https://reminiscencesoftoastkid.tumblr.com/post/166063657828/javaone-day4-flash-report https://reminiscencesoftoastkid.tumblr.com/post/166097265923/javaone-day-5-flash-report
よこなさん(@ihcomega)
http://ihcomega.hatenadiary.com/entry/2017/10/02/182157 http://ihcomega.hatenadiary.com/entry/2017/10/06/082500
まーやさん(@maaya8585)
https://hotchpotchj37.wordpress.com/2017/10/02/javaone-2017-1%E6%97%A5%E7%9B%AE%E3%83%8F%E3%82%A4%E3%83%A9%E3%82%A4%E3%83%88/ https://hotchpotchj37.wordpress.com/2017/10/03/javaone-2017-2%E6%97%A5%E7%9B%AE-%E3%83%8F%E3%82%A4%E3%83%A9%E3%82%A4%E3%83%88/
Java9のモジュール化について考えてみた #java9
これは何か
モジュール化のメリットがよくわからなかったので、実際に手を動かしながら考えてみた。
seasar2時代から発展していない時代遅れの脳だと、以下の構成がしっくり来た。
モジュールの分け方
actionModule、formModule、serviceModuleの3つに分けてみる。
- actionModuleはformModuleとserviceModuleを参照できる。
- formModuleはactionModuleからしか参照できない。
- serviceModuleはactionModuleから参照できない。
これで、xxxFormをうっかり(わざと?)serviceModule内で参照することを防ぐことができる。
または、formModuleでの入力チェックを行うために、serviceModuleを呼び出してしまうという事故も防げる。
お互いのモジュールの役割分担が出来るので、役割が分かりやすくなるかもしれない。
クラスパスの制御でもそれ出来るんじゃん?
今までは確かにクラスパスに追加する/しないでコントロールできたが、モジュール作成者の意図に沿ったものとは限らなかった。
今回、module-info.javaに依存関係を明記できるようになったことで、モジュール作成者の意図が伝えやすくなる。
思考をまとめてた時のソース
aaaActionModule
- Action.java
package action.project; import form.project.Form; import service.project.Bean; import service.project.Service; public class Action { public static void main(String... args) { Form form = new Form(); form.setName("aaa"); Bean bean = new Bean(); bean.setName(form.getName()); Service service = new Service(); service.execute(bean); } }
- module-info.java
module aaaActionModule { requires aaaFormModule; requires aaaServiceModule; }
aaaFormModule
- Form.java
package form.project; public class Form { public String getName() { return name; } public void setName(String name) { this.name = name; } private String name; }
- module-info.java
module aaaFormModule { exports form.project to aaaActionModule; }
aaaServiceModule
- Bean.java
package service.project; public class Bean { public String getName() { return name; } public void setName(String name) { this.name = name; } private String name; }
- module-info.java
module aaaServiceModule { exports service.project to aaaActionModule; }
参考にしたサイト
java.util.ObjectsクラスにcheckIndex()なるメソッドが増えてた話 #java9
序章
Java1.8とJava9のArrayListのソースを比較していたところ、set(int index, E element)/get(int)メソッドの中身が変わっていることに気づきました。
setメソッド
- Java1.8
public E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
- Java9
public E set(int index, E element) { Objects.checkIndex(index, size); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
getメソッド
- Java1.8
public E get(int index) { rangeCheck(index); return elementData(index); }
- Java9
public E get(int index) { Objects.checkIndex(index, size); return elementData(index); }
Objectsクラスを見てみる
ObjectsクラスにcheckIndex()なるメソッドが追加されたようです。中身を見てみます。
/** * Checks if the {@code index} is within the bounds of the range from * {@code 0} (inclusive) to {@code length} (exclusive). * * <p>The {@code index} is defined to be out-of-bounds if any of the * following inequalities is true: * <ul> * <li>{@code index < 0}</li> * <li>{@code index >= length}</li> * <li>{@code length < 0}, which is implied from the former inequalities</li> * </ul> * * @param index the index * @param length the upper-bound (exclusive) of the range * @return {@code index} if it is within bounds of the range * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds * @since 9 */ @ForceInline public static int checkIndex(int index, int length) { return Preconditions.checkIndex(index, length, null); }
Preconditionsなる慣れないクラスが出てきました。
どうやら、Java9で新たに追加されたクラスの様で、パッケージは jdk.internal.util です。
なんとなく、一般開発者はあまり直で触らない方がよさそうな雰囲気のパッケージ名です。深入りせずに、戻ることにします。
Objectsクラスに戻ってみると、checkIndex()メソッド以外にcheckFromToIndex()や、checkFromIndexSize()というメソッドも追加されています。
/** * Checks if the sub-range from {@code fromIndex} (inclusive) to * {@code toIndex} (exclusive) is within the bounds of range from {@code 0} * (inclusive) to {@code length} (exclusive). * * <p>The sub-range is defined to be out-of-bounds if any of the following * inequalities is true: * <ul> * <li>{@code fromIndex < 0}</li> * <li>{@code fromIndex > toIndex}</li> * <li>{@code toIndex > length}</li> * <li>{@code length < 0}, which is implied from the former inequalities</li> * </ul> * * @param fromIndex the lower-bound (inclusive) of the sub-range * @param toIndex the upper-bound (exclusive) of the sub-range * @param length the upper-bound (exclusive) the range * @return {@code fromIndex} if the sub-range within bounds of the range * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds * @since 9 */ public static int checkFromToIndex(int fromIndex, int toIndex, int length) { return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null); } /** * Checks if the sub-range from {@code fromIndex} (inclusive) to * {@code fromIndex + size} (exclusive) is within the bounds of range from * {@code 0} (inclusive) to {@code length} (exclusive). * * <p>The sub-range is defined to be out-of-bounds if any of the following * inequalities is true: * <ul> * <li>{@code fromIndex < 0}</li> * <li>{@code size < 0}</li> * <li>{@code fromIndex + size > length}, taking into account integer overflow</li> * <li>{@code length < 0}, which is implied from the former inequalities</li> * </ul> * * @param fromIndex the lower-bound (inclusive) of the sub-interval * @param size the size of the sub-range * @param length the upper-bound (exclusive) of the range * @return {@code fromIndex} if the sub-range within bounds of the range * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds * @since 9 */ public static int checkFromIndexSize(int fromIndex, int size, int length) { return Preconditions.checkFromIndexSize(fromIndex, size, length, null); }
新たなメソッドを使ってみる
とりあえず、使ってみることにします。
import java.util.Objects; public class CheckSize { public static void main(String... args) { checkIndex(); checkFromToIndex(); checkFromIndexSize(); } private static void checkIndex() { int a = Objects.checkIndex(2, 8); System.out.println("checkIndex:" + a); } private static void checkFromToIndex() { int a = Objects.checkFromToIndex(2, 8, 10); System.out.println("checkFromToIndex:" + a); } private static void checkFromIndexSize() { int a = Objects.checkFromIndexSize(2, 8, 10); System.out.println("checkFromIndexSize:" + a); } }
実行結果はこうなりました。
checkIndex:2 checkFromToIndex:2 checkFromIndexSize:2
JavaDocにも書かれているように、引数に問題が無ければ一番目の引数をそのまま返すようです。 では、不正な値を渡したらどうなるのでしょう?
private static void checkIndex() { int a = Objects.checkIndex(8, 2); System.out.println("checkIndex:" + a); }
こんなエラーを吐きました。
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 8 out-of-bounds for length 2 at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70) at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248) at java.base/java.util.Objects.checkIndex(Objects.java:372) at test.CheckSize.checkIndex(CheckSize.java:16) at test.CheckSize.main(CheckSize.java:9)
他のメソッドだと以下の通りです。
- checkFromToIndex()メソッドとそのエラー内容
private static void checkFromToIndex() { int a = Objects.checkFromToIndex(8, 1, 10); System.out.println("checkFromToIndex:" + a); }
Exception in thread "main" java.lang.IndexOutOfBoundsException: Range [8, 1) out-of-bounds for length 10 at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckFromToIndex(Preconditions.java:76) at java.base/jdk.internal.util.Preconditions.checkFromToIndex(Preconditions.java:295) at java.base/java.util.Objects.checkFromToIndex(Objects.java:398) at test.CheckSize.checkFromToIndex(CheckSize.java:22) at test.CheckSize.main(CheckSize.java:10)
- checkFromIndexSize()メソッドとそのエラー内容
private static void checkFromIndexSize() { int a = Objects.checkFromIndexSize(2, 1, 1); System.out.println("checkFromIndexSize:" + a); }
Exception in thread "main" java.lang.IndexOutOfBoundsException: Range [2, 2 + 1) out-of-bounds for length 1 at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckFromIndexSize(Preconditions.java:82) at java.base/jdk.internal.util.Preconditions.checkFromIndexSize(Preconditions.java:343) at java.base/java.util.Objects.checkFromIndexSize(Objects.java:424) at test.CheckSize.checkFromIndexSize(CheckSize.java:29) at test.CheckSize.main(CheckSize.java:11)
まとめ
通常のロジックで使うにはちょっとエラーメッセージが不親切、という印象です。自分で丁寧に判定ロジックを書いて、状況に合わせてわかりやすいメッセージを作った方がいいかもしれません。
そもそも、使い道がほとんどなさそうです。フレームワーク側で使うかも?くらいでしょうか。何かこんなパターンの時使えるのでは、という閃きがありましたら、教えてください。
10/5追記
Objects.checkIndexメソッドはArrayList.java以外にどこから呼ばれてるのかなとソースコードをgrep検索したところ、java.util.ImmutableCollections.javaとjava.util.AbstractList.java からも呼ばれていました。とはいえ、この二つは開発者は意識しないと思うクラスなので本当に「へー」程度ですね。
#Java9 #String 文字列結合のパフォーマンス向上について
2017年9月にリリースされたJava絡みの公式チュートリアルまとめ
これは何の記事?
いつかやってみるかもしれないチュートリアルをまとめておく。
一覧
JUnit 5 User Guide
- 2017/9/10リリース。
- PDFへのリンクあり
Java Shell User’s Guide
- 2017/9/21リリース
Java Platform, Standard Edition Java Shell User’s Guide - Contents
Project Jigsaw: Quick Start Guide
- 2017/9/21リリース
Project Jigsaw: Quick Start Guide
Java EE Tutorial
- 2017/9/21リリース。
半角英字の結合をしたらJava8より遅くなった件の調査【原因不明】 #Java9 #String
これの続編です。 結論から言うと謎が深まっただけです。 tadashi.hatenablog.com
LATIN1/UTF16 の判定が追加になっている、と書いてあるので、判定用の値を取得する coder()メソッドの結果を見てみることにしました。 d.hatena.ne.jp
ソースはこちらです。
※リフレクションを使っています。
https://github.com/suzukitadashi/jmhTest/blob/master/jmhTest/src/main/java/jmhTest/StringTest.java
package jmhTest; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class StringTest { private static String[] list = {"a","b","c","d","e","f","g","h","i", "j"}; public static void main(String... args) { // String[] val = {"", "a", "1", "あ"}; // for(String str : val) { // checkCoder(str); // } test1StringLine(); } private static void checkCoder(String str) { System.out.println("------"); Class<String> c = String.class; try { Method m = c.getDeclaredMethod("coder"); m.setAccessible(true); byte b = (byte)m.invoke(str); System.out.println(str + " coder(): "+b); Field f = c.getDeclaredField("coder"); f.setAccessible(true); byte b1 = f.getByte(str); System.out.println(str + " coder: "+b1); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } public static void test1StringLine() { int i = 0; String str0 = list[i]; checkCoder(str0); i++; String str1 = list[i]; checkCoder(str1); i++; String str2 = list[i]; checkCoder(str2); i++; String str3 = list[i]; checkCoder(str3); i++; String str4 = list[i]; checkCoder(str4); i++; String str5 = list[i]; checkCoder(str5); i++; String str6 = list[i]; checkCoder(str6); i++; String str7 = list[i]; checkCoder(str7); i++; String str8 = list[i]; checkCoder(str8); i++; String str9 = list[i]; checkCoder(str9); String str = str0 + str1 + str2 + str3 + str4 + str5 + str6 + str7 + str8 + str9; checkCoder(str); } }
遅くなる理由は、LATIN1で判定して違う、ということでUTF-16の処理になるために処理時間が遅延しているのでは、と推測しました。
さて、結果はというと…
------ a coder(): 0 a coder: 0 ------ b coder(): 0 b coder: 0 ------ c coder(): 0 c coder: 0 ------ d coder(): 0 d coder: 0 ------ e coder(): 0 e coder: 0 ------ f coder(): 0 f coder: 0 ------ g coder(): 0 g coder: 0 ------ h coder(): 0 h coder: 0 ------ i coder(): 0 i coder: 0 ------ j coder(): 0 j coder: 0 ------ abcdefghij coder(): 0 abcdefghij coder: 0
coderの値が0ならLATIN1、1ならUTF-16と判定されるロジックなのですが、LATIN1と判定されているようです。
うーん、なんで半角数字同様のパフォーマンスが出てくれないのだろう…?