せてぃーずノート

Javaのイベント参加レポートとかを書いたりします。

関数型インターフェースで気になったことを試してみた

関数型インターフェースとは?

ざっくり言うと、メソッドが1つだけ定義されたインターフェース。

関数型にならないケース

メソッド1つだけと言っても、defaultやstaticは対象外。
なので、defaultメソッドだけ持ったインターフェースは関数インターフェースと呼べない。

@FunctionalInterface
public interface A {
    default public int onlyMethod(int value) {
        return origin * 2;
    };
}

エラーメッセージはこんな感じ。

予期しない@FunctionalInterface注釈
Aは機能インタフェースではありません
  インタフェース Aで抽象メソッドが見つかりません

てか、関数型インターフェースって名前じゃないのか!
機械翻訳な気もするけど、Oracle公式は機能インターフェースなんですかねぇ。

関数型インターフェースと継承

関数型インターフェースを継承しても、メソッドが1つだけなら関数型インターフェースを名乗れる。
使いドコロは・・・ないと思うけど。

@FunctionalInterface
public interface A {
    int onlyMethod(int value);
}

@FunctionalInterface
public interface B extends A{
      // コンパイルエラーにならない。
}

当然ですけど、default修飾子付きのメソッドでオーバーライドするとコンパイルエラーです。
エラーメッセージは最初と同じで抽象メソッドが見つからないという内容です。

@FunctionalInterface
public interface C extends A{
    @Override
    default int onlyMethod(int value) {
        return 0;
    };
}

なお、@FunctionalInterfaceを外せばコンパイルは通ります。
それによって、インターフェースの抽象メソッドをインターフェースが実装するという謎なインターフェースが出来上がります。

継承(逆の場合)

関数型ではないインターフェースを継承して無理やり関数型にしてしまう。

public interface A {
   default int onlyMethod(int value) {
       return 0;
   };
}

@FunctionalInterface
public interface B extends A{
    int onlyMethod(int value);
}

デフォルトの実装を全く無視する荒業。
使い道あるかは知らぬ・・・。

多重継承

複数のインターフェースを継承した場合のパターンも試してみました。
まずはコンパイルエラーにならないパターン。

@FunctionalInterface
public interface A1 {
    int onlyMethod(int value);
}

@FunctionalInterface
public interface A2 {
    int onlyMethod(int value);
}

@FunctionalInterface
public interface B extends A1, A2 {
      // コンパイルエラーにならない。
}

当然、継承するインターフェースのメソッドの定義が違えばコンパイルエラーになります。

@FunctionalInterface
public interface A1 {
    int mainMethod(int value);
}

@FunctionalInterface
public interface A2 {
    int subMethod(int value);
}

@FunctionalInterface
public interface B extends A1, A2 {
      // これはコンパイルエラー。
}

ちなみにエラーメッセージはこんな感じ。

予期しない@FunctionalInterface注釈
Bは機能インタフェースではありません
インタフェース Bで複数のオーバーライドしない抽象メソッドが見つかりました

この場合、どちらかのメソッドを実装すればBを関数型インターフェースにすることができます。

@FunctionalInterface
public interface B extends A1 , A2 {
    @Override
    default int subMethod(int value) {
        return 1;
    };
}

やっぱり使いドコロが無さそうですが、あえて使うならこんな感じだと思います。

@FunctionalInterface
public interface C extends A , B{
    @Override
    default int subMethod(int value) {
        // デフォルトと言いつつ実装を強要してみる
        throw new UnsupportedOperationException();
    };
}

ここまでして関数型インターフェースを作りたい男の人って・・・。

まとめ

Lambdaに付随して言語仕様がガッツリ変わっているおかげで、インターフェース周りで色々出来て面白いです。
ただ、きちんと規約決めておかないとインターフェースに実装メソッドが大量発生したりstaticメソッドだらけになってカオスなものが出来上がる予感もします。。。

Java8時代の文字列結合のまとめが気になったので試してみた

元ネタはこちら

Java8時代の文字列連結まとめ - きしだのはてな

だいぶ今更感がありますけど、気になったことが合ったので試してみました。

  • 気になったこと1
    データ量が多くなったら急に性能が落ちるケースってあるのか?

  • 気になったこと2
    一応SIer所属なので、「漢は黙ってStringBuffer」も比較対象に加えたい。

というわけで、きしださんの作ったソースのコピペ をベースに、StringBufferで結合する素敵メソッドを追加。
それに対して文字列リストの要素数を1倍、10倍、100倍のケースで測ってみました。

まずはオリジナルの要素数で。

stringJoin:1812ms
stringBuilderJoinMem:958ms
stringArrayJoining:686ms
charBufferJoin:773ms
stringBufferJoin:1240ms

これはきしださんの結果と大体一致しています。
String#joinを使われるよりは、StringBufferの方がマシというところでしょうか。

次に文字列の要素数を10倍にして実行。
予想ではだいたい10倍位の時間になるはずですが。。。

