きしだのはてな このページをアンテナに追加 RSSフィード

2018-06-18(月) Java9から三項演算子でのunboxingの挙動がJava8とは変わっている

[]Java9から三項演算子でのunboxingの挙動がJava8とは変わっている 20:51 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までがバグだったぽい

トラックバック - http://d.hatena.ne.jp/nowokay/20180618

2018-06-17(日) Java11ではjavacせずにJavaファイルが実行できるようになる

[]Java11ではjavacせずにJavaファイルが実行できるようになる 21:43 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を少し気軽に実行できるようになりますね。入門には とてもいいと思います。

2018-06-14(木) Javaの新元号対応を試す。そして実用には問題がある

[] Javaの新元号対応を試す。そして実用には問題がある。 20:14  Javaの新元号対応を試す。そして実用には問題がある。を含むブックマーク

元号対応はNewEraという仮の元号で対応が進んでいるので、試してみました。

おそらく、実用では使えない場面がある仕様になっています。

なので、元号対応が必要そうな人は、早めに試して声をあげる必要があると思います。


ビルドする

※ 2018/6/16追記 ea18が出ているのでそのまま試せます

Masterブランチに取り込まれているので、明日あたりにでてくるea18で使えるようになると思いますが、いまは自分でビルドする必要があります。

ビルドについては、こちらを参考にしてください。ここに書いてるのとは違って、リポジトリhttp://hg.openjdk.java.net/jdk/jdkです。

http://d.hatena.ne.jp/nowokay/20171104#1509753358


使ってみる

JShellで使ってみます。

jdk $build/macosx-x86_64-normal-server-release/images/jdk/bin/jshell 
|  JShellへようこそ -- バージョン11-internal
|  概要については、次を入力してください: /help intro

jshell> import java.time.chrono.*

jshell> JapaneseDate.of(2018, 6, 14)
$2 ==> Japanese Heisei 30-06-14

jshell> JapaneseDate.of(2020, 6, 14)
$3 ==> Japanese NewEra 2-06-14

2020年の元号はNewEraになりました!

いまのところJapaneseEra.NEWERAは現時点ではprivateなので、直接使うことはできません。


問題点

たとえばぼくの免許の有効期限は平成32年3月までです。

これを扱おうとするとどうなるでしょうか?

