JVM Language Summitに行く-Day0 移動日

JVM Language Summitという、JVM言語の開発者が集まるイベントがSanta ClaraのOracle Campusであるのですけど、毎年おもしろそうな発表ばっかりで、一度行きたいと思っていたので行くことにしました。
ただ、時期が時期だけにSanJose空港行きの飛行機がちょう高かったので(もしかしたら福岡-成田が高いのかも)、台湾経由でサンフランシスコ空港に行くことにしました。


朝10時くらいに、ちょっとヨドバシでカードリーダー付USB-Cハブを買って、11時くらいに福岡空港に。


台湾時間13時に桃園空港についた。
トランジットに7時間あるので、台北駅まで出ました。MRT便利。


目的は、この変な人形の写真を撮ること。もちろんVRも撮ってます。



ところで、ガチャガチャコーナーがあって、NO MORE盗撮があったのですが、台湾の人にわかるんでしょうか?


台湾時間20時に飛行機に。
で、サンフランシスコ行こうとすると、一旦日本に戻ってくるわけですね。


そしてサンフランシスコ空港に西海岸時間17時ごろ到着


18:30くらいのBARTにのってMillbraeまで。


Millbraeで19:20くらいのCaltrainに乗り換え。


Caltrainでは、どっかの駅についたときに、サラサラ金髪の少年がなんか楽しそうに走ってきて、癇癪玉のようなものを外に投げて戻っていきました。楽しそう。


そしてようやく20:15くらいにSanta Claraにつきました。


そこからはUberで、AirBnBで予約したおうちまで。20:45くらいにつきました。
ちなみに移動手段はAirBnBのホストの人が全部調べていてくれました。ありがたや。


日本時間だと30日13時なので、27時間くらいかかってますね。
つかれた。

VR180カメラでVRを撮るのにハマりまくっている。みんなも買おう

先日Oculus Goを買って、360channelで鈴木咲がネクタイ締めてくれる3D動画を見たりして、VRおもしれーとハマっていました。
で、そういうの撮れるデバイスあるかなーと思ったら、VR180という規格をGoogleが作っていて、それに対応したカメラをLenovoやシャオミが出してることがわかり、これは可及的速やかに購入して身の回りを記録するべきだと早速購入。
買ったのはLenovoMirage Cameraです。

そしたらすげー面白かった。登壇のたびに撮影してます。登壇気分が味わえて楽しい。


ちなみに、360channelの動画はこれ。
”はだける浴衣”でイチャイチャ新婚生活♡ 鈴木咲 ファンが見たいVR | 360Channel | VR動画配信サービス
Oculus Goで3Dで見るには専用アプリで見る必要があります。
https://www.oculus.com/experiences/go/1068604633204352/
ここには360版だけのコンテンツと3Dもあるものがあるんですが、平面が360度あるより、180度立体があるほうが断然よいです。立体じゃない360コンテンツだとがっかり感ある。360だと、鈴木咲が近づいてきても、ただデカくなるだけで近づいてきた感じじゃないんですよね。3Dだと「ちょ、近づきすぎ」ってなる。
で、これ書きながら見てたら、Webの360版だと浴衣ぬぐのね。ぜんぜんはだけてないなーと思ったら、そういうことだったか。
ちなみに、鈴木咲は、だいぶ前にオリエント工業の人形として有名になった人ですね。
鈴木咲さんのツイート: "よくね、オリエント工業製のリアルな..."


いや、これは鈴木咲 紹介エントリではない。


まあそんな感じで、360よりも180で立体に撮れるほうが重要だと思って、そしてできるだけ早く3Dで記録を始めたいと思って、すぐにヨドバシで買ったのです。
で、何を撮るかというと、身の回りのいろいろを撮るのが楽しいです。コンビニの雑誌の棚とか近所の交差点とか。散らかった部屋を撮ってOculus Goで見ると、散らかった部屋が立体に見えて楽しいです。


大きい建物は結構いいです。博多駅を見上げたり。