stringJoin:18484ms
stringBuilderJoinMem:10775ms
stringArrayJoining:8595ms
charBufferJoin:13221ms
stringBufferJoin:12630ms

アイエエエ!?CharBufferナンデ!?
素数が10倍になったら処理時間が20倍くらいになってます。
まさかのStringBufferよりも遅いという結末。

思い当たるフシとして、allocateのサイズが割りと適当なこと。
そこで、allocateの引数を90000(適当な数値)結合した文字列の長さに合わせた79995バイトに変更してみました。

CharBuffer buffer = CharBuffer.allocate(79995);

再測定した結果はこんな感じです。

stringJoin:18971ms
stringBuilderJoinMem:10594ms
stringArrayJoining:8212ms
charBufferJoin:12023ms
stringBufferJoin:12849ms

StringBufferより辛うじて早いけれど・・・という感じです。
ちなみにその後に行った100倍の結果はこちら。

stringJoin:197357ms
stringBuilderJoinMem:111888ms
stringArrayJoining:89730ms
charBufferJoin:129791ms
stringBufferJoin:132432ms

こちらは比較的予想通りの結果です。
CharBufferも前回のリミット見直しのおかげでStringBufferより早いです。

まとめ

試してみたなりのまとめです。

  • カツカツな性能が求められていない限り、StringBuilderが安定。
  • CharBufferのリミットはしっかり設定しよう。
    本来は文字列結合だけの目的で使うクラスじゃないのでしょうが・・・。
  • あれ、Java8の要素があまりないよ?

ま、まぁ、+演算子で結合というような事をしない限りは、文字列結合の速度で問題にはならない気がします。

補足

ByteBufferは使うけど、CharBuffer使ったの初めてかも・・・。

UpdateもDeleteを使わないテーブル設計

今日読んでた本で出てきたのでメモメモ。
Insertで履歴を持つまではわかるけど、削除テーブルというのがイマイチピンと来ない。
毎回Joinしちゃうの?
ググってもあまり情報が出てこない。

で、ようやく見つけたのがこれ。

PostgreSQLでINSERTのみ使用してレコードの更新履歴を残すテーブル構造を実装する - mikage014の日記

  • 通常のテーブルはINSERTのみ
  • UPDATEしたい時は通常テーブルにレコードを追加し、削除テーブルにもINSERTする。
    削除テーブルにINSERTするのは更新前のレコード
  • 削除は削除テーブルにINSERT
  • Viewは通常テーブルに対して削除テーブルを消しこんだもの。

こうすれば確かにINSERTだけで回りそう。
JPA使うときとかこういう設計のほうがいいかも。

Apache Camel+Groovyで簡単システム統合ハンズオンに行ってきた

JGGUGのハンズオンセミナーで出てきたサイトのメモ。

簡単にメモ

  • Camelとは?
     ・汎用的なシステム統合フレームワーク
     ・エンタープライズインテグレーションパターン(EIP)を実現
     ・軽量&DSL

  • 結合可能なComponentは200以上!
    TwitterからHBaseまで有名どころは大体揃ってる感じ。

  • ApacheCamelは敷居が高いので下げることがハンズオンの目標

  • EIP本がベースになっている。
    システム統合の基本は非同期でメッセージングベース。

ちなみに本はこちら。700ページオーバーらしい。

Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions: Gregor Hohpe, Bobby Woolf: 0785342200683: Amazon.com: Books

  • CamelはJarで提供。最近のライブラリにしては不親切かも。

  • 基本的にメッセージング。Camelが落ちたらデータは揮発しちゃう。
    データのライフサイクルは以下の2つがある。

  • SEDA→Staging Event Driven Architecture
    Camelコンテキスト内で有効

  • VMVM内で有効

資料とかリンクとか

モジュール

ハンズオンで作成したモジュール。

nobusue/camel-groovy · GitHub

スライドシェア

Gws 20140418 camel_groovy

ApacheCamel本家

Apache Camel: Index

感想

軽く触ってだけでも凄くイケてるし可能性の秘めてるライブラリだと思う。
下手にGUIやツール化していないので、ケースに合わせて柔軟に対応できる。
Groovyを利用することで、個々のComponentを綺麗につなぐことが可能になる。

惜しむらくは日本語の情報の少なさか・・・。

JvmCasualNightへ行ってきた!

LL言語な人たちの参加がほとんどだったせいか、スーツ率5%未満という素敵な会場。
多分、数少ないJavaでアプリ作ってる側での参加者だったと思います。

SlideShareリンク

不足分は後ほど追加ということで・・・。

NorikraのJVMチューンで苦労している話

運用に効く!JVMオプション三選

Jvm operation casual talks

感想

