システムエンジニア兼IT講師の備忘録

技術やトレーニングテクニックなどを思いのままに発信していきます。

HTML5から追加されたinput要素の属性2つ

こんにちは。 突然ですが皆さん、HTML5は使っていますか?

勧告は2014年に行われており、ブラウザ側の対応はかなり進んでいますが
まだまだ開発側で対応が進んでいないHTML5

本日は、HTML5の中でも便利な、input要素の属性を2つ程ご紹介します。

そもそもinput要素って?

ユーザからの入力を受け付ける、テキスト入力欄やラジオボタンチェックボックス等です。
たとえば、通常のテキストフォームはこんな感じで書けます。

<input type="text">


見え方は、こんな感じですね。
※送信ボタンはダミーです。

inputの様々な属性

では、HTML5で追加されたinputの便利機能を幾つか紹介していきます。

required属性

さて、入力フォームといえば、「会員登録」や「アンケート」等が巷でよく見られるものです。
こういった入力フォームには、必ずと言っていいほど「必須項目」があります。
従来は、必須項目を作るためにJavaScriptなどを駆使していました。
それが、なんとHTML5ではキーワード一つでOKです。

<input type="text" required>

ブラウザによって若干挙動は違いますが、サーバ側で判定しているわけではないので、
サーバの負荷は当然減ります。 更に、無駄なコードを書く必要がなく、そのためバグも生まれにくいです。 便利ですね。

placeholder属性

こちらも、最近のオシャレなページなどでは良く見かけるやつです。

<input type="text" placeholder="名前">

こんな風に見えてきます。

フォーム自体がスッキリ見えますね。

まとめ

いかがでしたでしょうか。
HTML5を使うことで、サーバの負荷を減らしたり、
クライアントサイドスクリプトの開発工数を削減したり、
バグ発生の可能性を減らすことができるのではないでしょうか?

新規追加された属性や要素は他にもたくさんありますので、
ぜひ使ってみて下さい!

JDK10からは「var」が導入されるらしい

こんにちは!

Java SE 9 の新機能が云々などと言っているそばから、
なんとOpenJDK 10が2018年3月頃に公式リリースとなるとの情報が入ってきました。

現在は、テストフェーズに以降しているようで、
アーリーアクセス版もこちらからダウンロード可能です。
JDK 10 Early-Access Builds

OpenJDK 10からは各バージョンのリリース頻度を変更し、約6ヶ月ごとに新バージョンをリリースする方針であるようです。

OpenJDK 10のリアルタイムな情報や予定などはこちらからどうぞ。
JDK 10

さて、今回は上記で紹介したJDK 10を早速ダウンロードして使ってみたわけなんですが、
どうやら「var」なるキーワードが導入されているようです。

早速、jshellを使って試してみました。
jshellをご存じない方はこちらの記事をご覧ください。

bowtin.hatenablog.com

試してみた

java version "10-ea"だそうです。
f:id:bowtin:20180202154943p:plain

早速以下のコードを試してみます。

var sampleNumber = 10;
var sampleString = "Hello";

System.out.println(sampleNumber + sampleString);

f:id:bowtin:20180202155422p:plain
ほんとだ。イケる。

いわゆる型推論を行っているようです。

本当に大丈夫なの?

一般的に、varと言うとデータ型が不定であるため、バグや例外の温床になりがちな印象なのですが
一応安全策はいくつか取られているようです。

①初期化せずに宣言のみを行うことはできない

例えば、こんなコードはダメみたいです。

var x;

ちなみに、nullもダメでした。

var x = null;

②クラスのメンバ変数として利用することはできない

class Human{
    var name; //データ型が不定で推論できないため、不可
    var age; //データ型が不定で推論できないため、不可
}

③インタフェース型で受け取れない

こんなコードを良く見かけると思います。

List<String> sampleList = new ArrayList<String>();

これの左辺側をvarにしてしまうと、ArrayList型で受け取っていることになってます。

var sampleList = new ArrayList<String>();

例えば、この状態でsampleList変数へLinkedListオブジェクトを代入しようとすると…

sampleList = new LinkedList<String>();

f:id:bowtin:20180202161240p:plain
型が違うのでダメだぞ!と怒られます。

