#java

ハマっちゃったException第二弾です。 実際はハマったワケではありませんが、 一応こんなExceptionがあると。

String blank = "";

int i = Integer.parseInt(blank);

これで余裕に下記のExceptionが出ます。

java.lang.NumberFormatException: For input string: ""

何も考えずにあるJavascriptの処理をJavaに書き換える作業で発生したんです。 JavascriptはブランクをparseIntするとNaN(Not a Number)になるが、 Javaは完全におちますね。。。

#java

久々にJavaを書いたので、表題のExceptionにハマっちゃいました。 こんなコードでした。

String** array = {"a", "b", "c"};
List<String> list = Arrays.asList(array);
list.add("d");

ちょこっとググッてみたらasListで作ったListに add()で要素を追加すると上記のExceptionになるそうです。 asListのJavadocでの記載は

指定された配列を基にする固定サイズのリストを返します。返されたリストへの変更は、そのまま配列に書き込まれます。(後は省略)

なるほど。。。 とりあえず深く考えずに下記のように書き換えて回避しました。

String** array = {"a", "b", "c"};
List<String> list = new ArrayList<String>();
list.addAll(Arrays.asList(array));
list.add("d");
#jquery

表題の通り、IE6 + jQuery1.3.2の状態でbindする時に jQueryのnamespaceを使うと確実にメモリリークが発生します。 jQuery1.4.2では発生しないことを確認しました。

メモリリークが発生するコード

$("#foo").bind("change.abc", function(){});

上記”change.abc”のabcがnamespaceです。 それをなくすことでメモリリークは解消されます。 イベントハンドラの中身とは関係ありません。

メモリリークは発生しない

$("#foo").bind("change", function(){});

これはjQueryのbugとして上げられましたが、 完全に修正できなかったみたいです。 http://dev.jquery.com/ticket/4241で 当時の担当者のコメントを見ると

I had a really difficult time getting a reliable test case to verify this actually solves the memory leak. r6321 appears to have fixed this issue

「時間ないからちゃんとテストしてない、r6321の対応で解決できたように見える」と、 ずいぶん適当な回答ですよね。。。

#jquery

DOM操作を避けてjQueryのパフォーマンスを改善する掟です。 こんなコードがあるとしましょう。

パフォーマンスの悪い例

var list = *....*;    // 長さ100の配列とする

for (var i in list) {

    var li = document.createElement("li");

    $(li)
       .attr("id", "li" + i)
       .text(list*i*);

$("ul").append(li);

}

改善したコード

var list = *....*;    // 長さ100の配列とする

var li = "";
for (var i in list) {

    li += "<li id='li" + i "'>" + list*i* + "</li>";

}

$("ul").html(li);

まとめ

  • document.createElementの代わりにHTMLの文字列を作る
  • jQueryオブジェクトに属性やテキストを設定するのではなく、直接HTML文字列に書く
  • for文内毎回appendの代わりにhtml()を使う

実際のプロジェクトでやってみたら10倍以上は速くなりました。 とは言ってもこれはIE6でのパフォーマンスで、 FirefoxやIE8だと悪い例のコードても遅いとは実感できないくらいでした。

ちなみに $(li).attr(…).val(…).text(…)の方は読みやすいので結構気に入ったんですけど。。。

#jquery

jQuery 1.4.2ではこれは治ったようです。 jQuery最新版をお使いの方は下記のようなバグはもう発生しません。

サンプル

※jQuery 1.3.2で発生する問題※

HTML

<select>
	<option id="foo">&nbsp;</option>
	<option>11</option>
	<option>22</option>
</select>

<tr id="bar">&nbsp;</tr>

Javascript

var optionText = $("#foo").text();

// firefoxは0、IEは1
alert("select optionタグの をtrimした後のlength: " + $.trim(optionText).length);

var trText = $("#bar").text();

// firefoxは0、IEも0!
alert("trタグの をtrimした後のlength: " + $.trim(trText).length);

結果

selectのoptionタグのテキストにある“&nbsp;”に $.trimをかけて見ると Firefoxはちゃんとtrimしてlengthが0になったが、 IEはtrimできずlengthが1のままです。

しかしtrタグのテキストにある”&nbsp;”をtrimすると IEも正しくtrimしてlengthが0になるんです。。。

DEMO

jQuery最新版(1.4.2)を使うDEMO