JVMの話も面白かったのですが、違う世界を垣間見れたのが一番の収穫かも。

  • JVMを使う理由は、必要なミドルウェアを使用するためにJVMが必要だから。
    Lucene、Cassandra、HBaseとか。

  • JVMをライブラリの前提で使ってる人は、JVMの利点をあまり感じていない?
    強いて挙げられた感のある利点としては、「スレッドが軽量で実用性がある」「高負荷に耐える」「型がある言語」というところくらい?

  • プロセスに考え方がそもそも違う
    こちとらJavaメインなので、プロセスダウンしないようにチューニングしたりする。 でもLL言語の人たちにとってのプロセスは、ダメになった殺せばいいじゃんっていう考え方(だとお思う)
    帰りのエレベーターの中でも「FullGCで止まる前にプロセスを殺せないかなぁ」という話が聞けたり。
    確かにすぐに殺しちゃえっていう人からすると起動が遅いって致命的だよね・・・。

同じJVMに関わる立場でも、異なる視点や使い方の人の考えや意見を聞けたのはとてもいい経験に慣れたと思います。

Windowsでvagrantを試してみる

参考にするのはこのページ

仮想環境構築ツール「Vagrant」で開発環境を仮想マシン上に自動作成する - さくらのナレッジ

本当はdockerを試そうと思っていました。
でもdockerのチュートリアルをやろうとしたら、最初にvagrantを入れろって言うので仕方なく入れます。

って思っていたのですが、vagrantもすげー面白い!
むしろこれ極めればdockerいらないんじゃない?とか思っちゃうかも

vagrantのインストール

vagrantにはWindows向けのインストーラーがちゃんとあります。
プログラムファイルには出てきませんが、パスも通してくれるのでインストールすればすぐに使えます。
再起動は必要ですけどね。

最初の仮想マシン作成

で、早速initしてみる。

d:\vm>vagrant init centos-6-x64 http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210.box
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

【てきとーな訳】
Vagrantfileがこのディレクトリが完成した
ただちにvagrant upで最初のVM環境を作ってみたまえ!

VagrantfileにはインストールするOSの種類や仮想マシンの環境とかを定義します。
詳しいことはここを読むといいっぽい。

Vagrantfile - Vagrant Documentation

言われたとおりにvagrant upを実行すると、OSダウンロードして仮想マシンを作成。 その後起動までしてくれます。
OSのダウンロードは最初の1回だけでいいそうです。

d:\vm>vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Box 'centos-6-x64' was not found. Fetching box from specified URL for
the provider 'virtualbox'. Note that if the URL does not have
a box for this provider, you should interrupt Vagrant now and add
the box yourself. Otherwise Vagrant will attempt to download the
full box prior to discovering this error.
Downloading box from URL: http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x
64-vbox4210.box
Extracting box...ate: 2300k/s, Estimated time remaining: --:--:--)
Successfully added box 'centos-6-x64' with provider 'virtualbox'!
[default] Importing base box 'centos-6-x64'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for machine to boot. This may take a few minutes...
DL is deprecated, please use Fiddle
[default] Machine booted and ready!
[default] The guest additions on this VM do not match the installed version of
VirtualBox! In most cases this is fine, but in rare cases it can
prevent things such as shared folders from working properly. If you see
shared folder errors, please make sure the guest additions within the
virtual machine match the version of VirtualBox you have installed on
your host and reload your VM.

Guest Additions Version: 4.2.10
VirtualBox Version: 4.3
[default] Mounting shared folders...
[default] -- /vagrant

VirtualBoxを開いてみると仮想マシンが作成されて動いています。やったね。

今日のまとめ

ここまでの所要時間DL時間含めて5分かからずです。
これが自分で作った場合、isoを落としてVMにOS入れて初期設定して・・・と倍の時間はかかるでしょう。
目的にもよりますが、テスト環境を構築したいときなんかvagrantのほうが断然おすすめと思われます。

BBASもどきを作ってます

ボーダーブレイクネタです。
自分の勉強も兼ねて、BBASもどきを開発してます。

おりじなるは以下のURL。

http://daxs.info/bbas/

とりあえず、データ集計部分は今週くらいでできそうです。
こーんなな感じで使っているアセンとか武器を収集してます。

Assenble{headParts='セイバーI型', handParts='B.U.Z.-α', bodyParts='ヘヴィガードIV型', footParts='E.D.G.-θ', assultWepon=Wepon{main='電磁加速砲・速式', sub='MSL-ナイダス', hozyo='マーシャルソード', special='AC-ディスタンス'}, heavyWepon=Wepon{main='ウィーゼル機関銃', sub='サワード・バラージ', hozyo='改良型ECMグレネード', special='バリアユニットγ'}, sniperWepon=Wepon{main='炸薬狙撃銃・絶火', sub='スティッキーボム', hozyo='セントリーガンLZ', special='光学迷彩・耐久型'}, supportWepon=Wepon{main='レイジスマック', sub='リムペットボムV', hozyo='自律型弾薬BOX', special='リペアフィールド'}, callWepon='BA:オートガン', tipList=[ExceedTip{name='タックル', cost=0}, ExceedTip{name='投てき適性', cost=0}, ExceedTip{name='爆発範囲拡大II', cost=0}]}

オリジナルにない要素として

  • MAP別の人数とポイトン
  • 地域別のポイトン

とか盛り込んでみようかと考え中です。