まあ、こんなコードは書かないと思うので大丈夫だとは思います。

④ラムダもダメ

例えば、Comparatorを使ってハッシュコード順に並べ替えるとしたらこうなると思います。 (ハッシュ順の並べ替えなんてやりませんが...)

Comparator c = (obj1, obj2) -> {return obj1.hashCode() - obj2.hashCode();};

これの左辺をvarにするとダメです。

var c = (obj1, obj2) -> {return obj1.hashCode() - obj2.hashCode();};

f:id:bowtin:20180202163031p:plain

まとめ

まとめると、Javaのvarは以下のようになります。

  • 右辺を見て型が決定できないものはダメ
  • ローカル変数じゃないとダメ
  • 可読性下がるよっていう公式注意書き付き
  • リファクタリングがやりづらくなるという公式注意書き付き

他言語のvarに比べると、自由度が低いと感じるかもしれませんが JavaScriptのように自由すぎるわけでもなく、Javaなりにいい具合の妥協ポイントを突いてきた感じです。

では今日はこの辺で!

LinkedListとArrayListの性能差を検証してみた

こんにちは!

前回に続き、LinkedListとArrayListの使い分けについて考察していきます。

Listがそもそもなんだかよくわからん!という方はこちらをどうぞ。

bowtin.hatenablog.com

前回ご紹介した通り、JavaのListにはいくつかの種類があります。 Java APIドキュメントによれば、
Listインタフェースの既知の実装クラスは
AbstractList, AbstractSequentialList, ArrayList, AttributeList, CopyOnWriteArrayList, LinkedList, RoleList, RoleUnresolvedList, Stack, Vector
とありますので、他にも幾つかあることがわかります。

その中でも、ArrayListやLinkedListは使用頻度が高いので、今回ピックアップしてご紹介します。

使い方の違い

特にありません。 同一のインタフェースであるListを実装していますので、インスタンスの生成方法や呼び出せるメソッドに差はほぼありません。

内部の仕組みの違い

使い方に違いが無いということは、内部的に何かが違うということなのでしょう。 一般的には、以下のような違いがあると言われています。

ArrayList
  • ランダムアクセスに強い(例えば、「10番目の要素を取得」する等)
  • Listの途中にオブジェクトを挿入し、以後の要素を右にズラしたり、特定の要素を削除するような作業に弱い

2つ目のポイントについては、
全要素に通し番号を振って管理しているため、途中に挿入したり削除したりすると番号がずれてしまい、
以後の番号を振り直す作業が必要になるためだと思われます。

LinkedList
  • ランダムアクセスに弱い
  • Listの途中への挿入・削除に強い

1つ目のポイントに関しては、
全要素に通し番号を振っておらず、各要素が自分の次の要素のみを把握する(リンクしている)Listであるため、 List全体に対して「n番目の要素」と言っても、先頭から数えて行く必要があるためだと思われます。

2つめに関しても同様に、
全要素に通し番号を振っておらず、各要素が自分の次の要素のみを把握しているため、 途中にオブジェクトを挿入したとしても、隣接している要素に影響が及ぶだけで、 配列全体の通し番号を変更する必要が無いからだと思われます。

検証① ランダムアクセス(特定の位置からオブジェクトを取得する)

では、ランダムアクセスで検証してみたいと思います。

巨大なListの作成

両Listは、性能面で差が出るとは言いつつも微差なので、 大量に処理させることで違いをわかりやすくしたいと思います。

では、巨大なListを作ってみます。 データ型は、よく使いそうなStringにしてみます。

List<String> sampleArrayList = new ArrayList<>();
List<String> sampleLinkedList = new LinkedList<>();

for(int i = 0; int < 10000000; i++){
        sampleArrayList.add("Some Object");
}

for(int i = 0; int < 10000000; i++){
        sampleLinkedList.add("Some Object");
}

はい、1000万の要素を持つListが2つできました。

特定の要素を取り出す

では、特定の要素を取り出すコードを書いてみます。 こちらも、やはり100回くらいやった方が良いと思うので、繰り返し処理などを用いていきます。
あとは、パフォーマンス測定のためにSystem.nanoTime()メソッドを利用して
処理前、処理後のシステム時間を記録し、差を出すことで実際にかかった時間を測定していきます。

