mike-neckのブログ

Java or Groovy or Swift or Golang

Mono<Void> は常に empty

当然といえば当然ですが、意外と気づかない。

例えば、特定の条件を満たさないとリクエストを処理しないような WebFilter を記述する。

@Bean
WebFilter webFilter() {
  return (exchange, chain) -> {
    Optional<String> requestDate = extractRequestDate(exchange);
    return Mono.justOrEmpty(requestDate)
        .flatMap(date -> Mono.defer(() -> chain.filter(exchange)))
        .switchIfEmpty(() -> forbidden(exchange));
  };
}

このような感じで何らかのヘッダーの値がある場合は処理を行った結果を返すが、ない場合は 403 Forbidden を返すみたいな WebFilter を書いたのだが、 これは常に 403 Forbidden を返し続ける。

WebFilterChain#filter(ServerWebExchange)Mono<Void> を返すが、タイトルにあるように Mono<Void> は(Voidインスタンスが作れないため)常に empty になる

ここでは、 Mono を連鎖させるのではなく、 Optional の値によって取り回すほうがよい

@Bean
WebFilter webFilter() {
  return (exchange, chain) -> {
    Optional<String> requestDate = extractRequestDate(exchange);
    return requestDate
        .map(date -> Mono.defer(() -> chain.filter(exchange)))
        .orElseGet(() -> forbidden(exchange));
  };
}

loom の JDK をビルドしてみた

表題の通り、 project loom の JDK をビルドしてみた。

f:id:mike_neck:20181019112748p:plain


環境

以下の環境でビルドした。癖で(バーストしない方がよいかなと思って)インスタンスタイプは m5a.large にしたけど、 t3a.micro とかでもいいかもしれない(よくわからん)。

boot JDK には jdk12 または jdk13 しか選べない。 Java 8 や Java 11 ではビルドできないので注意。


ビルド方法

project loom の mercurial レポジトリーをクローンして、 configure すれば必要なソフトウェアがわかるので、上記 OS 以外の人は configure の際に表示される案内に従うこと。

また、 configure の際に、 --prefix=$HOME/loom みたいなパラメーターをつけると、 make install でインストールされるディレクトリーが設定できる。デフォルトは /usr/local/bin にインストールされる。

sudo apt-get update
sudo apt-get install -y build-essential mercurial zip unzip autoconf \
    curl libx11-dev libxext-dev libxrender-dev libxrandr-dev libxtst-dev \
    libxt-dev libcups2-dev libfontconfig1-dev libasound2-dev
curl -s "https://get.sdkman.io" | bash
source "/root/.sdkman/bin/sdkman-init.sh"

mkdir /work
cd /work
hg clone http://hg.openjdk.java.net/loom/loom/
cd loom
hg update -r fibers 
chmod +x configure
./configure --prefix=$HOME/loom
make images
make install

あと、なぜかは不明だが docker でビルドすると、もれなく docker ごと落ちてしまうっぽい。

実行

上記のスクリプト$HOME/loom にインストールされる。その中にに jvmbin というディレクトリーができる。 jvm/openjdk-13-internal/bin/jshell または bin/jshell を実行すると、 Jshell が起動できる。

$ $HOME/loom/bin/jshell
May 20, 2019 9:22:38 PM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
|  Welcome to JShell -- Version 13-internal
|  For an introduction type: /help intro

jshell>

お約束の Continuation

jshell> var cont = new Continuation(scope, () ->
   ...>   IntStream.range(0,10).
   ...>     <Runnable>mapToObj(i -> () -> System.out.println("phase: " + i)).
   ...>     flatMap(runnable -> Stream.of(runnable, () -> Continuation.yield(scope))).
   ...>     forEach(Runnable::run))
cont ==> java.lang.Continuation@6d21714c scope: test-scope

jshell> while(!cont.isDone()) {
   ...>   System.out.println("running");
   ...>   cont.run();
   ...> }
running
phase: 0
running
phase: 1
running
phase: 2
running
phase: 3
running
phase: 4
running
phase: 5
running
phase: 6
running
phase: 7
running
phase: 8
running
phase: 9
running

JJUG CCC 2019 Spring で 「Collections Framework 入門」というタイトルで発表してきました #jjug_ccc

表題の通り、発表してきました。

www.slideshare.net


いくつか質問を発表後にいただきましたので、ここであらためて回答します

(Q) 資料のコードの中で new ArrayList<>(List.of("foo", "bar")) とやっていますが、これは何のインスタンスを取得していますか?

(A) これは ArrayList (可変な List) のコレクションを取得しています。なお、 Collections Framework の設計方針で、すべての Collection 系のインスタンスコンストラクターには必ず Collection を取れるようにするようにしています。また、発表資料はスペースが限られるので、その中で要素を含む ArrayList を作るコードを書くためには List.of でコレクションを作りながら、 ArrayListコンストラクターを呼び出す方法が1行で書けるので、こちらにしました。

(Q) List.of() によって取得される Listインスタンスの実装クラスは何ですか?

(A) これにはメソッドのパラメーターの数によって実装クラスが変わります。

これと同様に Set の場合は ImmutableCollections.SetNImmutableCollections.Set12 が、 Map の場合は ImmutableCollections.MapNImmutableCollections.Map1(2個の要素の場合は MapN が使われる) があります。


本セッションを応募した理由

複数の Cfp を書きましたが、以前まあやさんや慎さんに「初心者向けのセッションが圧倒的に足りていない」ということを過去に聞いたことがあったので、((基本的すぎるので)需要はないと思うけど)書いたのが今回のテーマでした。

内容

内容については、僕が初学者にわかりやすく説明するなら、こうなるだろうという内容を書いたつもりです。しかし、僕が初学者だったのは十数年前だったので、その頃のことはもう覚えてないし、たとえ覚えていたとしても人間の考え方は人により全く異なるので、正直に言って、僕は作成した資料に対して自身を持てないところがありました。発表の後、ツイッターで反応を見ていたところ、「たとえがよかった」「しっくりきた」「丁寧な説明。基礎知識としてぜひ抑えておきたい」といった反応があり、資料の方向性等で確信を持てました(遅い)。


付録資料について

付録資料の ArrayList/LinkedList の比較は、定期的に話題になるものです。僕も比較してみようと思い、 JMH でコレクションの要素数を細かく設定してパフォーマンス計測をしてみました。

計測用のソースコードはこちらです。もし試してみたい方は、下記のリポジトリーをクローンして、 distZip タスクで計測プログラムをアーカイブ化して、 ec2 などのサーバーで実行することをお勧めします。 Java 12 以上が必要ですが、 11 でも動かせると思います。 Java 8 ではコンパイルできません。

github.com

計測すると、性能の良いマシンでも数時間はかかります。手元のマシンでなく、外部の計算資源をかりて行うほうが良いでしょう。僕は AWS の ec2 の m5a.large インスタンスで実行しました。バースト可能でないインスタンスがよいです。


以上