それと、吹き抜けおすすめ。これは羽田第一ターミナルの吹き抜けです。手を出して撮ると、足元に床がないので恐怖体験できます。


あと、写真撮影OKな美術館。国立西洋美術館で考える人VRを撮ってきました。


地獄の門はかなりいいです。もちろん横を向けば立像が見えます。


絵画も、サイズ感が体験できてすごくいいです。

ただ、解像度の問題で細部はぜんぜん見れないけど。シニャックの点描なんかは、完全に点がつぶれて普通の絵になっちゃってます。それでも存在感は なかなかいいです。


面白いのが、上野公園からスカイツリーが見えるのを写真で撮ると、見えてる大きさに比べて小さくしか映らないのだけど、これがVRで見るとそれなりに大きく見えます。


一番のヒットは名刺交換VRです。名前のとおり、名刺交換するところをVR動画で撮ったのですが、これは見るとフフッってなります。

他にもビールを注いでもらうVRも撮ったのですが、なにかしてもらうVRは とてもいいです。コンビニレジVRとか撮りたいですが、これはなかなか難しい。
あ、でも、普通に名刺交換の作法指導なんかに いい気がしますね。


福岡オフィスを撮って東京オフィスの人に見せたりもしたのですが、オフィス紹介VRとかもよさそう。

不動産やさんとかは物件紹介VRやればいいと思うな。


ただ、これ撮ってもOculus Go持ち歩くわけにもいかないし、なかなかその場で人に見せれないなーと思ったら、いいものがあった。

結構ちゃんとVRに見れるので、これでその場で人に見せることができます。
Oculus Goで見るには一度PCにデータ移してからOculus Goにファイル転送する必要もあって面倒だし。
関係ないけど、このAmazonレビュー、ほとんどが違う製品のレビューで、レビューをクリックすると別製品が出てくるんだけど、どういうことなんだろう?まあいいや。


180度レンズが筐体の端にあるので、普通に手で持つと高い確率で手が映り込みます。自撮り棒あるほうが楽です。はさむやつより、ネジのほうがいいです。


それと、1度壊れて電源入らなくなって修理待てないので買いなおしたのだけど、そうするとデータも取り出せなくなるので、MicroSDカード入れておくのがいいです。

買いなおしたのは、修理には10営業日かかると言われたので、確実に8月になってしまって、それまでの面白イベントが撮れないわけで。実際、この数日でもいろいろ撮れたので買いなおしてよかった。修理あがってきたら誰かに売りつけようかと。


あ、撮るときの注意としては、食べ物とか机の上に置いてあるものとか撮るときに下に傾けて撮るとVRで見るときに酔ってしまうので、あくまでカメラは垂直に。見るときに下を向こう。
それと、手の分 前に出てしまうので、あまり近づきすぎないように気を付けること。特に食べ物を撮るときに近づきすぎると焦点が合わないので、ちょっと目の高さよりカメラを下げるくらいがいいと思います。実際にそこに目を置いてちゃんと見えるか、という感じですね。
あと、手がかぶらないように。あ、視界の範囲の人は だいたい映るので、広く共有したいものを撮りたかったら、完全に視界から人がいなくなってから撮るのがいいです。それでもあとでVRで横を見たらおっさんがちょうこっち見てるとかあります。
それと、炎天下で動画とってると熱ですぐ止まってしまいます。注意。


ということで、みんなVR撮りまくると楽しいと思うよ。特に子どもとかイヌとかネコとか。
今のところ簡単に共有する方法がなくて、ファイルを直接やりとりするしかないのだけど、FacebookGoogleがなんとかしてくれるでしょう。

ロケールを指定してJShellを起動

-J-Duser.language=enをつける

C:\Users\naoki>java\jdk-10.0.1\bin\jshell -J-Duser.language=en
|  Welcome to JShell -- Version 10.0.1
|  For an introduction type: /help intro

2021/7/17 追記
上記はJShell自体のロケールの指定なので、実行するコードのロケールを指定するときには-Rで始める。