jshell> JapaneseDate.of(JapaneseEra.HEISEI, 32, 3, 10)
|  Exception java.time.DateTimeException: year, month, and day not valid for Era
|        at JapaneseDate.of (JapaneseDate.java:231)
|        at (#8:1)

例外が発生します。これでは、ぼくの免許の有効期限はJavaでは扱えないことになりますね。現状で平成が続くことを前提とした2019年以降を対象とする文書はたくさんあります。こういった文書に記載されている年月が扱えないのは、問題になることもあると思います。

政府は2019年5月1日以降も一定期間 平成を使い続けるシステムが残る方向で調整を進めていますが、このようなシステムでJavaが使えなくなります。

改元後も「平成」利用へ 納税や年金システム、混乱回避:朝日新聞デジタル

また、JDK10までは問題なく扱えていてもJDK11以降で扱えなくなるということもあります。


もうひとつ、保険証券など長期の期限をもつものを扱うサイトで、「来年2040年は平成52年が期限と記載されているお客様は満期となります」のような表示をしようと思ったとき、JapaneseDateではこの処理ができません。

from(JapaneseEra, LocalDate)のようなメソッドを追加して、元号を指定して変換ができる必要もあるのではないかと思います。


元号に関わる処理は日本向けシステムを作っている人にしか影響がないので、日本で声をあげないと改善はされません。元号を扱う可能性があるなら、動作を確認して声をあげていかないといけないと思います。

2018-06-13(水) 福岡でおいしいビールが飲める店

福岡でおいしいビールが飲める店 01:57  福岡でおいしいビールが飲める店を含むブックマーク

という検索語で調べても、おまえ行ってないだろーとか単なるプロモーションだろーみたいなのしか出ないので、まとめておきます。

おいしいレストランでビールも3種類くらいあるよ、というのは載せてません。


ベースキャンプ

福岡で一番おいしいベルギービールの店です。ほとんどの銘柄が専用グラスで出ます。

大名にあります。

自分のところで樽を輸入したりしてます。

カレーの店という触れ込みですが、福岡で一番ベルギービールにこだわってる店です。


バイエルン福岡

福岡で一番おいしいドイツビールの店です。ほとんどの銘柄が専用グラスで出ます。

地行というところにあります。

名前からわかるように、サッカーチームのバイエルンを応援する店ですけど、ドイツビールの品ぞろえが最高です。

場所的には不便ですが、わざわざ行く価値はあります。

レカロシートの席がありますが、レカロシートは運転で体を動かさないときに快適になるように作られていて、会話のように前のめりで体を動かすのには不向きなので、カウンターか奥の席にいったほうがいいです。

RubyKaigiな人向け情報としては、九州RubyKaigi02をやったこともあります。

RegionalRubyKaigi レポート (38) 九州 Ruby 会議 02


BEER PADDY FUKUOKA

高砂のビアバー

福岡で一番いいクラフトビールの店です。

あまり広い店ではないので、大人数で行くには不向きです。

福岡で一番おいしい よなよなリアルエールが飲めます。


ブルワーズ

呉服町のビアバー

実はイベントがあるときにしか行っていないので、通常営業がどういう感じになっているかわからないのですが、たぶんおいしい。

たまにクラフトビールイベントをやっています。


クラフトビア・クリーク

今泉のビアバー

結構おもしろいビールを置いています。


Ales

最近行ってないけど、舞鶴にある、クラフトビールを置いているいい店。

IPAが多い印象。


FUKUOKA CRAFT

大名でエルボラーチョがやってるクラフトビールの店

そろそろ自家醸造が始まるはず。そうすると、自家醸造ビールが気軽に飲める福岡唯一の店ということになります。


Goodbeer STAND by Goodbeer faucets

博多駅近くにあって気軽に行けるけど、KITTEにあって割高。

Good Beer Faucetsは いつ復活するんすか?

追記:復活せずに閉店の模様・・・


== ビールにこだわってる店と言えるのはここまでかな ==


BRIM

大名にあるクラフトビールの店です。

あまりちゃんとクラフトビールを扱わなくなってきた印象


Cotton Fields

中州のビアバー。

種類は多いです。

以前は全部廣島での輸入だったので行かなくなったのだけど、久しぶりに行ったら輸入元が変わっていたので、たまに行ってもいいかなと思うようになった。


Morris

クラフトビールを置いててキャッシュオンの店

時期によって輸入元が違ったりして、というかふたりでデリリウムを頼んだら輸入元が廣島と大月で全然味がちがったということがあった。(廣島輸入は だいたいおいしくない)

あと、ベルギービールもボトルだけで出してくるので、グラスをもらったほうがいいです。

Hippo

リバレインの近くにある。

Black Sheep

大名にある。

Crafty Bear

キャナルの近くにある。

RubyKaigi後にみんなで行くなら一番いいかも

Red Fox

大名にあるっぽい。ここは行ったことない。


Hotel Okura

いま時点だと、福岡で唯一自家醸造のビールを市内で飲める店。

最近行ってないけど、バーだけになったのかな。


アサヒビール工場

竹下駅前にある、ビール工場併設のレストラン。

ジンギスカンとか食べる。

これがあるおかげで、博多駅まわりはスーパードライばかりなのだけど、よそで飲むスーパードライよりおいしかったりする。

もちろんビール工場で飲むスーパードライはおいしい。


エビスバー

博多駅の地下にある。

まだ行ったことない。

KITTEにある銀座ライオンでも似たようなビールを出してるかもしれない。


キリンビアホール 麦 BAKU

キリンビールが好きならいいんじゃないでしょうか。


あげてない店

Beer Barre Soiree(結構ビールがあった)

シュタットマインツ(ドイツ料理とあわせてドイツビールがある)

五滴の膳(キリンのSpring Valley Breweryがおいてあった)

ラ・パニエ・ド・ニーム(よなよな などヤッホーブルーイング飲み放題をやっている)

KIRIN SOW-SOW(Spring Valle Breweryもおいてある。BAKUには ない)

D&Dマーケットテーブル(行ったことない)

BREWMASTER(好みじゃないのとサイト見てもやってるかどうかわからない。あと昼しかやってないので起きてないので行けない)

Irish PubやHalf Penny(ビールは扱ってる酒の一部でしかない感じなので)


ビールは知っておくと よりおいしく飲めます。

白熱ビール教室 (星海社新書)

白熱ビール教室 (星海社新書)

2018-06-11(月) Java9、10でStringの+=に副作用があるバグ

[] Java9、10でStringの+=に副作用があるバグ 00:23  Java9、10でStringの+=に副作用があるバグを含むブックマーク

Java 9、10でStringの+=にバグがあるということがStack OverFlowで報告されていました。

Why does array[idx++]+=”a” increase idx once in Java 8 but twice in Java 9 and 10? - Stack Overflow


どういうバグかというと「s[i++] += i + ""」のようなコードが正しく動かないというものです。

次のコードを実行してみます。

public class PlusEqual {
    public static void main(String[] args) {
        System.out.print(System.getProperty("java.version"));

        String[] s = {"aa", "bb"};
        int i = 0;
        s[i++] += i + "";
        System.out.printf(" %s %d%n", Arrays.toString(s), i);
    }
}

Java 8では期待通りに動きます。

1.8.0_151 [aa1, bb] 1

ところが、JDK10.0.1では次のようになります。

10.0.1 [bb2, bb] 2

おもしろいのは、target=8とするとJDK10でもJava8と同じように動くところです。

10.0.1 [aa1, bb] 1

これは、「s[i++] += i + ""」が「s[i++] = s[i++] + i + ""」のように扱われていると考えることができます。

JDK11ea17で修正されています。JDK10.0.2はどうなるのかな。バックポートはされる予定。Java9はメンテナンスリリースは公開されないので、そのまま。

JDK-8204322 ”+=” applied to String operands can provoke side effects - Java Bug System


で、このバグレポートはJEP280に関連づけられてるので、+演算子をdynamicInvoke使う実装にしたときにエンバグしたっぽいですね。

JEP 280: Indify String Concatenation

Java8までのJVMでは もちろん文字列結合のdynamicInvokeに対応していないので、target=8としたときには問題が発生しない、と。

なので、Java9やJava10.0.1でtarget=8したくない場合は-XDstringConcat=inline をつけてコンパイルすれば問題を回避することができるようです。