K4750.NET

Java13プレビュー機能「拡張switch」を試す

まだプレビュー機能なので、デフォルトでは有効ではないが(有効にするには、JVM起動オプションに –enable-preview が必要)、Java13から「switch」が文(statement)だけではなく式(expression)としても使えるようになったので、試してみる。


1.switch文(case …:)

従来の書き方。フォールスルーするので、break文が必要。

switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        System.out.println(6);
        break;
    case TUESDAY:
        System.out.println(7);
        break;
    case THURSDAY:
    case SATURDAY:
        System.out.println(8);
        break;
    case WEDNESDAY:
        System.out.println(9);
        break;
}

2.switch文(case … ->)

switch文の別の書き方として「:」の代わりに「->」を書くと、フォールスルーせず、break文は不要。

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

複数文を記述したい場合は「{}」で括る。

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> { System.out.println(9); System.out.println(10); }
}

3.switch式(case …:)

式としてswitchを使う場合は、yieldで値を返す必要がある。

System.out.println(switch (day) {
    case MONDAY, FRIDAY, SUNDAY: yield 6;
    case TUESDAY: yield 7;
    case THURSDAY, SATURDAY: yield 8;
    case WEDNESDAY: yield 9;
});

フォールスルーするので、以下の書き方も可能。

System.out.println(switch (day) {
    case MONDAY:
    case FRIDAY:
    case SUNDAY:
        yield 6;
    case TUESDAY:
        yield 7;
    case THURSDAY:
    case SATURDAY:
        yield 8;
    case WEDNESDAY:
        yield 9;
});

4.switch式(case … ->)

式でも「->」が使える。この場合は、yieldの省略が可能。

System.out.println(switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY -> 7;
    case THURSDAY, SATURDAY -> 8;
    case WEDNESDAY -> 9;
});

複数文を記述する等「{}」を使う場合は、明示的にyieldを書く必要がある。

System.out.println(switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY -> 7;
    case THURSDAY, SATURDAY -> 8;
    case WEDNESDAY -> { System.out.println("(WEDNESDAY)"); yield 9; }
});

RestControllerのスタックトレースをStringで得るコード

Spring BootのRestController実行時のスタックトレースをString化してみる。

package com.example.demo;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.stream.Stream;

@RestController
public class StackTrace {
    @RequestMapping("printStackTrace")
    public String printStackTrace() {
        return Stream.of(Thread.currentThread().getStackTrace())
                .skip(1)
                .map(StackTraceElement::toString)
                .reduce((a, ste) -> a + "\n" + ste)
                .get();
    }
}

skip(1)がないと、getStackTrace()の呼び出しまでスタックトレースに含まれてしまう。実行結果はこんな感じ。

com.example.demo.StackTrace.printStackTrace(StackTrace.java:12)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.base/java.lang.reflect.Method.invoke(Method.java:566)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1579)
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
java.base/java.lang.Thread.run(Thread.java:834)

日本初の自作キーボード専門店「遊舎工房」へ行ってきた

秋葉原(というか末広町)の自作キーボード専門店へ行ってきた。また、久々の秋葉原訪問なので、ついでに各店舗をめぐってキーボード数を再カウントしたかったが・・・ツクモeX.だけ寄って今日はおしまい。


1.遊舎工房

東京メトロ銀座線の末広町駅から御徒町方面へ徒歩5分程度。狭いお店に人が賑わっていた。

  • キーキャップのガチャガチャが・・・これは目当てではない^^;
  • ロープロファイル用のキーキャップが¥3,000ちょい(だったかな?)欲しいけど・・・その前にそのためのロープロファイルスイッチが欲しいところ。Kailhロープロファイルスイッチの赤軸が欲しいが、オンラインショップでは在庫無し。店舗はどうなのかな(結局聞かず)。
  • 自作キーボード関連の同人誌が5~6冊だか置いてあって、試し読みも可。数冊はすでに持っているものだったが・・・C95で販売された本(KbD C95 DECEMBER 2018)は初見だった。個人的にはPDFで欲しいので、BOOTHあたりで電子書籍版を待つかな^^;
  • 海外からバカ高い送料払ってキーキャップを取り寄せていたのはいつの時代だか・・・大量のキーキャップが店内にずらり。
  • 店内の工作スペースで早速作られている?方々が。
  • カウンターに展示されているのはHelixかな・・・ちょっと人が居すぎて近寄れず・・・あぁ帰宅時間が・・・T-T

2.ツクモeX.