C:\Users\naoki>jshell -R-Duser.language=en
|  JShellへようこそ -- バージョン17-ea
|  概要については、次を入力してください: /help intro

jshell> "%tA".formatted(java.time.LocalDate.now())
$1 ==> "Sunday"

-Jだと実行コードのロケールはOS設定のまま

C:\Users\naoki>jshell -J-Duser.language=en
|  Welcome to JShell -- Version 17-ea
|  For an introduction type: /help intro

jshell> "%tA".formatted(java.time.LocalDate.now())
$1 ==> "日曜日"

Java11 API Changes

JDK11 features are frozen since it was in the Rampdown phase last month.


Big changes are listed in this page as JEPs.
JDK 11


However there are many changes outside of JPEs in JDK 11, therefore I list up the API changes in JDK 11 as far as I know.

String

lines()

Get a stream divided by line breaks.

jshell> "test\nhoge\n".lines().map(String::toUpperCase).toArray()
$11 ==> Object[2] { "TEST", "HOGE" }
repeat(int)

Repeat string for the specified times.

jshell> "test".repeat(3)
$7 ==> "testtesttest"
isBlank()

The method appended that determines whether the string contains only spaces or not. Full width space is also treated as a space.

jshell> var halfSpace = "\u0020"
halfSpace ==> " "

jshell> halfSpace.isBlank()
$11 ==> true

jshell> var fullSpace = "\u3000"
fullSpace ==> " "

jshell> fullSpace.isBlank()
$13 ==> true
strip() / stripLeading() / stripTrailing()

Almost same as trim() / trimLeft() / trimRight() but it takes full width spaces as a spece.

jshell> var aaa = fullSpace + "aaa" + fullSpace
aaa ==> " aaa "

jshell> aaa.strip()
$14 ==> "aaa"

jshell> aaa.trim()
$15 ==> " aaa "

CharSequence

compare(CharSequence, CharSequence)

Sort by dictionaly order.
It is used by compateTo in CharSequence/StringBuffer/StringBuilder. Therefore the 3 classes implements Comparable.

Character

toString(int)

It was not convenient so far but now it become convenient.
JDK10.0.1

jshell> Character.toString(65)
|  Error:
|  incompatible types: possible lossy conversion from int to char
|  Character.toString(65)
|                     ^^


JDK11ea14

jshell> Character.toString(65)
$9 ==> "A"

Path

of(String, String...)

We had to use Paths.get() so far, now we can use of() as same manner as another classes.

Files

writeString(Path, CharSequence)

We can save a string with 1 method.

jshell> Files.writeString(Path.of("test.txt"), "Hello!!!")
$3 ==> test.txt
readString(Path)

We can read a string with 1 method.

jshell> Files.readString(Path.of("test.txt"))
$4 ==> "Hello!!!"

Reader

nullReader()

We can get a Reader that do nothing.

Writer

nullWriter()

We can get a Writer that do nothing.

Predicate

not(Predicate)

We could not use a method reference where it needs to invert the condition, now we can use a method reference.

jshell> Stream.of("aa", "", "bb").filter(Predicate.not(String::isEmpty)).toArray()
$23 ==> Object[2] { "aa", "bb" }

Collection

toArray(IntFunction)

We had to use a non stylish notation like list.toArray(new String[list.size())]) on creating an typed array from a collection, now we can write in a stylish notation.

jshell> List.of("aa","bb").toArray(String[]::new)
$1 ==> String[2] { "aa", "bb" }

Optional/OptionalInt/OptionalLong/OptionalDouble

isEmpty()

isPresent() had existed so far, now we have isEmpty().

jshell> Optional.ofNullable(null).isEmpty()
$5 ==> true

TimeUnit

convert(Duration)

added for java.util.concurrent.TimeUnit

Pattern

asMatchPredicate()

There was asPredicate that do find, now we have asMatchPredicate that do match.

jshell> var pred = Pattern.compile("aaa").asPredicate()
pred ==> java.util.regex.Pattern$$Lambda$25/0x00000008000b5040@2f686d1f

jshell> pred.test("aaa")
$6 ==> true

