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

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

PythonでJSONをパースする方法

お久しぶりです。

PythonJSONをパースする時の備忘録です。

とは言っても、Pythonは標準ライブラリでJSONをパースする機能が備わっているので、 とても簡単です。

PythonJSONをパース

#下のコードなら、requestsとjsonのimportが必須!
import requests
import json

#とりあえず例として、どこかのWeb APIを叩くことにする
url = "https://dummy-URL.com"

#requests.getを使うと、レスポンス内容を取得できるのでとりあえず変数へ保存
response = requests.get(url)

#response.json()でJSONデータに変換して変数へ保存
jsonData = response.json()

#このJSONオブジェクトは、連想配列(Map)っぽい感じのようなので
#JSONでの名前を指定することで情報がとってこれる
print(jsonData["JSONのキー"])

#responseから取得したJSONデータが単一のJSONオブジェクトではなく
#配列みたいになっているときはfor文と組み合わせてやるとよし。
for jsonObj in jsonData:
    print(jsonObj["name"])

Javaとかだと色々めんどくさいですけど、Pythonだと簡単ですね。 Python万歳!

JDK10で実装されたAPI2つ

こんにちは!

今日はJDK10で追加されたAPIを2つ程ご紹介します。
追加されたAPIの一覧はこちらをどうぞ。

コレクションのImmutableなコピー

JDK10からは、Immutable(addやput等の変更ができない)Listを作るためのAPIが追加されました。 これによって、一時的なコレクションのビューを返したい時など、変更されては困るコレクションが作成しやすくなっています。
この機能は従来からも一応存在してはいましたが、コードが冗長であるなど少々問題を抱えていました。
※作成済みのListのImmutableなコピーを作成する(従来の方法)

//リスト作成
List<Integer> list = new ArrayList<>();

//適当に要素追加
list.add(1);
list.add(2);
list.add(3);

//Immutableなコピーの作成
Collections <Integer> tmpView = Collections.unmodifiableCollection(list);

//tmpViewはImmutableになっているため変更不可(UnsupportedOperationExceptionがスローされる)
tmpView.add(4);

//元のlistはImmutable化していないので変更可能
list.add(4);

さて、JDK10での新しいAPIです。 java.util.List、java.util.Set、java.util.Mapの各インタフェースに、新しく「copyOf」メソッドが追加されており、
これを利用することでImmutableなコピーの取得が可能です。

//リスト作成
List<Integer> list = new ArrayList<>();

//適当に要素追加
list.add(1);
list.add(2);
list.add(3);

//Immutableなコピーの作成
var tmpView = List.copyOf(list);

//tmpViewはImmutableになっているため変更不可(UnsupportedOperationExceptionがスローされる)
tmpView.add(4);

という感じです。 少しは直感的になったのではないでしょうか。

ファイルのコピー

FileReaderやFileWriterを使ってファイルをコピーする際、
ファイルの中身を一文字(Buffered系の場合は一行)単位で読み取っては対象ファイルに書き出すか、
Files等を使用して冗長なコードを書くしかありませんでした。

現時点ではテキストデータに限られるようですが、FileReaderクラスにtransferToメソッドが追加されており、
簡単にファイル内容の転送が行えます。

コードはこんな感じです。
※jshell環境で動作確認しているため、本来は例外処理が必要になると思われます。

//コピー元のファイルを指定
FileReader reader = new FileReader("sample.txt");

//コピー先のファイルを指定
FileWriter writer = new FileWriter("transfer.txt");

//FileReaderのtransferToメソッドを呼び出し、引数にFileWriterオブジェクトを渡す
reader.transferTo(writer);

//各ファイルのフラッシュまたはクローズ
reader.close();
writer.close();

だいぶスッキリしたと思います。

まとめ

・List、Set、Mapの各コレクションにcopyOfメソッドが追加されており、Immutableなコレクションのコピーが取得できる
・FileReaderクラスにtransferToメソッドが追加されており、簡単にテキストファイル内容の転送(コピーができる)

では今日はこの辺で!

JavaScriptを使ったWebページの操作

こんにちは、お久しぶりです。 少しサボってしまいました、すみません。

今日は、簡単なJavaScriptを使ったWebページ上の操作を試してみたいと思います。

JavaScriptって何?

最近のWebページは、非常に綺麗で動きのついたものが多いですね。 まずは、JavaScriptがどのように利用されているのかを覚えておきましょう。

近年のWebページは、主にHTML・CSSJavaScriptを駆使することでリッチなコンテンツを実現しています。 それぞれの役割は図のような感じです。 f:id:bowtin:20180315141333p:plain

参考までに、サンプルのコードを置いておきます。

・HTML