ArrayListから行きます。

//開始時間取得
long timeBefore = System.nanoTime();

//適当な要素を100回取得する
for(int i = 0; i < 100; i++){
        sampleArrayList.get((int)(Math.random() * 10000000));
}

//終了時間を取得
long timeAfter = System.nanoTime();

//終了時間 - 開始時間を表示
System.out.println(timeAfter - timeBefore);

ブレもあると思うので、3回程実行してみました。
ナノ秒だとわかりづらいので、ミリ秒に変換しますね。
1回目:0.72ミリ秒
2回目:0.97ミリ秒
3回目:0.82ミリ秒

いずれも、1ミリ秒以下です。

では、次にLinkedListで試します。

//開始時間取得
long timeBefore = System.nanoTime();

//適当な要素を100回取得する
for(int i = 0; i < 100; i++){
        sampleLinkedList.get((int)(Math.random() * 10000000));
}

//終了時間を取得
long timeAfter = System.nanoTime();

//終了時間 - 開始時間を表示
System.out.println(timeAfter - timeBefore);

1回目:1067ミリ秒
2回目:1041ミリ秒
3回目:979ミリ秒
大体、1秒前後かかっていますね。
というわけで、検証①の「ランダムアクセス」に関しては、明らかにArrayListのほうが高速な様子です。
「検索結果一覧表示」などは、ArrayListが良さそうですね。

検証② Listの途中への要素挿入

では、Listの途中に要素を挿入するときのことを想定して検証してみましょう。 一応ランダムアクセスは発生しますが、ArrayListでは通し番号を再度振り直す必要がでてきますので、 性能面ではLinkedListのほうが上回るかあるいは同等、と予想できます。

とは言いつつも、仮に例えばArrayListの終端に近いような位置へ挿入すると 通し番号の振り直し回数も減りますので、ArrayListのほうが上回る可能性もあります。

巨大なListの作成

検証①と同じです。

List<String> sampleArrayList = new ArrayList<>();
List<String> sampleLinkedList = new LinkedList<>();

for(int i = 0; int < 10000000; i++){
        sampleArrayList.add("Some Object");
}

for(int i = 0; int < 10000000; i++){
        sampleLinkedList.add("Some Object");
}
適当な位置に新しいオブジェクトを挿入する

では、ArrayListから行きましょう。

//開始時間取得
long timeBefore = System.nanoTime();

//適当な位置に適当な要素を100回挿入する
for(int i = 0; i < 100; i++){
        sampleArrayList.add((int)(Math.random() * 10000000), "Another Object");
}

//終了時間を取得
long timeAfter = System.nanoTime();

//終了時間 - 開始時間を表示
System.out.println(timeAfter - timeBefore);

1回目:3529ミリ秒
2回目:3315ミリ秒
3回目:2832ミリ秒

約3秒という結果になりました。

ちなみに、ランダムな位置ではなく、Listの終端に近い位置(9,999,995等)に挿入してみると 0.05~0.1ミリ秒程度になりましたので、やはり挿入位置が先頭に近いほどArrayListは遅くなるようです。

では、LinkedListで試して行きましょう。

//開始時間取得
long timeBefore = System.nanoTime();

//適当な位置に適当な要素を100回挿入する
for(int i = 0; i < 100; i++){
        sampleLinkedList.add((int)(Math.random() * 10000000), "Another Object");
}

//終了時間を取得
long timeAfter = System.nanoTime();

//終了時間 - 開始時間を表示
System.out.println(timeAfter - timeBefore);

1回目:1027ミリ秒
2回目:995ミリ秒
3回目:1035ミリ秒

大体1秒前後でした。 こちらに関しては、挿入位置を終端寄りにしても、大きな差は出ませんでした。

というわけで、待ち行列などを管理していて、割り込みなどが多発するケースでは LinkedListが適切なのではないかと思います。

まとめ

  • ランダムな位置からの取得だけならArrayList(検索結果一覧表示等)
  • ランダムな位置への挿入や削除が多いならLinkedList(待ち行列と割り込み等)

