エンターテイメント!!

遊戯王好きのJavaエンジニアのブログ。バーニングソウルを会得する特訓中。

2019/09/09週 気づきと振り返り

業務こなしての問題・気づき

callkit の CXProvideDelegate

すべてのイベントがハンドリングできるわけではない。

CXCallObserverDelegateで監視してやる必要がある。
着信画面の応答・拒否は、CXCallObserverDelegateでしかハンドリングできない。

CXCallObserverDelegate → call(CXProvideに状態の変化を伝えるメソッドを叩く) → CXProvideDelegate の流れがcallkitを開発した人が目論んでる流れだと思う。

stack viewで表示しきれない

stack viewで表示しきれない場合、scrollviewを使って、スクロールで表示できるようにする。

scroll -> stack -> ~ で実装すると、いい感じにできる。
iphone XRだと問題ないのだが、SEで表示ができず、レイアウト配置で相当悩んだ。
逆に考えるんだ、「出せなきゃ出さなきゃいいのさ」と考えて、この対応を考えた。
やっぱり、ジョジョは偉大。

その他雑記

カフェイン

最近分かったが、俺は、どうやらカフェインに過剰反応するらしい。

コーラを飲んだだけで、眠れなくなる。
夕食のときにコーラを飲んでしまうと、2時位まで寝付けないという事象が発生するのが、最近になって分かった。

ちなみに、コーヒーを飲むと、過剰反応で頭痛と下痢になる。
たぶん、血管が収縮して、血液が周りにくくなって酸素が回ってないから頭痛になるんじゃないかと予想。
下痢は、分からん。

腕時計

昔、腕時計を買ったのだが、全然身につける習慣がなくて、もったいないから、最近なるべくつけるようにしている。
そしたら、腕時計を付けたところが青ざめるんですけど、アレルギー反応なのかな?
出社するまでの1時間くらいで、うっすら青ざめてムッチャ怖いんですけど。。。
痒くなるし、変色するし、汗でベタつくから不快なんだよね。。。

仕事中は外してる。
使うのは、資格試験のときの時間確認くらいでしか利用したことがない。

これは、俺にアップルウォッチを買えというお告げなのうだろうか?
スマホは、Androidなんだけど。。。。

また増えた

今週で、とうとう32歳ですわ。
来年でゾロ目だな。

2019/08/26週 気づきと振り返り

業務こなしての問題・気づき

Swiftのlazy

クラス変数をOptionalにしたくないときに使う。
singletonみたいな使い方ができる。
遅延実行の方が近いかもしれない。

参考サイト

【Swift4.1】lazyプロパティの使い所 - Qiita

【Swift】レイジ―プロパティ(lazy)の使い方。最初にアクセスされたときに初期値が決まる。 | はじはじアプリ体験記

複数人開発でのStoryboardの使い方

複数人で開発する場合、画面ごとに分けたほうがいい。
競合が多くなり、開発効率が悪化するので、人数が増えてきたら考慮の余地がある。

参考サイト

【Xcode】Storyboardを複数に分割して管理する方法 - Qiita

多人数でのiOS開発におけるStoryboardとの向き合い方(1画面1Storyboard) - machio Development Diary

[iOS] チーム開発するなら Storyboard を分割セヨ | DevelopersIO

swiftのtableviewで、storyboardとコードの住み分け

コード回避可能なものは、なるべくコードで定義。
storyboardで何でも解決しようとすると、黒魔術化して、自分があとで分らなくなる。 見た目は、storyboard、ロジックはコードで実装するのが、一番分りやすいと思う。

Java13リリース前の予習(Text Blocks深堀)

きっかけ

前回記事でJava13の調査したけど、後々になってTextBlocksに疑問が湧いてきたので調査した

過去記事は、書きを参照

suzaku-tec.hatenadiary.jp

355: Text Blocks (Preview)

JEP 355: Text Blocks (Preview)

ダブルクォートだけを表示させたらどうなるか?

テストコード

public class Jep355Sample2 {
  public static void main(String[] args) throws Exception {
    String str = """"""";
    System.out.println(str);
  }
}

期待値

「"」だけが表示される。

答え

$ javac --enable-preview --release 13 Jep355Sample2.java 
Jep355Sample2.java:3: エラー: テキスト・ブロックの開始区切り文字のシーケンスが無効です。行の終了文字がありません
    String str = """"""";
                    ^    
Jep355Sample2.java:3: エラー: テキスト・ブロックの開始区切り文字のシーケンスが無効です。行の終了文字がありません
    String str = """"""";
                       ^