あれ?展示されているキーボードのマニアックさが薄れて、なおかつキーボード数が減ったみたい。大量にあった左右分離キーボードも見かけなかったような?最近はキーボードにこだわるような人は自作キーボードに流れて行って、出来合いのキーボードは売れなくなってきているということなのかな・・・。

Angularでcowsayしてみた

オライリーの「Docker」本で初めてcowsayコマンドの存在を知った・・・Angularで出来るかな?


1.Angularプロジェクト作成

いつものやつ。

$ ng new cowsayangular7

2.cowsayインストール

ずばりcowsayパッケージがあるので、これをインストールする。

$ cd cowsayangular7
$ npm install --save cowsay

3.AppComponent変更

とりあえず、app.component.htmlは超シンプルにして、

<pre>{{title}}</pre>

app.component.tsにimportを追加して、title行を変更し、

import { Component } from '@angular/core';
import { say } from 'cowsay/build/cowsay.es.js';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = say({ text: 'Hello Angular7 World!'});
}

app.component.scssはこんな感じか。

pre {
  font-family: "Lucida Console";
  font-size: 32px;
}

4.Cow say “Hello Angular7 World!”

実行してみる。

$ ng serve --open

出た出た^^

Hello Angular7 World

DockerfileのCOPYの動きを確認してみる

DockerfileのCOPY命令がファイルの内容に変化がなければキャッシュを使うことは分るが・・・ファイルが消えた時等はどうなるのだろう・・・ということで試してみた。


1.サンプルファイル

Dockerfile
src\
   a.txt
   b.txt
   c.txt

Dockerfileの内容:

FROM alpine:latest
COPY src dst

2.初回ビルド

$ docker build -t copytest .
Sending build context to Docker daemon  4.096kB
Step 1/2 : FROM alpine:latest
latest: Pulling from library/alpine
4fe2ade4980c: Already exists
Digest: sha256:621c2f39f8133acb8e64023a94dbdf0d5ca81896102b9e57c0dc184cadaf5528
Status: Downloaded newer image for alpine:latest
 ---> 196d12cf6ab1
Step 2/2 : COPY src dst
 ---> 7a3d51886012
Successfully built 7a3d51886012
Successfully tagged copytest:latest

COPY結果を確認してみる。

$ docker run --rm copytest ls -l /dst
total 0
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 a.txt
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 b.txt
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 c.txt

3.2回目ビルド

ホスト環境を何も変えず、2回目を実行してみる。

$ docker build -t copytest .
Sending build context to Docker daemon  4.096kB
Step 1/2 : FROM alpine:latest
 ---> 196d12cf6ab1
Step 2/2 : COPY src dst
 ---> Using cache
 ---> 7a3d51886012
Successfully built 7a3d51886012
Successfully tagged copytest:latest

COPYは実行されず、キャッシュが使われている。よって、COPY結果も変わらず。


4.ファイルを追加する

まずはファイルを追加してみる。

Dockerfile
src\
   a.txt
   b.txt
   c.txt
   d.txt <- ファイルを追加する

ビルドを実行してみると・・・

$ docker build -t copytest .
Sending build context to Docker daemon  4.608kB
Step 1/2 : FROM alpine:latest
 ---> 196d12cf6ab1
Step 2/2 : COPY src dst
 ---> 4584e2974830
Successfully built 4584e2974830
Successfully tagged copytest:latest

キャッシュは使われずに、COPYが実行されている。結果を確認してみる。

$ docker run --rm copytest ls -l /dst
total 0
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 a.txt
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 b.txt
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 c.txt
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 d.txt

5.追加したファイルを削除する

先ほど追加した d.txt を削除して、ビルドを実行してみると、

$ docker build -t copytest .
Sending build context to Docker daemon  4.096kB
Step 1/2 : FROM alpine:latest
 ---> 196d12cf6ab1
Step 2/2 : COPY src dst
 ---> Using cache
 ---> 7a3d51886012
Successfully built 7a3d51886012
Successfully tagged copytest:latest

予想に反して(?)、(d.txtを追加する前に作成した)キャッシュが使われている。賢い^^;


6.さらにファイルを削除する

さらに c.txt を削除して、ビルドを実行してみると、

$ docker build -t copytest .
Sending build context to Docker daemon  3.584kB
Step 1/2 : FROM alpine:latest
 ---> 196d12cf6ab1
Step 2/2 : COPY src dst
 ---> c8f23fe46a11
Successfully built c8f23fe46a11
Successfully tagged copytest:latest

ファイルが消えたことを検知して、COPYが実行された。dstの内容は・・・

$ docker run --rm copytest ls -l /dst
total 0
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 a.txt
-rwxr-xr-x    1 root     root             0 Oct 27 14:25 b.txt

期待通りの動きだ^^