<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>kamolog &#187; Java</title>
	<atom:link href="http://www.mkamo.org/blog/category/dev/java/feed" rel="self" type="application/rss+xml" />
	<link>http://www.mkamo.org/blog</link>
	<description>mkamo&#039;s blog ．．．．． mkamo&#039;s memo?</description>
	<lastBuildDate>Tue, 22 Feb 2011 15:20:40 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>オープンソースのJava用CSVライブラリ</title>
		<link>http://www.mkamo.org/blog/20090514/199.html</link>
		<comments>http://www.mkamo.org/blog/20090514/199.html#comments</comments>
		<pubDate>Thu, 14 May 2009 04:16:40 +0000</pubDate>
		<dc:creator>mkamo</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.mkamo.org/blog/20090514/199.html</guid>
		<description><![CDATA[opencsvはオープンソースのJava用CSVライブラリ．quote文字で囲まれたカンマを無視したり，quote文字や区切り文字を自由に設定したり，最初の数行はスキップしたり，といろいろできる． CSVファイルを読むサ [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://opencsv.sourceforge.net/">opencsv</a>はオープンソースのJava用CSVライブラリ．quote文字で囲まれたカンマを無視したり，quote文字や区切り文字を自由に設定したり，最初の数行はスキップしたり，といろいろできる．</p>
<p> <span id="more-199"></span>CSVファイルを読むサンプルコードは以下のとおり．CSVReader#readNext()で1行読み込んで，行を区切った結果をStringの配列で返してくれる．
</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d396cfde-0b7a-41ec-8fb5-44b1776da020" class="wlWriterEditableSmartContent">
<pre name="code" class="c#:nogutter:nocontrols">CSVReader reader = new CSVReader(new FileReader("hoge.csv"));
String[] line;
while ((line = reader.readNext()) != null) {
    System.out.println(line[0] + line[1] + "etc...");
}</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.mkamo.org/blog/20090514/199.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>エラー内容の流し方</title>
		<link>http://www.mkamo.org/blog/20080728/83.html</link>
		<comments>http://www.mkamo.org/blog/20080728/83.html#comments</comments>
		<pubDate>Mon, 28 Jul 2008 12:04:50 +0000</pubDate>
		<dc:creator>mkamo</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[設計]]></category>

		<guid isPermaLink="false">http://www.mkamo.org/blog/20080728/83.html</guid>
		<description><![CDATA[J2EEで開発しているプロジェクトで，EJB層で検出したエラーチェック内容をvalue objectのプロパティとして流しているのを見かけた．問題点と改善案を示してみる． まずは現状の説明から．EJB層からの戻り値となる [...]]]></description>
			<content:encoded><![CDATA[<p>J2EEで開発しているプロジェクトで，EJB層で検出したエラーチェック内容をvalue objectのプロパティとして流しているのを見かけた．問題点と改善案を示してみる．</p>
<p><span id="more-83"></span>
<p>まずは現状の説明から．EJB層からの戻り値となるvalue objectでは，EJB層で検出するひとつのエラーに対して，ひとつの～Flgというvalue objectのプロパティを定義している．</p>
</p>
<div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:431d4a64-d2ef-4542-970b-e24ffc2f547e" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="java:nogutter:nocontrols">public class FooResult {
    private boolean hogeCodeErrorFlg;
    private boolean gehoCodeErrorFlg;

    public boolean getHogeCodeErrorFlg() {
        return hogeCodeErrorFlg;
    }
    public void setHogeCodeErrorFlg(boolean value) {
        this.hogeCodeErrorFlg = value;
    }

    public boolean getGehoCodeErrorFlg() {
        return gehoCodeErrorFlg;
    }
    public void setGehoCodeErrorFlg(boolean value) {
        this.gehoCodeErrorFlg = value;
    }
}</pre>
</div>
</p>
<p>EJB層ではメソッドの戻り値として返すFooResultに対して，エラーがあった場合はそれぞれのプロパティにfalseを，なかった場合にはtrueを設定している．</p>
<div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:bf6ce2a3-22dd-4341-8b0d-d984ca8ee1a5" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="java:nogutter:nocontrols">public FooResult foo(...) throws Exception {
    FooResult result = new FooResult();

    if (validateHogeCode(...)) {
        result.setHogeCodeErrorFlg(true);
    } else {
        result.setHogeCodeErrorFlg(false);
    }

    if (validateGehoCode(...)) {
        result.setGehoCodeErrorFlg(true);
    } else {
        result.setGehoCodeErrorFlg(false);
    }

    /// do something...

    return result;
}</pre>
</div>
<p>JSP/Servlet層では，このvalue objectのget～Flg()をそれぞれ調べて，falseの場合はエラーを表示している．以下の例ではstrutsのタグを使ってエラーを表示している．</p>
</p>
<div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:a380b143-5e36-4c3b-8e0d-fc4405425a27" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="xml:nogutter:nocontrols">&lt;logic:equal name="fooResult" property="hogeCodeErrorFlg" value="false"&gt;
    &lt;%= "hogeコードがおかしいですよ．" %&gt;
&lt;/logic:equal&gt;

&lt;logic:equal name="fooResult" property="gehoCodeErrorFlg" value="false"&gt;
    &lt;%= "gehoコードがおかしいですよ．" %&gt;
&lt;/logic:equal&gt;</pre>
</div>
<p>このコードにはいくつかの問題点がある．</p>
<p>まず大きな問題として，エラーの追加という変更に対して非常に弱いということである．EJB層のfoo()メソッドで行うエラーチェックをひとつ増やすと，上で示した3つのコードのすべての箇所で修正が必要である．データ・ロジック・表示の修正が必要と，まさにダメ三冠王である．例えばFooResultではエラー内容をListなどに格納しておき，JSP/Servlet層ではそのListの中身を順番に表示する，といった形にすればデータと表示に関してはエラーの追加による影響を減らすことができる．</p>
<p>次に気になるのはプロパティ名である．boolean型のプロパティ名に～Flg，～Flagなどと名づけるのは基本的にはご法度である．hogeCodeErrorFlgといわれても，エラーがあった場合の値がtrueなのかfalseなのかわからない．実際私は上のコードを書いていて何度かtrueとfalseを間違えてしまった．boolean型のプロパティ名は，is～，has～，can～のどれかの名前にしないといけない，と思っておけば問題ない．例えばisValidHogeCodeやisNotValidHogeCodeといったプロパティ名にしておけば，エラーがあった場合の値がtrueなのかfalseなのかはプロパティ名だけから推測できる．</p>
<p>改善案の一例を以下に示しておく．エラー情報保持用のValidationErrorクラスを定義し，FooResultがリストでエラーを保持できる形にする．なお，この例では簡単のため，エラーメッセージをValidateionErrorのプロパティとして持たせているが，idとエラーの原因となった入力値だけをプロパティに持たせておいて，JSP/Servlet層でそれらの値からメッセージを組み立てるようにした方がよいこともある．</p>
</p>
<div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:4e792726-b45e-47c1-aab5-5ea3ab508299" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="java:nogutter:nocontrols">/// なにかしらのエラー情報を持つクラス
public class ValidationError {
    /// エラーの種別を表すID
    private String id;
    /// エラーメッセージ
    private String message;

    public ValidationError(String id, String message) {
        this.id = id;
        this.message = message;
    }
    public String getId() {
        return id;
    }
    public String getMessage() {
        return message;
    }
}

/// エラー情報をリストで保持
public class FooResult {
    private List&lt;ValidationError&gt; errors;
    public FooResult() {
        errors = new ArrayList&lt;ValidationError&gt;();
    }
    public List&lt;ValidationError&gt; getErrors() {
        return errors;
    }
}</pre>
</div>
<p>EJB層では，エラーがあったときにValidationErrorオブジェクトを生成して，FooResultのerrorsプロパティに追加する．</p>
<div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:b310f955-db54-4149-b496-bd6801c61e44" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="java:nogutter:nocontrols">public FooResult foo(...) throws Exception {
    FooResult result = new FooResult();

    if (!validateHogeCode(...)) {
        result.getErrors().add(
            new ValidationError("error.isNotValidHogeCode", "hogeコードがおかしいですよ．");
        );
    }

    if (!validateGehoCode(...)) {
        result.getErrors().add(
            new ValidationError("error.isNotValidGehoCode", "gehoコードがおかしいですよ．");
        );
    }

    /// do something...

    return result;
}</pre>
</div>
<p>JSP/Servlet層では，FooResultのerrorsプロパティに格納されているValidationErrorのmessageプロパティを順次表示する．</p>
<div class="wlWriterSmartContent" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:fd807049-1a5f-4741-bc20-26da8267f20a" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px">
<pre name="code" class="xml:nogutter:nocontrols">&lt;logic:iterate id="error" name="fooResult" property="errors"&gt;
    &lt;bean:write name="error" property="message"/&gt;
&lt;/logic:iterate&gt;
</pre>
</div>
<p>これでエラーチェックを追加する場合でも，EJB層のfoo()メソッドのコードの修正だけで対応できるようになる．</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mkamo.org/blog/20080728/83.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>StringTokenizerでCSVを処理するときの注意点</title>
		<link>http://www.mkamo.org/blog/20080704/64.html</link>
		<comments>http://www.mkamo.org/blog/20080704/64.html#comments</comments>
		<pubDate>Fri, 04 Jul 2008 09:41:17 +0000</pubDate>
		<dc:creator>mkamo</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.mkamo.org/blog/20080704/64.html</guid>
		<description><![CDATA[StringTokenizerでCSVを処理するときの注意点のメモ． Googleで「csv java」で検索するとStringTokenizerを使ってCSV形式の文字列を処理するいくつかの例が見つかるが，これらの例に [...]]]></description>
			<content:encoded><![CDATA[<p>StringTokenizerでCSVを処理するときの注意点のメモ．</p>
<p> <span id="more-64"></span>Googleで「csv java」で検索するとStringTokenizerを使ってCSV形式の文字列を処理するいくつかの例が見つかるが，これらの例には注意しないといけない点がある．具体的には，&quot;foo,,baz&quot;といった，一部の列に値が存在しないために「,」が続くような文字列が入力された場合，&quot;foo&quot;と&quot;baz&quot;だけが処理対象となってしまう．一般的に期待するのは&quot;foo&quot;と&quot;&quot;(空文字)と&quot;bar&quot;が処理対象となることだろう．
</p>
<p>Googleで見つかるStringTokenizerを使ったCSV処理の例から，列の分割処理だけを切り出して整えるとだいたい以下のようなコードになる．</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:7dd26ecc-1b36-47e9-911c-814672025454" class="wlWriterEditableSmartContent">
<pre name="code" class="java:nogutter:nocontrols">private static String[] splitLineWithComma(String line) {
    if (line == null) {
        return new String[0];
    }

    List&lt;String&gt; ret = new ArrayList&lt;String&gt;();

    StringTokenizer tokenizer = new StringTokenizer(line, ",");
    while (tokenizer.hasMoreTokens()) {
        ret.add(tokenizer.nextToken());
    }

    return (String[]) ret.toArray(new String[ret.size()]);
}</pre>
</div>
<p>このコードは&quot;foo,bar,baz&quot;といったすべての列に値が入っている文字列に対しては期待通りに&quot;foo&quot;と&quot;bar&quot;と&quot;baz&quot;が入った配列を返す．しかし，&quot;foo,,baz&quot;といった，一部の列に値が存在しないために「,」が続くような文字列に対しては期待通りの結果を返さない．StringTokenizerが「,」と「,」の間の&quot;&quot;をトークンとはみなせないために，&quot;foo&quot;と&quot;bar&quot;だけが入った配列を返してしまう．</p>
<p>単純にカンマで区切るだけでよいのならJDK 1.4以上であれば <code>line.split(&quot;,&quot;, -1)</code>とすればよいし，それ以前のバージョンのJDKであれば以下のようなコードでよい．</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:270b9611-4e81-4b87-bf29-810f1b6848b2" class="wlWriterEditableSmartContent">
<pre name="code" class="java:nogutter:nocontrols">private static String[] splitLineWithComma(String line) {
    if (line == null) {
        return new String[0];
    }

    List ret = new ArrayList();

    int colStart = 0;
    int colEnd = 0;
    while ((colEnd = line.indexOf(',', colStart)) != -1) {
        ret.add(line.substring(colStart, colEnd));
        colStart = colEnd + 1;
    }

    ret.add(line.substring(colStart));

    return (String[]) ret.toArray(new String[ret.size()]);
}</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.mkamo.org/blog/20080704/64.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CSVのための正規表現</title>
		<link>http://www.mkamo.org/blog/20080701/63.html</link>
		<comments>http://www.mkamo.org/blog/20080701/63.html#comments</comments>
		<pubDate>Tue, 01 Jul 2008 09:53:57 +0000</pubDate>
		<dc:creator>mkamo</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.mkamo.org/blog/20080701/63.html</guid>
		<description><![CDATA[CSVファイルを読むための正規表現のメモ． CSVファイルの一行を列に分解するには「&#34;」に囲まれていない「,」で行を分割して，その後各列から余分な「&#34;」を省けばよい．以下でこうした処理を正規表現を使っ [...]]]></description>
			<content:encoded><![CDATA[<p>CSVファイルを読むための正規表現のメモ．</p>
<p> <span id="more-63"></span>CSVファイルの一行を列に分解するには「&quot;」に囲まれていない「,」で行を分割して，その後各列から余分な「&quot;」を省けばよい．以下でこうした処理を正規表現を使って実現する方法の一例を示す．
</p>
<p>まず「&quot;」に囲まれていない「,」で行を分割することを考える．正規表現で表現するために，「&quot;」に囲まれていない「,」，を，後ろに偶数個の「&quot;」が現れる「,」，と読み替える．これを正規表現で書くと，「,(?=(([^&quot;]*&quot;){2})*[^&quot;]*$)」となる．この正規表現で区切って行を分割すればよい．</p>
<p>次に各列から余分な「&quot;」を省くことを考える．余分な「&quot;」を省くには，各列を囲んでいる「&quot;」を削除し，エスケープされた「&quot;&quot;」を「&quot;」に戻せばよい．それぞれ「^&quot;|&quot;$」にマッチすれば「」(空文字)に置換，「&quot;&quot;」にマッチすれば「&quot;」に置換という処理を行えばよい．</p>
<p>以上をまとめてJavaのコードにしたものを以下に示す．なお，この例では「&quot;」が閉じられていないなど，CSVとして不正な形式の文字列が入力されたときのことは考慮していない．
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:dc66d0cb-2097-43f5-8e51-76139f931c78" class="wlWriterEditableSmartContent">
<pre name="code" class="java:nogutter:nocontrols">/** 後ろに偶数個の「"」が現れる「,」にマッチする正規表現． */
private static final Pattern separatingCommaPattern = Pattern.compile(",(?=(([^\"]*\"){2})*[^\"]*$)");
/** 最初と最後の「"」にマッチする正規表現． */
private static final Pattern surroundingDoubleQuatationPattern = Pattern.compile("^\"|\"$");
/** 「""」にマッチする正規表現． */
private static final Pattern escapedDoubleQuoatationPattern = Pattern.compile("\"\"");

/** lineをカンマ区切りで分割して不要な'"'を取り除いたStringの配列を返す． */
public static String[] splitLineWithComma(String line) {
    /// '"'で囲まれていない','でlineを分割
    String[] cols = separatingCommaPattern.split(line, -1);
    String[] ret = new String[cols.length];
    for (int i = 0, len = cols.length; i &lt; len; i++) {
        String col = cols[i].trim();

        /// 最初と最後に'"'があれば削除
        Matcher matcher = surroundingDoubleQuatationPattern.matcher(col);
        col = matcher.replaceAll("");

        /// エスケープされた'"'を戻す
        matcher = escapedDoubleQuoatationPattern.matcher(col);
        col = matcher.replaceAll("\"");

        ret[i] = col;
    }
    return ret;
}</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.mkamo.org/blog/20080701/63.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