いずれにせよ、処理する件数が多くないなら微差ですが
不特定多数のリクエストを捌かなければいけないWebサーバなどでは有用かもしれません。

長くなりましたが、今回はこの辺で。

JavaのListって何だよ!

こんにちは!今日はJavaのお話です。

Java SE 9で動作確認しています。

Javaには、単純な配列ではなく、検索や途中挿入等の便利機能を持った配列である 「List」が用意されており、自由に利用することができます。

ただ、Listにも幾つか種類があり、基本的に使い方は同じなのですが 内部の仕組みが違っているため、時々効率の違い等が出るようです。

今回は、そもそもListの使いかたについて見ていきましょう。

Listの使い方

普通の配列と比較してみましょう。

普通のString型の配列

大きな特徴の一つは、要素数が決め打ちになってしまうことですね。

//要素数10の配列を作る
String[] stringArray= new String[10];

//最初に決めた要素数以上は挿入できない
stringArray[11] = "Hello!"

他にも、「既存の配列の5番目に新しく追加して、残りの要素を右にズラす」などは やろうと思えばできますが、ちょっとめんどくさいです。

List

Listでは、まず要素数を決める必要はありません。

//要素数は決めずに配列が作れる
List<String> list = new ArrayList<>();

//メモリの許す限り、いくらでも要素を足して良い
list.add("Hello");
list.add("World");

//途中挿入も思い通り
list.add(1, "Java");

結論、Listは高機能な配列と思ってもらえればOKです。

というわけで、出てきましたね。

List<String> list = new ArrayList<>();

はい。この部分です。イコールの右辺側にArrayListが出てきていますね。 実はJavaでは、こういった高機能な配列を作る時、どういう内部的な仕組みを取るか、 選ぶことができます。

幾つかのタイプが用意されていますが、よく使われているのがArrayListやLinkedListです。

具体的な使い方は、以前にもお見せした通り
List<好きなデータ型> 変数名 = new ArrayList<>();
List<好きなデータ型> 変数名 = new LinkedList<>();

です。

ソースにすると、こんな感じですね。

List<String> sampleList1 = new ArrayList<>();
List<String> sampleList2 = new LinkedList<>();

次回は、この2つの違いや使い分けについて、実験しながら考察していきたいと思います。

では!

よく聞くけど意外とわからない言葉その2 「Web3階層」

こんにちは。

今回は、「Web3階層」という用語についてお伝えしていきます。

確かに良く聞く言葉ではあるんですが、「じゃあ説明してよ」と言われると意外とわからないものですよね。 というわけで、簡単に説明していきます。

実は、Web3階層には「Webアプリケーション」という用語がくっついて来ます。

Webアプリケーションとは?

現在、日常的にWebアプリケーションを利用していない人はほとんどいないでしょう。 ネットショッピングをしたり、SNSにつぶやきを投稿したり、スケジュール管理をしたり・・・ これらに共通するのは、Webブラウザを使って利用していることです。

通常、Webブラウザを利用して、いわゆる「アプリ」のように使えるサービスのことを 「Webアプリケーション」と呼んでいきます。「Amazon.co.jp」「Twitter」「Facebook」等が有名どころなのではないでしょうか。

じゃあWeb3階層って何?

一つ上の項目で、「Webアプリケーション」が何なのかというお話をしたと思います。 では、「Webアプリケーション」を作るにはどうしたら良いのでしょうか? f:id:bowtin:20180117102520p:plain

世の中にはいろいろなモノが溢れていますが、どれをとっても、微妙に作り方は異なると思います。 例えば、手帳はいろいろなメーカーが販売していて、いろいろな種類があり、おそらく会社ごとに作り方は若干違うでしょう。 ですが、何もかもが違うわけではなく、大まかで一般的な「セオリー」が存在するはずです。

Webアプリケーションを作るときも同じで、「こうするとイイよ」と先人たちが貯めてくれたセオリー、 これが「Web3階層」です。

Webアプリケーションはどうやって作るの?

「Webアプリケーション」を作るには、物理的なハードウェアも必要ですし、プログラマが開発したソフトウェアも必要です。 「ソフトウェア」のイメージがつかない人は、「業務用のアプリ」だと思って下さい。

