【JAVA】初心者バグをなくそう PART4 -例外処理-

例外処理は、コーディングの中で一番重要な処理だと考えています。

不具合があったときの最後の砦。
だからこそしっかりとした設計・しっかりとしたプログラミングが必要です。

でも現実は、面倒くさい思うのか、はたまた難しいと思われているのか
結構軽視されることの多い例外処理。

これはJAVAの経験年数を積んだ人でもしっかりとした
設計・コーディングができている人が少ないです。


逆に言うと例外処理を極めることで人よりも1歩進むことができます。


今回は初心者向けということで設計というよりいつものように
実際にあった不具合を参考にコーディングレベルでの
注意点について書きたいと思います。


■ログの嵐


とある場所で例外が発生しました。
むむ!?なぜだか、異常にログ出力が多い。
ソースコードを追ってみると。。。

下記のようなコードが書かれていました。

public void process(String id) {
	try  {
		try {
			Integer iId = new Integer(id);
			int cnt = iId.intValue();
		} catch (NumberFormatException ex) {
			ex.printStackTrace();
			throw new SystemException(ex);
		}

		残りの処理・・・

	} catch (Exception ex) {
	 ex.printStackTrace();
	}
}


サンプルのため簡単に記述しなおしていますが、基本のフォーマットは同じです。

お分かりかと思いますが、
『ex.printStackTrace()』という文が7行目と14行目で2回出現しています。
そのためエラー時の情報が重複してログ出力されていました。


これは、正しく例外処理を理解していないといことです。

正しい例の一つは、
public void process(String id) {
	try  {
		Integer iId = new Integer(id);
		int cnt = iId.intValue();
		残りの処理・・・
	} catch (NumberFormatException ex) {
		System.err.println("引数idが数字に変換可能な値ではありません");
		ex.printStackTrace();
	} catch (RuntimeException ex) {
		System.err.println("想定外の例外が発生しました");
		ex.printStackTrace();
	}

となります。


だいぶ違いがあるかと思いますが、なぜこうなるのかは別途お話したいと思います。
それまでにご自身で理由を考えてもらえればと思います。



■データベースに接続できない;;


これまた、とある場所でSQLの実行ができないとのエラーが発生しました。

再現性を確認するために同じ操作を繰り返しおこなっていると・・・
『データーベースへの接続数がいっぱいでこれ以上は無理!』というエラーが発生しだしました。
それ以降はずっとその状態。

それは下のようなソースでした。


public static String selectName(String pkey) {
	// DBへ接続
	// getConnection()で正常にコネクションが取れるものとします。
	Connection con = getConnection(); 

	// 入力された主キーが数値以外の場合エラーを返す。
	try  {
		Integer iPkey = new Integer(pkey);
	} catch (NumberFormatException ex) {
		throw new SystemException("引数idが数字ではありません");
	}

	try {
		検索の処理・・・
	} catch (SQLException e) {
		throw new SystemException("データベース操作中にエラーが発生", e);
	} finally {
		con.close();
	}
}



上記のソースを見てすぐに気がつくかもしれませんが、
8行目で変数 pkey に数値以外が入力されていた場合は 10行目の例外処理は行われますが、
それより後ろに書かれている 18行目の con.close();の部分は実行されることはありません。



必ず後始末が必要な場合、何があっても後始末をしなければいけません。

正解は。
public static String selectName(String pkey) {
	// DBコネクション
	Connection con = null;

	// 入力された主キーが数値以外の場合エラーを返す。
	try  {
		Integer iPkey = new Integer(pkey);
		
     	// getConnection()で正常にコネクションが取れるものとします。
        con = 	getConnection(); 

		検索の処理・・・

	} catch (NumberFormatException ex) {
		throw new SystemException("引数idが数字ではありません");
	} catch (SQLException e) {
		throw new SystemException("データベース操作中にエラーが発生", e);
	} finally {
        if (con != null) {
    		con.close();
        }
	}
}


ありえない!と思うかもしれませんが、実際にあった話です。
もしかしたら数日に及ぶ残業・徹夜などが続き正常にコーディングができなかったのかもしれません。

しかしながら、このレベルの不具合は絶対に発生させてはいけないことです。
頭がモウロウとしていても、指が覚えている。そんなレベルになってほしいと思います。

しっかりとコネクションを閉じることができれば問題ありません。
この手のバグは一回埋め込まれてしまうとなかなか発見することができないため
コーディングの最中から常に注意を払いたいですね。

■今日のポイントひらめき


例外処理をする時、場所をしっかりと考えよう。
例外処理は必ず行われるように注意をしよう

この例外処理については、考え方も難しいため改めてきちっとした 記事を書こうと考えています。
とりあえず、今回は上記2つのポイントを抑えておいてくださいね。
タグ:java 初心者


参考になりましたらクリックしていただけると励みになります。



posted by てる。 at 00:16 | Comment(0) | TrackBack(0) | 【JAVA】初心者バグをなくそう | このブログの読者になる | 更新情報をチェックする

【JAVA】初心者バグをなくそう PART3 -&と|の使い方-


先日は比較についての記事を書きました。

今回は、そのつながりで。
if文で ”かつ”、 ”または”というように複数の条件を合わせて条件を評価したいときがあります。
今日はそのお話です。


■”かつ”、”または”を使う



下記のソースは、『引数 test がnull値や空文字ではないか』
ということを確認しようとしているソースなのですが、 1つ問題があります。

これも実際にあったバグのひとつなのですが、どこがおかしいかわかりますか?


例1-1)間違えた if 文
public boolean requiredCheck(String test) {
    if (test != null & !test.equals("")) {
        return true;
    }
    return false;
}