コンパイル時に怒られた。。。

Descriptionをよく読むと、The opening delimiter is a sequence of three double quote characters (""") followed by zero or more white spaces followed by a line terminator. とある。

Google翻訳よ、おらに力を分けてくれ~」と思いながら翻訳すると、「開始区切り文字は、3つの二重引用符( "" ")の後にゼロ個以上の空白が続き、行終端文字が続くシーケンスです。」となる。

期待値通りの出力をするには、下記に変えると行ける。

public class Jep355Sample2 {
  public static void main(String[] args) throws Exception {
    String str = """ 
    " 
    """;
    System.out.println(str);
  }
}

テキストブロックに\nを入れたらどうなるか?

public class Jep355Sample3 {
  public static void main(String[] args) throws Exception {
    String str = """
    hello\nSaga!!
    """;
    System.out.println(str);
  }
}

何を表示させようかと迷ったら、とりあえず佐賀。

期待値

そのまま、「hello\nSaga!!」が表示される

答え

$ java --enable-preview Jep355Sample3
hello
Saga!!

改行されるだと。。。

Descriptionをよく読むと、たしかになんか書いてある。

The content may include line terminators directly, unlike the characters in a string literal. The use of \n in a text block is permitted, but not necessary or recommended. For example, the text block:

"""
line 1
line 2
line 3
"""

is equivalent to the string literal:

"line 1\nline 2\nline 3\n"

or a concatenation of string literals:

"line 1\n" +
"line 2\n" +
"line 3\n"

If a line terminator is not required at the end of the string, then the closing delimiter can be placed on the last line of content. For example, the text block:

"""
line 1
line 2
line 3"""

is equivalent to the string literal:

"line 1\nline 2\nline 3"

ざっくり読むと、「書くこともできるけど、非推奨」的な感じだと思う。
わざわざ「\n」入れるより、改行したほうが楽だろうってことだろうね。。。

たぶん、ほかのエスケープ系の文字も同様の扱いになっている気がする。

疑問

どこでインデントがきまるの?

    String str = """
    hello Saga!!
    """;

上記の実行結果は、下記になる。

$ java --enable-preview Jep355Sample4
hello Saga!!

本来なら、文字列の前にインデントようの空白があるのだが、なぜか表示されない。
意図通りだからいいんだけど、どういうルールなのか気になった。

さっきよりインデントを増やしたら、どうなるのか試したら、今度は、追加したインデントが表示された。

    String str = """
      hello Saga!!
    """;
$ java --enable-preview Jep355Sample4
  hello Saga!!

インデントの位置は、たぶん、もっともインデントが少ないところがベースになるのだろうと予想。

dependenciesをよく読んでいると、2. Incidental white space に、なんかそれっぽい記述がある。
どうも、インデントの決定は、開始の"""以降の最小のインデントで決まるっぽい。

タブ文字は、1文字とカウントされるっぽいので、インデントに使う文字列を統一してないと、予期せぬレイアウト崩れになりそう。
TextBlocksのところだけインデントが1行ごとに違うとかは、面倒くさいから誰もやらないとは思うが、Javaのユーザ数は多いから、居そうだな。。。

Java13リリース前の予習

書こうと思ったきっかけ

そろそろリリースが近づいて来たので、まとめようと思い一念発起した。
サイト見る限り、最終リリース候補が出てるようなので、もう、大きな変更はないだろうから、キャッチアップしても大丈夫だろうという考えもある。

各種サイトへのリンク

https://openjdk.java.net/projects/jdk/13/

JDK 13 Early-Access Builds

JEP

  • 350: Dynamic CDS Archives
  • 351: ZGC: Uncommit Unused Memory
  • 353: Reimplement the Legacy Socket API
  • 354: Switch Expressions (Preview)
  • 355: Text Blocks (Preview)

ざっくり読んだ感じ、開発者に影響がありそうなのは、JEP 354/JEP 355

JEP 353も影響ありそうかと思ったけど、内部の実装の変更のようなので、調査対象から外した。
Google翻訳でやってるから、微妙に違うところがあるかも。。。
あと、見てて思ったが、JavaでSocketAPIを直に見るのは、学生のとき以来だなって思った。

354: Switch Expressions (Preview)

簡単に言うと、switchの結果を変数に入れられるようになった。

テストコード

下記の通り、テストコードを作成
java12のやつを流用して作った。

import java.util.Calendar;
import static java.util.Calendar.*;

public class jep354sample {
  public static void main(String[] args) {
    int day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
    int numLetters = switch (day) {
      case MONDAY, FRIDAY, SUNDAY -> 6;
      case TUESDAY                -> 7;
      case THURSDAY, SATURDAY     -> 8;
      case WEDNESDAY              -> 9;
      default -> 0;
    };
    
    System.out.println("numLetters:" + numLetters);
  }
}

実行

最初、defaultがない状態でコンパイルしようとしたら、下記の通り、コンパイルエラーになった。

$ javac --enable-preview --release 13 jep354sample.java 
jep354sample.java:7: エラー: switch式がすべての可能な入力値をカバーしていません
    int numLetters = switch (day) {
                     ^
注意:jep354sample.javaはプレビュー言語機能を使用します。
注意:詳細は、-Xlint:previewオプションを指定して再コンパイルしてください。
エラー1個

網羅されてないとエラーになるようになったんだな。。。
それとも、前から?
Java12のときは、エラーにならなかった気がするが、気のせいかな?

本題とはそれるので、とりあえず、コンパイル&実行

$ javac --enable-preview --release 13 jep354sample.java 
$ java --enable-preview jep354sample
numLetters:8

土曜日なので、SATURDAYだから、8で正解。
どうでもいい話だが、SATURDAYは、一週間が終わったから「去ったデー」って習った。

注目スべきは、switchの戻り値があるところだろう。
これで、ケースに応じて結果を返せるようになった。
個人的には、defualtの挙動の方が驚いた。。。

swiftの画面遷移とかで使うswitchの使い方に近いことができるのではないかと思う。

yield

yieldっていう結果返すワードが追加されたので、試す。

テストコード

public class Jep354YieldSample {
  public static void main(String[] args) {
    String day = "xxx";
    int j = switch (day) {
        case "MONDAY"  -> 0;
        case "TUESDAY" -> 1;
        default      -> {
            int k = day.toString().length();
            System.out.println("default day:" + day);
            int result = f(k);
            yield result;
        }
    };
    
    System.out.println("j:" + j);
  }
  
  private static int f(int k) {
    return k + 10000;
  }
}

実行

実行したら、下記の通り。

$ javac --enable-preview --release 13 Jep354YieldSample.java 
$ java --enable-preview Jep354YieldSample
default day:xxx
j:10003

caseの中で計算が必要なときに使うのだろうけど、必要なのか疑問に感じてしまう。。。
とりあえず、新しい動きなので、覚えておいて損はないだろう。

355: Text Blocks (Preview)

開発者が定義した通りの文字列を定義できる。 エスケープ処理が入るので、開発者は、\nとかを気にしなくていい

テストコード

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;

public class Jep355Sample {
  public static void main(String[] args) throws Exception {
    String html = """
              <html>
                  <body>
                      <p>Hello, Saga!!</p>
                  </body>
              </html>
              """;

    System.out.println("== html ==");
    System.out.println(html);
    System.out.println("==========");

    String query = """
               SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
               WHERE `CITY` = 'INDIANAPOLIS'
               ORDER BY `EMP_ID`, `LAST_NAME`;
               """;

    System.out.println("== sql ==");
    System.out.println(query);
    System.out.println("=========");

    ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
    Object obj = engine.eval("""
                            function hello() {
                                print('"Hello, Saga!!"');
                            }
                            
                            hello();
                            """);
  }
}

やってるのは、HTMLとSQLの表示、JSの実行。

実行

$ javac --enable-preview --release 13 Jep355Sample.java 
$ java --enable-preview Jep355Sample
== html ==
<html>
    <body>
        <p>Hello, Saga!!</p>
    </body>
</html>

==========
== sql ==
SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
WHERE `CITY` = 'INDIANAPOLIS'
ORDER BY `EMP_ID`, `LAST_NAME`;

=========
Warning: Nashorn engine is planned to be removed from a future JDK release
"Hello, Saga!!"

エスケープ文字列入れてないのに、ちゃんと改行されて、きれいにHTMLとSQLが出力される。
jsも、エスケープ処理なくても、きちんと実行できて"Hello, Saga!!"が出力される。

簡単なDBアクセスでSQL発行するサンプルを作りたいとか、簡単にできそう。
できれば、文字列の代入もあるといいかなと思う。
いちいちプラスで連結するのは、面倒。
Swiftみたいに、\()で代入できると楽なんだが、対応予定はあるのかな?

感想

355: Text Blocks がとても気になる。
文字列操作がもどかしいことがよくあるので、これからも継続的に改善があると嬉しい。

スケジュール通りに進んでいるようなので、Java13も予定通りリリースされると思う。

luceneで文章の類似性を試す

きっかけ

Javaで文章の類似性を数値化できないか調べたところ、luceneというライブラリで実現可能なようなので、サンプル実装して動かしてみた。

環境

IntelliJ IDEA 2019.2.1 (Community Edition)
Build #IC-192.6262.58, built on August 20, 2019
Runtime version: 11.0.3+12-b304.39 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0
GC: ParNew, ConcurrentMarkSweep
Memory: 2002M
Cores: 4
Registry: 
Non-Bundled Plugins: net.seesharpsoft.intellij.plugins.csv

実装

GitHub - suzaku-tec/sample-lucene

githubにコード載せておいたので、適時参照してね。

Gradle dependencies

必要になるのは、下記

    // https://mvnrepository.com/artifact/org.apache.lucene/lucene-core
    compile group: 'org.apache.lucene', name: 'lucene-core', version: '8.2.0'

    // https://mvnrepository.com/artifact/org.apache.lucene/lucene-spellchecker
    compile group: 'org.apache.lucene', name: 'lucene-spellchecker', version: '3.6.2'

今回試す分は、上記だけで大丈夫。

TestBatch.java

import org.apache.lucene.search.spell.JaroWinklerDistance;
import org.apache.lucene.search.spell.LevensteinDistance;

public class TestBatch {

    public static void main(String[] arg) throws Exception {

        String one = "今日の東京は非常に寒いです。でも、天気は快晴ですよ!";
        String two = "今日の京都は非常に暑いです。";

        //1に近いほど似ている
        LevensteinDistance l_algo = new LevensteinDistance();

        JaroWinklerDistance j_algo = new JaroWinklerDistance();

        System.out.println("実行結果(LevensteinDistance):" + l_algo.getDistance(one,two));
        System.out.println("実行結果(JaroWinklerDistance):" + j_algo.getDistance(one,two));

    }

}

やることは、インスタンスを生成して比較するだけ。

実行すると、下記のような表示になるはず。

実行結果(LevensteinDistance):0.42307693
実行結果(JaroWinklerDistance):0.7990983

感想

意外と簡単に試せた。
比較のアルゴリズムが、全然分からないから、調査が必要そう。
たぶんだが、コサイン類似度を使ってるんだろうなって気はする。

タスク

参考サイト

Java で Firebase を使う方法のまとめ。 | ソフトコミュ開発ブログ

2つの文字列がどれだけ類似しているかを判定するレーベンシュタイン距離とジャロ・ウィンクラー距離(Java編) | ぱーくん plus idea

windowsにgiboを導入

きっかけ

windows.gitignore作りたかったから。
作るのが死ぬほどめんどくさい。

環境

OS

当然windowsですよ。
念のため、環境情報載せておく

>ver
Microsoft Windows [Version 10.0.18362.295]

Git

>git --version
git version 2.9.0.windows.1

やりかた

やることリスト

  1. giboのダウンロード
  2. パスを通す
  3. 実行可能か確認

giboのダウンロード

任意のディレクトリにgithubから落としてくる。
後でパスを通すので、tmpとかは辞めたほうがいいと思う。

実行コマンドは、下記の通り

git clone https://github.com/simonwhitaker/gibo.git

パスを通す

落としたら、giboディレクトリにパスを通す。

E:\dev\配下にcloneしたら、gibo ディレクトリができると思うので、E:\dev\gibo環境変数に登録
自分は、システム環境変数に登録しました。

確認

下記コマンドを実行する。

gibo version

下記のような表示が出てくれば、実行環境の構築は成功

>gibo version
gibo 2.2 by Simon Whitaker <sw@netcetera.org>
https://github.com/simonwhitaker/gibo

使い方

macと使い方は変わらないので、まとめた下記の過去記事を参照

suzaku-tec.hatenadiary.jp

感想

もっと面倒くさいと思ったけど、案外楽にやれた。
macだと、homebrewが手軽すぎて、「windowsの敷居が高いのでは?」と勝手に妄想してた。

参考サイト

【入門】Windowsでgiboを用いるための環境構築とgiboの使い方 - Qiita

githubのssh-keyの登録

きっかけ

いつも迷うから。

やることは大筋理解しているのだが、面倒で手軽な方向にばかり逃げてきたので、自戒のためにまとめる。

前提条件

githubに登録するので、前提条件としては、githubのアカウント/リポジトリがあることとする。
また、vi操作は、できるものとして話を進める。

環境

OS

$sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G87

mac前提です。
windowsだと、sshクライアントがデフォルト付いてないのが嫌なので、やっぱり開発はmacでってなってしまう。
cygwin入れればいいのだろうけど、インストールが面倒なんだよね。
時間もかかるし。

Git

$git --version
git version 2.22.0

毎回、git -v をやって怒られてしまう。
ailiasつければいいのだろうが、あんまりailiasに頼りすぎると、環境を一から作るときに苦労しそうなのでやめてる。
他の人はどうしているのだろう?
「そもそも、gitのバージョンなんて確認しねーよ」って人がほとんどだろうか?

やり方

道筋

大まかなやり方の方針を、まずはざっくり理解する。

  1. ssh-keyの生成
  2. 設定ファイルの作成
  3. githubに公開鍵を登録
  4. ssh接続のテスト

ssh-keyの生成

まずは、公開鍵と秘密鍵を作る。

$ cd ~/.ssh
$ ssh-keygen -t rsa -C <メールアドレス>

ディレクトリは、~/.ssh以外でもいいけど、指定があとあと面倒になるので、なるべくここにした方が無難。

ssh-keygenを実行すると、何回か質問される。
Enter file in which to save the key (/Users/<ユーザ名>/.ssh/id_rsa):は、他の場所に保存するかどうか聞かれる。
あんまり場所を移すと、あとあとどこに何をおいたのか分からなくなるので、デフォルトのまま、何も入力せずにenterする。

Enter passphrase (empty for no passphrase):は、見た通り、パスワード設定。
これを入力すると、確認のために、再度入力を求められるので、もう一回入力してenter。

そうすると、~/.ssh/下に、id_rsa/id_rsa.pubが出来上がる。
ファイルの内容は、下記の通り。
id_rsa : 秘密鍵
id_rsa.pub : 公開鍵

設定ファイルの作成

鍵の管理を容易化するために、設定ファイルを追加する。
なければ、新規作成。

$ vi ~/.ssh/config

下記を追記する。

Host github.com
  HostName github.com
  IdentityFile ~/.ssh/id_rsa
  User git

githubに公開鍵を登録

やっと登録。
まずは、githubにサインインする。
サインインできたら、右上のアカウントアイコンを押下して、Settingsを選択。

f:id:suzaku0914:20190816141755p:plain

そしたら、左のメニューから、SSH and GPG keysを選択。 SSH keysの右側にあるnew ssh keysボタンを押下。

titleは、適当に入力。
keyには、id_rsa.pubの内容をコピペする。
下記のコマンドで、クリップボードにコピーしてペーストすると、楽チン。

$ pbcopy < ~/.ssh/id_rsa.pub

入力が終わったら、Add SSH keyボタンを押下して登録。
そうすると、一覧画面に登録した内容が表示されているはず。

ssh接続のテスト

もろもろの登録が終わったので、ちゃんと動作するのかテストする。
失敗したまま進むと、何が問題か分からなくなるので、何事も一個一個、こまめに確認しながら進むことが大事。

下記のコマンドで、ssh接続してみる。

$ ssh -T git@github.com

Are you sure you want to continue connecting (yes/no)?って聞かれたら、とりあえずyes
Enter passphrase for key '/Users/<ユーザ名>/.ssh/id_rsa':って聞かれるので、ssh-keygenで入力したパスワードを入力。
通信が成功すると、Hi <githubアカウント名>! You've successfully authenticated, but GitHub does not provide shell access.って表示されるはず。

感想

やることは簡単なんだけど、やるとなると面倒臭く感じるのは、俺が怠惰だからかも知れない。
githubは、privateリポジトリが誰でも作れたりするようになったので、ssh-keyを作成する需要は上がるかもって思って、まとめ記事を書いてみた。
実際、何も見ないでssh-keyを生成・登録できる人って、少数だと思いたい。少なくとも、俺は無理。何回も調べちゃう。

sshの概念って、わかっちゃいるけど、いざやるとパニクる時代が懐かしいなと感じた。
まだ、IT初心者の頃は、知識としてsshは知っていても、いざ問題に直面すると、フリーズしてしまった頃があった。
今は、簡単に問題解決できるように成長した俺を褒めたい。

参考サイト

GitHubにSSH接続できるようにする方法 - Qiita

GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~ - Qiita