まとめると、
どのハードウェアをどこに配置してどのハードウェアと繋げ、
各ハードウェアにはどんなソフトウェアをインストールするのか

このノウハウこそがWeb3階層です。

具体的には、下図のような構成が一般的です。 f:id:bowtin:20180117102836p:plain

簡単に説明しますと、
Webサーバ・・・例えるなら受付。お客さんからの要求を受け付け、すぐに答えられるものはその場で回答(応答)する
アプリケーションサーバ・・・Webサーバでは処理できないもの(難しい判断や処理等)を担当し、保存しなければいけない情報や、データベースから貰わなければいけない情報があればデータベースサーバと連携していく
データベースサーバ・・・単純に言うとデータの倉庫。ひたすらデータを綺麗に貯めこむだけ。

矢印をつけると、こんな感じになりますね。 f:id:bowtin:20180117102921p:plain

いずれのサーバも、基本的にはただのコンピュータを設置すると思ってもらってOKです。 但し、家電量販店などに売られている普通のパソコンではなく、 多数のユーザからのリクエストを同時に捌いてもパンクしないような高性能なコンピュータが選定されることが多いです。 基本的には、値段も高いですね。

じゃあソフトウェアは?

ソフトウェアも、自由に選んでOKです。 よくある構成はこんな感じです。

【無償製品で埋める場合】
Webサーバ・・・OSはLinux、WebサーバとしてApacheをインストール
アプリケーションサーバ・・・OSはLinuxアプリケーションサーバとしてTomcatをインストール
データベースサーバ・・・OSはLinux、データベースとしてMySQLあるいはPostgreSQL

Microsoft社製品で埋める場合】
Webサーバ・・・OSはWindows Server、WebサーバとしてMicrosoft IISをインストール
アプリケーションサーバ・・・OSはWindows Server、アプリケーションサーバ上記IISで問題なし
データベースサーバ・・・OSはWindows Server、データベースサーバはSQL Serverをインストール

というのが非常に多いですね。 もちろん、基本的に無償製品を利用するけど、データベースだけはOracle社のOracle Databaseを使う、なんてこともあります。

各サーバは、物理的に別れている可能性もありますが、物理的には別れていない同一のコンピュータ、ということもあります。

結局、Web3階層は論理的な話だと思って頂ければOKです。

さいごに

結局のところ、Web3階層はただの「セオリー」です。 型破りな構成にしても良いですし、まったくの新しい概念を生み出しても良いです。 もちろん、ハードルは高いでしょうけれども。

では、今日はこの辺で!

VBScriptで「ファイルを開く」ウィンドウを開く

みなさんあけましておめでとうございます!

先日、VBScriptでコードを組んでいまして、 どうしても「ファイルを開く」ウィンドウを開きたかったのですが、 どうやらVBScript自体にはそういった機能が無いようです。

InputBoxを使ってファイル名をフルパスで入力してもらうとか、 色々小技はありそうですが、どうも使い勝手が悪いと感じました。

そこで、ちょっとした裏技を入手しましたのでご紹介します。

Excelを開いて、Excelの「ファイルを開く」ウィンドウを使う

Microsoft Excelには、「ファイルを開く」ウィンドウが備わっているので、 VBScriptからExcelを開いた上でこのウィンドウを表示させ、 あとからExcelをしっかり終了してやればOKという寸法です。

コードはこんな感じになります。

'①Excelを開く
Set excel = CreateObject("Application.Excel")

'②Excelそのものを使いたいわけではないので、Excelは非表示がオススメ。
'Trueにすれば表示できます
excel.Application.Visible = False

'③Excelの「ファイルを開く」ウィンドウを呼び出し、ファイルパスを戻り値として受け取る
openFileName = excel.Application.GetOpenFileName("ログファイル, *.log")

'④Excelを終了する
excel.Quit

'これで、変数openFileNameにはファイルのフルパスが保存されているので、
'好きなように使う(例えばメモ帳でファイルを開く、など)
WScript.CreateObject("WScript.Shell").Run "notepad.exe" & openFileName