条件をつなげつとき、 "&" や "|" のように1つだけ記述すると
その後の式も実行されてしまいます。

つまり、test==null の条件判定の結果がtrueでもfalseでも、 test.equals("")の部分の式は必ず実行されるということです。

もし引数test に null の値が入ってきた場合どうなるでしょう?
そう、NullPointerExceptionが発生してしまうのです。

そのため下記のように記述するのが正解です。


例1-2)正しい if 文
public boolean requiredCheck(String test) {
    if (test != null && !test.equals("")) {
        return true;
    }
    return false;
}


普通、& や | だけで評価をすることは少ないかと思います。
(わざと何らかの例外を発生させたい場合などは除きます。)

なので、少し雑ですが、"&&", "||"を常に使うと
覚えてしまっても良いかもしれません。


■重複した比較


バグではないのですが、関連した話をもうひとつ。

さて、上記の例を踏まえ、下記のようなソースを見たとき
皆さんはどう考えますか?


例2-1)
public boolean flgCheck(AbcBean bean) {
    if (bean == null || (bean != null && !bean.getFlg())) {
        return false;
    }
    return true;
}


例1-2を参考に考えると
もし、bean が null のときはそれ以降の式は実行されないので
"bean != null"の部分は必要がありません。
つまり、こんな感じ。


例2-2)
public boolean flgCheck(AbcBean bean) {
    if (bean == null || !bean.getFlg()) {
        return false;
} return true; }


どうですか、不必要な部分がなくなった分スッキリしませんか?

& なのか、&& なのか。
たった1文字で大きく動作が変わってしまうのですね。

&と|の使い方のお話でした。

■今日のポイントひらめき

&, | ではその前後の式すべて実行した後評価される。
&&, || では条件が成立した時点で評価が終了する。




タグ:java 初心者


参考になりましたらクリックしていただけると励みになります。



posted by てる。 at 22:29 | Comment(0) | TrackBack(0) | 【JAVA】初心者バグをなくそう | このブログの読者になる | 更新情報をチェックする

【JAVA】初心者バグをなくそう Part2 -文字列比較-


まずは、最初なので超低レベルの話題あせあせ(飛び散る汗) 『文字列の比較』から始めたいと思います。
おそらく誰もが一度はやってしまったのではないでしょうか。

■文字列を比較する。


文字列の比較方法については、どの参考書でも載っているはずなのでが、
今の現場ではJAVA経験年数5年以上のベテランさんが上げているバグです。


それは、下記のようなコードでした。どこが違うかお分かりですね?


例1-1)間違った文字列比較
public boolean isBlank(String target) {
    if (target == "") {
        return true;
    }
    return false;
}

そう、JAVAでは文字列の比較は下記のようにします。


例1-2)正しい文字列比較
public boolean isBlank(String target) {
    if (target.equals("")) {
        return true;
    }
    return false;
}

簡単に言うと例1では、
  『引数のtargetという箱と""の入っている箱は同じですか?』
という意味になり、例2の場合では
  『引数のtargetという箱の中身と""は同じですか?』
の意味になります。

なので、中身同士を比べる例1-2)が正解となります。



■nullとの比較。



で、さらにソースを見るとがく〜(落胆した顔)。。。


例2-1)間違ったnullとの比較
public boolean isNull(String target) {
    if (target.equals(null)) {
        return true;
    }
    return false;
}

残念。
nullというのは箱が無いと同じ意味です。
存在しない箱と存在する箱の中身を比べると。。。

それに、もし引数ターゲットが本当に null だった場合、
equals メソッドを実行した段階で NullPointerException と
なってしまいますふらふら

なので、正解は

例2-2)正しい null との比較
public boolean isNull(String target) {
    if (target == null) {
        return true;
    }
    return false;
}

となります。

■異なるオブジェクトの比較。


さらにさらに。

例3-1)間違えたオブジェクトの比較
public boolean isNumber(Integer target) {
    if (target.equals("")) {
        return false;
    }
    return true;
}


何がおかしいかお分かりですか?
おかしなところが2つあります。
 ・Integer(数字の箱)の中身は文字列ということは無い。
 ・数字の箱の中身と文字列の箱の中身を比べても。。。

まず、1つ目ですが、
 おもちゃ箱の中に鼻をかんだティッシュが入っていたらどうですか?
 いやですねもうやだ〜(悲しい顔)
 現実の世界では絶対に無いとは言い切れませんが、
 JAVAの世界ではありえないことです。

そして2つ目
 おもちゃ箱とゴミ箱の中身を比べてうれしいことはありますか?
 ということです。


ただ、お兄ちゃんのおもちゃ箱の中身と僕の宝箱の中身であれば
比較する価値はあるかも知れませんね。

では、実際JAVAではそのようなことはあるのでしょうか?
あるか、無いかは別の機会で。


で、本題の正解ですが、”比較の必要が無い”です。
絶対にありえないものを比較しても絶対にfalseが戻ってくるので。



今回は、始めということもあり初心者の方でも知っている話をさせて頂きました。


■今日のポイントひらめき


文字列の比較は equals メソッドを使う
文字列のnull値確認は == を使う
異なるオブジェクトは equals で比較できない


■おまけ。


たかが比較、されど比較的なネットからの記事です。

文字列をequalsで判定する時
「x == y」が真なのに「x.equals(y)」が偽になるケースがあるのですがこれはJavaのバグでしょうか?


※この記事はあえてJavaの専門用語やオブジェクト思考的な考えは書きませんでした。
タグ:java 初心者


参考になりましたらクリックしていただけると励みになります。



posted by てる。 at 00:23 | Comment(0) | TrackBack(0) | 【JAVA】初心者バグをなくそう | このブログの読者になる | 更新情報をチェックする
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。