<input id="samplebutton" type="submit" onclick="action()">


CSS

#samplebutton{background-color : #4e87ad;]


JavaScript

function action(){
    alert("本当によろしいですか?");
}


こんな感じですね。


コードをできるだけシンプルにしたので、ボタンは少々ダサいですが、組み合わせればこんな感じです。

HTML、CSSJavaScriptの実行環境

Webの世界では、クライアントからのリクエストを元に、クライアントの画面に表示すべきコンテンツのセットがサーバから送られてきます。
このコンテンツのセットには、HTML・CSSJavaScriptが含まれます。

ブラウザが、これを読み取って描画することによって、我々の目には綺麗なコンテンツが映っているんですね。

つまり、HTML・CSSJavaScriptの実行環境は、ブラウザだということになります。

JavaScriptの機能

JavaScriptには、HTMLの特定の属性に対して、特定の動作をさせる機能がたくさん備わっています。
例えば、「ボタンをクリックする」「新しいタブを開く」「入力フォームに入力する」などですね。
郵便番号を入力すると、住所が自動で入力されるのもJavaScriptのおかげであることが多いです。

ということは、JavaScriptのコードを直接書いて実行する環境があれば、
今開いているページに対して特定の操作をさせることができる!ということになります。

用意するもの

JavaScriptコードを自分で書いて実行できるブラウザ(Google Chromeがわかりやすいのでオススメです)
・動かしたいページ(無い場合は、次の節で掲載するソースをテキストファイル等に貼り付け、ブラウザで動かして下さい)
・遊び心

これだけです。

サンプルのソース

動かしたい対象のページが無い方はこちらをお使いください。

<html>
    <head>
       <script>
           function sample(){
               alert("本当によろしいですか?");
           }
       </script>
       <style>
        #submitbutton{background-color : #4e87ad;}
        </style>
   </head>
    <body>
        <input id="submitbutton" type="submit" value="GO!" onclick="sample()">
    </body>
</html>

Google Chromeの開発者ツールを開く

動かしたいページを、Google Chromeで開きましょう。

開いた後F12キーを押して開発者ツールを開き、「Console」タブをクリックします。
f:id:bowtin:20180315144045p:plain この「Console」タブでは、自由にJavaScriptコードを書いて実行することができます。

例えば、特定のボタンをクリックしたい場合は以下のようなコードが良いでしょう。

document.getElementById("submitbutton").click();

この時、「document」はページ全体のこと、getElementByIdは後続の括弧無いで示した名前を持つ要素を示します。
今回であれば、HTMLは下記のようになっているので、このボタンをクリックしたいときは「submitbutton」という名前を使ってやれば、一意に特定の要素を識別できるというわけです。

<input id="submitbutton" type="submit" value="GO!" onclick="sample()">

ついでに・・・

JavaScriptには、繰り返し処理の構文が存在します。
例えば、先程のボタンをクリックするコードを繰り返し文(while文)で囲んでやると・・・

while(true){document.getElementById("submitbutton").click();}

無限にクリックし続けることになります。
多分、CPU使用率がエラいことになるので、やる時は気をつけてくださいね。

悪用は禁止!

このように、クライアントが自分でやる場合は自己責任、なのですが
サーバ側から送られてきたコードの場合、スクリプトに書かれた条件を元に強制的に実行されるためタチが悪いです。

例えば、特定のボタンをクリックしたタイミングで、新規ウィンドウを無限に立上げ続けるとかも可能です。
かなり昔に流行った、「ブラクラ」という奴ですね。

というわけで、自分でやる分には自由ですが、くれぐれも悪用はしないでくださいね!

HashSetの利用とhashCodeメソッド、equalsメソッドの実装

こんにちは、お久しぶりです。

本日は、JavaのHashSetの簡単な使い方をご紹介していきます。

HashSetの特徴

HashSetは、ArrayListやLinkedList、HashMapなどと並んで「コレクションフレームワーク」と呼ばれる
Javaのライブラリの一つであり、色々な場面で多用されています。

超初心者の方は、とりあえず「Javaでの配列のようなもの」と考えておけば大丈夫でしょう。

上述した通り、コレクションフレームワークにはいくつかの種類があるのですが HashSetの大きな特徴は一つ、「重複を許さないこと」です。

では、書き方を見ていきましょう。

書き方

書き方はこんな感じです。

HashSet<String> sampleSet = new HashSet<String>();

ちなみに、Java SE 7 以降は右辺側の<>の中身を省略してもOKです。
俗に、「ダイアモンド演算子」と呼ばれています。

HashSet<String> sampleSet = new HashSet<>();

こんな感じですね。

<>の中には、配列に入れたいモノのデータ型を入れることができます。 文字列ならStringといった感じですね。