コードの③部分の解説になりますが、開くファイル形式はなんでも大丈夫です。 たとえば、スクリプト内でJSONのファイルが開きたい!ということであればこのようになります。

openFileName = excel.Application.GetOpenFileName("JSONファイル, *.json")

この関数の引数のうちの前半は、ウィンドウ上で表示されるファイル形式名ですので、自分や利用者がわかればなんでも良いです。 後半は、見ての通り拡張子です。txtでもxlsxでも、あるいは自分の独自のファイルでもいけます。

あくまでも、Excelの「ファイルを開く」を利用してファイルパスを取得するだけですね。

ちょっとした注意点ですが、この引数は全部で一つの引数ですのでご留意ください。 "メモ帳, .txt"であって、"メモ帳", ".txt"ではありません。 ちょっと気持ち悪いですが。

それでは、今日はこの辺で。

VMware Workstation Playerで使えそうな設定まとめ

こんにちは!

※この記事はVMware Workstation Player 12.0および14.0で動作確認しています

マシンの仮想化を行うためによく用いられているVMware。 私は会社で、検証用の環境としてしょっちゅう活用しています。

さて、私はVMwareを使うときに良くイメージそのものをコピーして使うことが多いのですが、 毎回こういう警告が出てきてウザったく感じたわけであります。

まず、イメージをコピーしましたか移動しましたか、っていう警告。 f:id:bowtin:20171219135736p:plain

それから、ちょっとおまけですがVMware player自体の更新メッセージ

f:id:bowtin:20171219135734p:plain

これらを消す方法と、その際の注意点について解説していきます。

更新メッセージの消し方

こちらのほうが話がシンプルなので、先に書きます。

1.VMware Workstation Playerを開きます。

2.[Player] -> [ファイル] -> [環境設定]を開きます。 f:id:bowtin:20171219140031p:plain

3.下記画像の2つのチェックボックスを外しましょう。 f:id:bowtin:20171219140143p:plain
これで毎回表示されないはずです。

戻すときは、同様の手順でチェックボックスをONにしてやれば大丈夫です。

「コピーしましたか、移動しましたか」メッセージの消し方

こちらは消すだけなら簡単ですが、ちょっとした注意事項があります。

まずは消し方から。

1.仮想マシンのファイルが保存されているフォルダを開きます。

2.中はこんな感じになっているので(実際のファイル名は伏せています)、.vmxと拡張子のついたファイルを探して下さい。 f:id:bowtin:20171219140727p:plain

3.このvmxファイルをメモ帳などで開きます。

4.中は設定ファイルになっているので、下記の記述を追加しましょう。

uuid.action  = "keep"

または

uuid.action = "create"

これで毎回確認は出なくなるはずです。 上記二点の違いは後述します。

uuid.action = "keep"とuuid.action = "create"の違い

この設定には、「UUID」が深く関わってきます。 まあざっくり、マシンを一意に識別するための128ビットのIDだと思って頂ければOKです。

よくある製品ライセンスなんかも、このUUIDが同一であれば同一マシンとみなしているケースが非常に多いです。

ただ、VMwareはマシンの仮想化を行いますので、イメージをコピーしてしまった際に UUIDも同様にコピーしてしまうと、コピーしたイメージと元のイメージを同時に起動したときに問題が起こる可能性があります。

ちなみに、VMwareではUUIDが同じであればMACアドレスも同じになるようなので、 同一ネットワーク内に同一UUIDが存在するとマズい、と思ってもらえればOKですね。 uuid.action = "keep"では上記のような動きになります。

f:id:bowtin:20171219142527p:plain

コピー時にUUIDを新規生成するようにするためには、uuid.action = "create"を使います。 そうすれば、同一ネットワーク内で起動しても大丈夫です。

但し、製品ライセンス等UUIDを参照するようなプログラムがあった場合、 コピー元と同じようには動かない可能性があります。 f:id:bowtin:20171219142530p:plain

というわけで、VMイメージファイルをコピーした際に UUIDだけは新規生成するのが「コピーしました」設定、 同一UUIDを保持するのが「移動しました」設定になります。

同一ネットワーク内で起動させることがなければ、現状どちらでも問題ないように感じます。

ではまた。