jshell> pred.test("aaab")
$7 ==> true

jshell> var matPred = Pattern.compile("aaa").asMatchPredicate()
matP ==> java.util.regex.Pattern$$Lambda$24/0x00000008000b6440@402a079c

jshell> matPred.test("aaa")
$9 ==> true

jshell> matPred.test("aaab")
$10 ==> false

ListSelectoinModel

getSelectedIndices()/getSelectedCount() are added.
Swing is changing!

Thread

destroy() / stop(Throwable)

Removed. stop() remains.

Policy

javax.security.auth.Policy is removed.

ArrayIndexOutOfBoundsException

The message become gentle for human.
JDK10.0.1

jshell> new int[]{}[0]
|  java.lang.ArrayIndexOutOfBoundsException thrown: 0
|        at (#8:1)


JDK11-ea14

jshell> new int[]{}[0]
|  Exception java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
|        at (#4:1)

IndexOutOfBoundsException

hyphens are removed in the message.
JDK10.0.1

jshell> List.of().get(0)
|  java.lang.IndexOutOfBoundsException thrown: Index 0 out-of-bounds for length 0
|        at Preconditions.outOfBounds (Preconditions.java:64)
|        at Preconditions.outOfBoundsCheckIndex (Preconditions.java:70)
|        at Preconditions.checkIndex (Preconditions.java:248)
|        at Objects.checkIndex (Objects.java:372)
|        at ImmutableCollections$List0.get (ImmutableCollections.java:106)
|        at (#6:1)


JDK11-ea14

jshell> List.of().get(0)
|  Exception java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
|        at ImmutableCollections$ListN.get (ImmutableCollections.java:411)
|        at (#3:1)

System

arraycopy

The message become gentle for human.
JDK10

jshell> System.arraycopy(new int[0],0,new double[0],0,0)
|  java.lang.ArrayStoreException thrown


JDK11ea19

jshell> System.arraycopy(new int[0], 0, new double[0], 0, 0)
|  Exception java.lang.ArrayStoreException: arraycopy: type mismatch: can not copy int[] into double[]
setProperty(String, String)

So far changing java.home would make trouble but now it is not affect for the system, maybe...

Base64

Since ea20, the encoding become faster by using AVX512, but I can not confirm on Windows.

Boolean

parseBoolean

It become lettle faster to remove redundant null check, they said.
JDK10

    public static boolean parseBoolean(String s) {
        return ((s != null) && s.equalsIgnoreCase("true"));
    }


JDK11

    public static boolean parseBoolean(String s) {
        return "true".equalsIgnoreCase(s);
    }

I haven't confirmed it yet.

List

copyOf

copyOf that has introduced since Java10, it was wrong copying a subList. It could not be serialized. Now fixed.
Common initialize.

jshell> var list1 = List.of("a","b","c")
list1 ==> [a, b, c]

jshell> var list2=list1.subList(1,2)
list2 ==> [b]

jshell> var list3=List.copyOf(list2)
list3 ==> [b]


JDK11ea19

jshell> list2==list3
$13 ==> true

jshell> new ObjectOutputStream(OutputStream.nullOutputStream()).writeObject(list3)
|  Exception java.io.NotSerializableException: java.util.ImmutableCollections$SubList
|        at ObjectOutputStream.writeObject0 (ObjectOutputStream.java:1185)
|        at ObjectOutputStream.writeObject (ObjectOutputStream.java:349)
|        at (#14:1)


JDK11ea20

jshell> list2==list3
$26 ==> false

jshell> new ObjectOutputStream(OutputStream.nullOutputStream()).writeObject(list3)

jshell>

TimSort

There are some bug, but fixed, maybe.
https://blog.satotaichi.info/timsort-was-broken/

Java11でのAPI変更を雑に列挙

先月末でJDK11はRampdownフェーズに入って、機能凍結されました。
なので、今後はAPIの追加・削除・変更はほとんどないと思われます。
おそらく、機能的には現在でているea20とほとんど同じものがJava11としてリリースされることになると思います。
JDK 11 Early-Access Builds


大きな機能変更としては、ここでJEPとしてまとまっています。
JDK 11」 http://openjdk.java.net/projects/jdk/11/
Raw String Literalが間に合わなかったのはとても残念です。JDK11トレインに乗り遅れるからがんばるぞ!みたいな投稿があって仕様をまとめてからML上は音沙汰なしですが、Rampdownフェーズが始まってから機能追加するLate Enhancement Request Processというのがあるようなので、ここに賭けましょう。
JEP 3: JDK Release Process


Switch ExpressionはRelease 12とターゲットが明記されていますが、Raw String Literalsは まだターゲットが明記されておらず、11に入れることを諦めたわけではないと、一縷の望みが。
JEP 325: Switch Expressions
JEP 326: Raw String Literals


ともあれ、JDK11ではJEPにあげられている以外の変更も多く入っています。そこで、いま個人的に把握している範囲でのAPI変更を列挙しておきます。

String

repeat(int)

文字列を指定した回数繰り返します。

jshell> "test".repeat(3)
$7 ==> "testtesttest"
isBlank()

空白だけかどうかを判定するメソッドが追加されました。全角スペースも空白として判定されます。

jshell> var halfSpace = "\u0020"
halfSpace ==> " "

jshell> halfSpace.isBlank()
$11 ==> true

jshell> var fullSpace = "\u3000"
fullSpace ==> " "

jshell> fullSpace.isBlank()
$13 ==> true
strip() / stripLeading() / stripTrailing()

trim() / trimLeft() / trimRight() とほぼ同じ役割なのですが、全角スペースなども空白とみなされるところが違います。

jshell> var aaa = fullSpace + "aaa" + fullSpace
aaa ==> " aaa "

jshell> aaa.strip()
$14 ==> "aaa"

jshell> aaa.trim()
$15 ==> " aaa "

CharSequence

compare(CharSequence, CharSequence)

辞書順に文字列を比較します
動作的にはStringのcompareToがa.compareTo(b)と書けていたのがCharSequenceに対応してstaticメソッドになった感じですね。どちらかがnullならぬるぽです。

Character

toString(int)

いままで微妙に不便だったのがちょっと便利になりました。
JDK10.0.1

jshell> Character.toString(65)
|  エラー:
|  不適合な型: 精度が失われる可能性があるintからcharへの変換
|  Character.toString(65)
|                     ^^


JDK11ea14

jshell> Character.toString(65)
$9 ==> "A"

Path

of(String, String...)

いままでPaths.get()を使っていたところが、ほかの作法と同様にof()で得れるようになりました。

Files

writeString(Path, CharSequence)

1メソッドで文字列保存できるようになりました。

jshell> Files.writeString(Path.of("test.txt"), "Hello!!!")
$3 ==> test.txt
readString(Path)

1メソッドで文字列読み込みできるようになりました。

jshell> Files.readString(Path.of("test.txt"))
$4 ==> "Hello!!!"

Predicate

not(Predicate)

条件を反転する必要があるためにメソッド参照が使えなかったところで、メソッド参照が使えるようになります。

jshell> Stream.of("aa", "", "bb").filter(Predicate.not(String::isEmpty)).toArray()
$23 ==> Object[2] { "aa", "bb" }

Collection

toArray(IntFunction)

いままで型をちゃんとあわせた配列をListなどから作るのにlist.toArray(new String[list.size())])みたいなかっこわるい記述が必要だったのが、ちょっとかっこよく書けるようになりました。

jshell> List.of("aa","bb").toArray(String[]::new)
$1 ==> String[2] { "aa", "bb" }

Optional

isEmpty()

いままでisPresent()はありましたが、isEmpty()も追加されました。

jshell> Optional.ofNullable(null).isEmpty()
$5 ==> true

Pattern

asMatchPredicate()

asPredicateはfindするPredicateだったのですが、matchするPredicateが用意されました。

jshell> var pred = Pattern.compile("aaa").asPredicate()
pred ==> java.util.regex.Pattern$$Lambda$25/0x00000008000b5040@2f686d1f

jshell> pred.test("aaab")
$7 ==> true

jshell> var matPred = Pattern.compile("aaa").asMatchPredicate()
matP ==> java.util.regex.Pattern$$Lambda$24/0x00000008000b6440@402a079c

jshell> matPred.test("aaab")
$9 ==> false

Thread

destroy() / stop(Throwable)

削除されました。stop()は残ってます。

ArrayIndexOutOfBoundsException

メッセージが人類に優しくなりました。
JDK10.0.1

jshell> new int[]{}[0]
|  java.lang.ArrayIndexOutOfBoundsException thrown: 0
|        at (#8:1)


JDK11-ea14

jshell> new int[]{}[0]
|  Exception java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
|        at (#4:1)

IndexOutOfBoundsException

むやみにハイフンが入ってたのが取り除かれました。
JDK10.0.1

jshell> List.of().get(0)
|  java.lang.IndexOutOfBoundsException thrown: Index 0 out-of-bounds for length 0
|        at Preconditions.outOfBounds (Preconditions.java:64)
|        at Preconditions.outOfBoundsCheckIndex (Preconditions.java:70)
|        at Preconditions.checkIndex (Preconditions.java:248)
|        at Objects.checkIndex (Objects.java:372)
|        at ImmutableCollections$List0.get (ImmutableCollections.java:106)
|        at (#6:1)


JDK11-ea14

jshell> List.of().get(0)
|  Exception java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
|        at ImmutableCollections$ListN.get (ImmutableCollections.java:411)
|        at (#3:1)


実はList.of()がList0とかList1とか要素数にあわせた専用クラスのインスタンスを返してたのですが、それもListNに統一されたことがわかります。

System

arraycopy

エラーメッセージが人類に優しくなりました。
JDK10

jshell> System.arraycopy(new int[0],0,new double[0],0,0)
|  java.lang.ArrayStoreException thrown


JDK11ea19

jshell> System.arraycopy(new int[0], 0, new double[0], 0, 0)
|  Exception java.lang.ArrayStoreException: arraycopy: type mismatch: can not copy int[] into double[]
setProperty(String, String)

いままでjava.homeとかをいじるとエラいことなってたと思うのですが、システムに影響がなくなりました。たぶん。

Swing

ea20からフォント描画でユニコードのバリエーションセレクタが反映されるらしい。未確認。

Base64

ea20からエンコードにAVX512を使うようになったので速くなった、らしい。
Windowsでは確認できませんでした。Linuxだけかも。

Boolean

parseBoolean

無駄なnullチェックを省いてちょっと速くなった、らしい。
JDK10

    public static boolean parseBoolean(String s) {
        return ((s != null) && s.equalsIgnoreCase("true"));
    }


JDK11

    public static boolean parseBoolean(String s) {
        return "true".equalsIgnoreCase(s);
    }

差については未確認

List

copyOf

Java10で導入されたcopyOfですが、subListをコピーするときの挙動がダメだったらしい。シリアライズができない。
ここまでは共通。

jshell> var list1 = List.of("a","b","c")
list1 ==> [a, b, c]

jshell> var list2=list1.subList(1,2)
list2 ==> [b]

jshell> var list3=List.copyOf(list2)
list3 ==> [b]


JDK11ea19

jshell> list2==list3
$13 ==> true

jshell> new ObjectOutputStream(OutputStream.nullOutputStream()).writeObject(list3)
|  Exception java.io.NotSerializableException: java.util.ImmutableCollections$SubList
|        at ObjectOutputStream.writeObject0 (ObjectOutputStream.java:1185)
|        at ObjectOutputStream.writeObject (ObjectOutputStream.java:349)
|        at (#14:1)


JDK11ea20

jshell> list2==list3
$26 ==> false

jshell> new ObjectOutputStream(OutputStream.nullOutputStream()).writeObject(list3)

jshell>

TimSort

なんかバグがあって修正されたぽい
https://blog.satotaichi.info/timsort-was-broken/

Java9から三項演算子でのunboxingの挙動がJava8とは変わっている

Java9からJDK11-ea18まで、三項演算子でのunboxingの挙動がJava8とは変わっているようです。


次のようなコードの挙動がJava8でコンパイルしたときとJava9以降でコンパイルしたときとで変わっています。

Double d = false ? 1.0 : new HashMap<String, Double>().get("a");


試しに次のようなコードを実行してみます。

import java.util.HashMap;

public class BoxingBehavior {
    public static void main(String[] args) {
        System.out.println(System.getProperty("java.version"));
        Double d = false ? 1.0 : new HashMap<String, Double>().get("a");
        System.out.println(d);
    }
}


Java8ではdにnullが入ります

1.8.0_151
null


Java9以降ではNullPointerExceptionが発生します。

Exception in thread "main" 9.0.4
java.lang.NullPointerException
	at com.mycompany.BoxingBehavior.main(BoxingBehavior.java:17)


Java9以降のコンパイラでtargetを1.8にしても発生します。また、コンパイラのバグなので、Java9以降でtargetを1.8にしてコンパイルしたバイナリをJava8で動かしても発生します。


これ、Java6のときから何度か発生しているようなのに、また発生したということは、この時点でテストをちゃんと作らなかったのが問題じゃないですかね。
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6977221
https://bugs.openjdk.java.net/browse/JDK-8062801


※追記 こちらの挙動のほうが正しいっぽいので、バグじゃないらしく、Java8までがバグだったぽい
※追記(6/19) Java言語仕様15.25 条件演算子の表15.25-D
Chapter 15. Expressions

Java11ではjavacせずにJavaファイルが実行できるようになる

JDK11 ea18から、javacしないでもJavaファイルを実行できるようになりました。
あと、Windowsバイナリはzipファイルで提供されるようになっています。tarコマンドが提供されたとはいえ、エクスプローラーから解凍できるzipファイルになるのは ありがたい。
JDK 11 Early-Access Builds


JEP330が取り込まれたことにより、ソースファイルがひとつのJavaプログラムは、javac不要でjavaコマンドで実行できるようになります。
JEP 330: Launch Single-File Source-Code Programs


Windowsコマンドプロンプトだと こんな感じ。

C:\Users\naoki\java>more Hello.java
public class Main {
  public static void main(String... args) {
    System.out.println("Hello!!");
  }
}

C:\Users\naoki\java>jdk-11-ea18\bin\java Hello.java
Hello!!


これはインタプリタのように逐次ソースコードを読みながら実行するというわけではなく、内部的には、次のようにメモリに出力してコンパイルが行われ、そのメモリ内容を実行するような処理になっています。

javac -d <memory> Hello.java
java -cp <memory> Main


ここで注目してもらいたいのは、ファイル名とクラス名が一致していないところです。


ただし、すでにクラスパス上にコンパイル済みclassファイルがある場合はエラーになります。

C:\Users\naoki\java>jdk-11-ea18\bin\java Hello.java
error: class found on application class path: Main


拡張子javaを付けない場合でも、--source指定をすれば直接実行ができます。

C:\Users\naoki\java>more hello
public class Main {
  public static void main(String... args) {
    System.out.println("Hello!!");
  }
}

C:\Users\naoki\java>jdk-11-ea18\bin\java --source 11 hello
Hello!!


これを利用すると、ShebangとしてJavaファイルをコマンドのように実行することもできます。Cygwinですが、次のようになりました。

naoki@DESKTOP-P96N9VS ~$ cat hello
#! /cygdrive/c/Users/naoki/java/jdk-11-ea18/bin/java --source 11
public class Main {
  public static void main(String... args) {
    System.out.println("Hello!!");
  }
}

naoki@DESKTOP-P96N9VS ~$ ls hello -l
-rwxr-xr-x 1 naoki naoki 171 6月  17 17:50 hello

naoki@DESKTOP-P96N9VS ~$ ./hello
Hello!!


Javaを少し気軽に実行できるようになりますね。入門には とてもいいと思います。