ちなみに、int型やdouble型等の「基本データ型」と呼ばれるものを指定したい場合は、
ラッパークラスと呼ばれるものを使っていきます(まあ、単純に置き換えて頂ければとりあえずOKです)。

基本データ型とラッパークラスの対応は以下を参考にしてください。

byte → Byte
short → Short
int → Integer
long → Long
float → Float
double → Double
char → Character
boolean → Boolean

基本的に、データ型名の先頭を大文字にすればOKなのですが、intとcharだけちょっと違いますのでご注意を。

要素の追加

HashSetクラスでは、要素の追加をaddメソッドを用いて簡単に行うことができます。
例えば、上述のsetに要素を追加するとしたら、こんな感じです。

HashSet<String> sampleSet = new HashSet<String>();

sampleSet.add("APPLE");
sampleSet.add("ORANGE");

ちなみに、冒頭でもご紹介した通り、HashSetは同一の要素がaddされた場合、無視します。
これによって、「重複を許さない」という特徴を実現しているのですね。

sampleSet.add("APPLE");
sampleSet.add("APPLE");

System.out.println(sampleSet);

上記コードでは、"APPLE"という要素を二回addしていますが、最終的にsetに格納されているオブジェクトは一つのみになります。

どのように「同一のオブジェクトである」とみなしているのか?

「同一のオブジェクトである」とみなされる要因は2つあります。

  • ハッシュコードが一致する
  • equalsメソッドの戻り値がtrueである

javaの内部で処理される順番は、
①「ハッシュコードが一致するかどうか」
②「equalsメソッドの戻り値がtrueかどうか」

となっています。


例えば、上記で挙げたStringオブジェクトの実装を見てみると・・・
hashCodeメソッドはこんな感じ。

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            hash = h = isLatin1() ? StringLatin1.hashCode(value)
                                  : StringUTF16.hashCode(value);
        }
        return h;
    }

続いて、equalsメソッドです。

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }

何言ってるんだ?と思うでしょうけれども、とりあえず
「同じ文字列だったらhashCodeでは同じハッシュコードを返し、equalsではtrueを返すように」
という実装になっていると思って頂ければOKです。

このように、Java側で実装してくれているStringクラスのようなものであれば、 既にequalsやhashCodeは実装済みであるケースが多いですので、あまり気にせずHashSetを使っても問題ないと思います。

自作クラスにhashCodeとequalsを実装する

では、自作クラスにこれら2つのメソッドを実装するときにはどうしたら良いでしょうか?

題材として、自作のこんなクラスを使っていきたいと思います。

public class Human {

    private String name; //名前
    private int age; //年齢
    private String address; //住所
    private String email; //メールアドレス

        //コンストラクタ
    public Human(String name, int age, String address, String email) {
        this.name = name;
        this.age = age;
                this.address = address;
                this.email = email;
    }
      
        //getter、setterなどは省略
}

はい、よくある「人間クラス」的な感じですかね。

人間には年齢、性別、住所等様々な情報があると思いますが、「同一人物であるかどうか」を判別する場合、 すべての情報を使っているとは限らないですよね。
例えば、クレジットカードの審査等を行う場合には、氏名と携帯電話の番号等が主なキーになるようです。

今回は、仮に名前と年齢が同一であれば同じ人物であるとしましょう。

hashCodeの実装

public int hashCode(){
        return (name + age).hashCode();
}

equalsの実装

public boolean equals(Object obj){
        Human tmpHuman = (Human)obj;
        
        if(tmpHuman.getName().equals(this.getName()) && tmpHuman.getAge == this.getAge()){
                return true;
        }else{
                return false;
       }
}

はい、かなり簡易的なものですが、簡単な実装はこんな感じになると思います。
hashCodeでは、氏名と年齢を連結した文字列のハッシュ値を返すようにしています。
必然的に、同一の氏名・年齢を持つオブジェクトであれば、同一のハッシュ値になります。

equalsでは、比較対象のオブジェクトを受取り、そのオブジェクトの氏名・年齢が自分のものと同一であれば
trueを返すような実装になっています。

開発環境でEclipse等を使っている場合には、自動生成の機能がありますので、
そちらを使っても良いでしょう。

まとめ

  • HashSetは、同一のオブジェクトを排除しつつ管理していくコレクション・フレームワーク
  • String等の既存ライブラリオブジェクトであれば、同一オブジェクトは勝手に排除される(基本的には)
  • 自作クラスの場合は、勝手に排除されないので自分でhashCodeおよびequalsメソッドを実装する
  • 評価順序はhashCode→equalsなので、両方の実装が必要

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 GA Release

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サーバなどでは有用かもしれません。

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