なぜJ2EEプロジェクトで例外処理について話すのですか?たぶん、多くのJavaの初心者は、「例外処理を試してみません....キャッチ...ついに誰もがこれを知っています!」と言いたいと思うかもしれません。著者はまた、彼が最初にJavaを学んでいるときにこのように考えています。マルチレイヤーJ2EEプロジェクトで対応する例外クラスを定義する方法は?プロジェクトの各レイヤーで例外を処理する方法は?例外はいつスローされますか?例外はいつ記録されますか?例外を記録する方法は?チェックされた例外を未確認の例外にいつ変換する必要がありますか、そして未チェックの例外をチェックされた例外にいつ変換する必要がありますか?例外はフロントエンドページに提示する必要がありますか?例外フレームワークを設計する方法は?これらの問題については、この記事で説明します。
1。Java例外処理
手続き上のプログラミング言語では、値を返すことによってメソッドが正常に実行されるかどうかを判断できます。たとえば、C言語で記述されたプログラムでは、メソッドが正しく実行された場合、1を返します。エラーが実行されると、0。vbまたはdelphiが開発したアプリケーションで、エラーが発生したときにユーザーにメッセージボックスをポップアップします。
メソッドの返品値を通じてエラーの詳細を取得することはできません。これは、この方法が異なるプログラマーによって記述されているためかもしれません。同じタイプのエラーが異なる方法で発生する場合、返された結果とエラー情報が一貫していないためです。
したがって、Java言語は、統一された例外処理メカニズムを採用しています。
例外とは何ですか?実行時に発生するキャッチ可能で加工可能なエラー。
Java言語では、例外はすべての例外の親クラスです。例外は、例外クラスに拡張されます。例外はエラータイプに相当します。新しいエラータイプを定義する場合は、新しい例外サブクラスを拡張します。例外を使用する利点は、プログラムエラーを引き起こし、詳細なエラー情報を取得するソースコードの位置を正確に見つけることができることです。
Java例外処理は、5つのキーワードを通じて実装され、試し、キャッチ、スロー、スロー、最後に実装されます。特定の例外処理構造は、try….catch…。まずブロックによって実装されます。 Tryブロックは、例外がある可能性のあるJavaステートメントを保存します。キャッチは、例外の発生をキャッチし、例外を処理するために使用されます。最終的なブロックは、プログラム内のUnfreeリソースをクリアするために使用されます。 Tryブロックがどのように戻るかを管理していないコードが戻ってきた場合、最終ブロックは常に実行されます。
典型的な例外処理コード
public String getPassword(String userId)Throws dataaccessexception {string sql = "userId = '" +userid +"'"; string password = null; connection con = null; resultet rs = null; try {con = getConnection(); S.Executequery(SQL); while(rs.next()){password = rs.getString(1);} rs.close(); s.close();} catch(sqlexception ex){throw new data accessexception(ex);}最後に{try {if(conc conce!= null){con.close();}} catcheps(squcecections(squlsection)失敗! "、sqlex);}}パスワードを返します;} Javaの例外処理メカニズムの利点があることがわかります。
エラーは均一に分類され、例外クラスまたはそのサブクラスを拡張することにより実装されます。これにより、同じエラーが異なる方法で異なるエラーメッセージを持つ可能性があることが回避されます。異なる方法で同じエラーが発生した場合、同じ例外オブジェクトをスローするだけでいいです。
より詳細なエラー情報を取得します。例外クラスを通じて、ユーザーにとってより詳細で便利な例外にエラー情報を提供できます。ユーザーがプログラムを追跡およびデバッグするのは簡単です。
エラーメッセージから正しい返品結果を分離します。プログラムの複雑さを減らします。発信者は、返品結果についてもっと知る必要はありません。
プログラムの品質を向上させるために、発信者に例外を処理するように強制します。メソッド宣言が例外をスローする必要がある場合、発信者はTRYを使用する必要があります。...キャッチブロックは例外を処理します。もちろん、発信者は例外を上位レベルに引き続き投げ続けることもできます。
2。例外を確認するか、未確認の例外を確認しましたか?
Javaの例外は、チェックされた例外と未チェックの例外の2つのカテゴリに分けられます。 Java.lang.exceptionを継承するすべての例外は、チェックされた例外に属します。 Java.lang.RuntimeExceptionを継承するすべての例外は、未確認の例外に属します。
メソッドがチェックされた例外をスローする可能性のあるメソッドを呼び出す場合、Try ... Catch Blockを使用して、例外をキャプチャして処理または再スローする必要があります。
接続インターフェイスのcreateStatement()メソッドの宣言を見てみましょう。
公式声明CreateStatement()はsqlexceptionをスローします。 Sqlexceptionはチェックされた例外です。 CreateStatementメソッドが呼び出されると、Javaは発信者にSqlexceptionをキャプチャするように強制します。 public string getPassword(String userId){try {... statement s = con.createStatement(); ... catch(sqlexception sqlex){...} ...}または
public string getPassword(String userId)Sthows sqlexception {statement s = con.createStatement();} (もちろん、接続やサテメントなどのリソースは時間内に閉じる必要があります。これは、チェックされた例外が発信者にキャッチまたはスローを強制する必要があることを示すためだけです)
未チェックの例外は、ランタイム例外とも呼ばれます。通常、RuntimeExceptionは、データベース接続を取得できないこと、ファイルを開くことができないなど、ユーザーが回復できない例外を示します。しかし、発信者が未確認の例外をキャッチしない場合、コンパイラはあなたにそれを強制しません。
たとえば、文字を整数値に変換するコードは次のとおりです。
string str = "123"; int value = integer.parseint(str);
parseintメソッドの署名は次のとおりです。
public staticint parseint(string s)は、Numberformatexceptionをスローします
渡されたパラメーターを対応する整数に変換できない場合、数値化はスローされます。 NumberFormatexceptionはruntimeexceptionにまで及ぶため、未確認の例外です。したがって、試す必要はありません... parseintメソッドを呼び出すときにキャッチ
Javaは、発信者に未確認の例外をキャッチまたはスローするように強制しないためです。そのため、プログラマーは常にチェックされていない例外を投げたいと思っています。または、新しい例外クラスが必要な場合、それは常にruntimeexceptionから拡張するために使用されます。これらのメソッドを呼び出すと、対応するキャッチブロックがない場合、コンパイラは常に合格し、この方法がどのような例外が投げられるかを理解する必要はありません。これは良い考えのように思えますが、そうすることは、Java例外処理の本当の意図から離れています。そして、それはあなたのクラスに電話するプログラマーに誤解を招きます。なぜなら、発信者は、例外を処理するために必要な状況の下では知らないからです。チェックされた例外は、このクラスを呼び出すときにどのような例外を処理する必要があるかを発信者に明確に伝えることができます。発信者がそれを処理しない場合、コンパイラはプロンプトし、コンパイルして渡すことができません。もちろん、それに対処する方法は、決定するための発信者次第です。
そのため、Javaは、アプリケーションコードでチェックされた例外を使用することを推奨しています。前のセクションで例外を使用する利点は、発信者に生成される例外を処理するように強制できることがあると述べたように。チェックされた例外は、「Javaチュートリアル」などの公式Javaドキュメントの標準として使用されます。
チェックされた例外を使用することは、多くの試みがあることを意味するはずです...あなたのコードにキャッチされます。執筆と処理の後、ブロックをキャッチすることを試してみると、多くの人が最終的にチェックされた例外を標準として使用すべきかどうか疑問に思い始めました。
有名な「ジャバの思考」の著者であるブルース・エッケルでさえ、彼の以前の考えを変えました。ブルース・エッケルは、標準的な使用法として未チェックの例外を使用して支持することさえあります。記事を公開して、チェックされた例外をJavaから削除すべきかどうかをテストします。 Bruce Eckel:「少量のコードで、チェックされた例外が非常にエレガントな概念であり、多くの潜在的なエラーを回避するのに役立つ場合。
チェックされた例外とチェックされていない例外に関する詳細な議論については、参照してください
Javaチュートリアルhttp://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html
チェックされた例外を使用すると、多くの問題を引き起こす可能性があります。
チェックされた例外があまりにも多くを引き起こします...コードをキャッチします
Sqlexceptionなどの開発者が合理的に処理できない多くのチェックされた例外があるかもしれません。しかし、開発者は...キャッチしなければなりません。開発者がチェックされた例外を正しく処理できない場合、通常、単に例外を印刷するか、何もしません。特に初心者の場合、チェックされた例外が多すぎると、彼は途方に暮れます。
try {…statement s = con.createstatement();…catch(sqlexception sqlex){sqlex.printstacktrace();}または
try {...ステートメントs = con.createstatement();チェックされた例外は、多くの理解が困難なコード生成を引き起こします
開発者が正しく処理できないというチェックされた例外をキャッチする必要がある場合、通常、新しい例外に再パッケージ化されてからスローされます。そうすることは、プログラムに利益をもたらすことはありません。代わりに、後でコードを理解するのが難しくなります。
JDBCコードを使用するのと同じように、たくさんの試みがあります…CATCH。本当に便利なコードは、try…catchに含まれています。この方法を理解することを困難にします
チェックされた例外により、例外が常に別のクラスの例外にカプセル化され、スローされます
public void methoda()throws exceptiona {….. throw new Exceptiona();} public void methodb()throws exceptionb {try {methoda();…} catch(exceptiona ex){throw new excecustb(ex);}} public void methodc()throws {try {methodb(); catch(execuptionb(); {exception(){expeciondb();例外はレイヤーごとにカプセル化され、再スローされていることがわかります。
チェックされた例外により、インターフェイスメソッドの破損が発生します
インターフェイス上のメソッドは、複数のクラスで使用されています。この方法に追加のチェックされた例外が追加された場合、このメソッドを呼び出すすべてのコードを変更する必要があります。
発信者がチェックされた例外を正しく処理できず、カプセル化してから再投与することを余儀なくされるため、上記の問題はキャッチと処理を余儀なくされていることがわかります。これは非常に不便であり、利益をもたらしません。この場合、未確認の例外が通常使用されます。
チェックされた例外がすべてではありません。チェックされた例外は、従来のプログラミングのエラー返信値よりもはるかに使いやすいです。返品値で判断するよりも、コンパイラを介して例外が正しく処理されることを確認する方がはるかに良いです。
例外が致命的である場合、それは回復できません。または、発信者は利益なしにそれをキャッチしに行き、未確認の例外を使用します。
例外を回復し、発信者が正しく処理できる場合は、チェックされた例外を使用します。
未チェックの例外を使用する場合、メソッドがスローする可能性のある未確認の例外は、メソッド宣言で詳細に説明する必要があります。発信者は、未確認の例外をキャッチするかどうかを決定します
チェックされた例外を使用するのはいつ、および未確認の例外を使用する時期は何ですか?絶対標準はありません。しかし、私はいくつかの提案をすることができます
すべての発信者がこの例外を処理する必要がある場合、発信者は操作を再試行することができます。または、例外はメソッドの2番目の返品値に相当します。チェックされた例外を使用します。
この例外は、より少数の高度な発信者によってのみ処理され、通常の発信者はそれを正しく処理できません。未チェックの例外を使用します。処理する機能を持つ発信者は、高度な処理を実行できますが、一般に発信者はそれをまったく処理しません。
この例外は、データベース接続エラー、ファイルの開く障害など、非常に深刻なエラーです。または、これらの例外は外部環境に関連しています。再試行の問題を解決することはできません。未チェックの例外を使用します。この例外が発生すると、発信者はそれをまったく処理できないためです。
わからない場合は、未確認の例外を使用してください。そして、発信者にそれを処理するかどうかを決定させるためにスローされる可能性のある例外を詳細に説明してください。
3.新しい例外クラスを設計します
新しい例外クラスを設計するときは、最初にこの例外クラスが本当に必要かどうかを確認します。一般的に、新しい例外クラスを設計しないようにしてください。ただし、既にJavaに存在する例外クラスを使用してみてください。
のように
IllegalargumentException、UnsupportedoperationException
それが新しい例外であろうと、チェックされた例外であろうと、未確認の例外であろうと。私たちは皆、例外のネスティングの問題を考慮する必要があります。
public void methoda()throws exceptiona {….. throw new Exceptiona();}メソッドメソッド宣言は例外をスローします。
public void methodb()は例外をスローします
MethodB宣言は例外をスローします。 MethodaがMethodBメソッドで呼び出される場合、例外は処理できないため、例外は引き続き投げ続ける必要があります。 1つの方法は、MethodB宣言を例外にすることです。しかし、これにより、MethodBのメソッド署名が変更されました。変更されたら、MethodBを呼び出すすべてのメソッドを変更する必要があります。
別の方法は、例外をexceptionbにカプセル化してから投げることです。例外Bで例外をカプセル化しない場合、ルート例外情報が失われ、例外の元のソースを追跡することが不可能になります。
public void methodb()throws exceptionb {try {methoda(); ...} catch(Exceptiona ex){throw new Exceptionb(ex);}}}上記のコードと同様に、ExceptionBは例外をネストします。例外は例外Bが発生するため、当面は例外を「例外」と呼びます。これにより、例外情報が失われないようになります。
したがって、新しい例外クラスを定義する場合、ネストされた例外を含むようなコンストラクターを提供する必要があります。そして、この「原因の例外」を保存するためのプライベートメンバーがいます。
パブリッククラスの例外bは例外{プライベートスロー可能原因; public exceputionb(string msg、throwable ex){super(msg); this.cause = ex;} public exceptionb(string msg){super(msg);} public excepubleb(this.cause = ex;}}}}}}}}}}}}}}もちろん、printStacktraceメソッドを呼び出す場合、すべての「原因の例外」情報を同時に印刷する必要があります。そのため、すべての例外スタックトレースを表示するには、printStackTraceメソッドをオーバーライドする必要があります。ネストされた例外のスタックトレースが含まれています。
public void printstacktrace(printstrean ps){if(coss == null){super.printstacktrace(ps);} else {ps.println(this); cause.printstacktrace(ps);}}}}ネストされたチェックされた例外クラスソースコードの完全なサポートは次のとおりです。当面はここでnestedexceptionと呼びましょう
public nestedexceptionは例外{プライベートスロー可能な原因; public nestedexception(string msg){super(msg);} public nestedexception(string msg、throwable ex){super(msg); this.cause = ex;} public throwable getause(){return(this.cause == null?this:this -causeage();} public getmessage();} super.getMessage(); shrowable course = getCause(); if(cosse!= null){message = message + ";ネストされた例外は" + course;} printStacktrace(printStream ps){if(getCause == null){super.printstacktrace(ps);} else {ps.println(this); getcause()。printstacktrace(ps);}} public void printstacktrace(printwrite pw){if(getCause()== null){super.printstacktrace(pw);} else {pw.println(this); getcause()。printstacktrace(pw);}} public void printstacktrace(){printstacktrace(system.error);}}}}また、上記のように未チェックの例外クラスを設計する必要があります。 runtimeexceptionを継承するだけです。
4.例外を記録する方法
大規模なアプリケーションシステムとして、システムの操作を容易にするためにシステムの操作を記録するにはログファイルが必要です。システムで発生する例外は、当然ログシステムに記録する必要があります。
public String getPassword(String userID)throws nosuchuserexception {userinfo user = userdao.queryuserbyid(userid); if(user == null){olgger.info( "userId ="+userid); show nosuchuserexception(ユーザー情報はused = "+userid); user.getPassword();}} public void senduserpassword(string userid)throws exception {userinfo user = null; try {user = getPassword(//…..sendmail(); //} catch(nosuchuserexception ex)(nosuchuserexception ex)(logger.error(exping(ex); "+used+エラーが2回記録されていることに気付きました。エラーの原点では、情報レベルでのみ記録します。 SenduserPasswordメソッドでは、例外情報全体も記録します。
著者は、3721に関係なく、このように多くのプロジェクトを記録する例外を記録しており、例外全体が例外に遭遇した場合にのみ記録されます。例外が継続的にカプセル化され、複数回スローされている場合、複数回記録されます。では、例外はどこに記録する必要がありますか?
例外は、最初の場所に記録する必要があります!
正しく処理できない例外をキャッチする必要がある場合は、それを別の例外にカプセル化して投げかけるだけです。記録された例外を再度記録する必要はありません。
例外がキャッチされている場合、この例外を処理できます。例外を記録する必要はありません
public date getDate(string str){date applydate = null; simpledateFormat format = new simpledateFormat( "mm/dd/yyyy"); try {applydate = format.parse(applydatestr);} catch(parseexception ex){//なぜ、フォーマットが間違っているとき、null} returndate;}録音されていない例外または外部システムの例外がキャッチされている場合、例外の詳細を記録する必要があります。
try {…string sql =” select * from userInfo”;ステートメントs = con.createStatement();例外情報を記録する場所と例外情報を記録する方法は、意見の問題かもしれません。一部のシステムでは、例外クラスを記録する例外もあります。新しい例外オブジェクトが生成されると、例外情報が自動的に記録されます。
パブリッククラスBusinessExceptionは例外を拡張します{private void logtrace(){stringbuffer buffer = new Stringbuffer(); buffer.append( "class:"); buffer.append(getClassName()); buffer.Append( "、method:"); buffer.append(getmethname(); 」これは非常に素晴らしいようですが、必然的に例外が繰り返し記録されることにつながります。同時に、「クラスの責任の分配の原則」に違反し、悪いデザインです。記録の例外は、例外クラスの動作に属していないため、記録の例外は特別なロギングシステムによって行われる必要があります。また、異常な記録情報は絶えず変化しています。より豊かな情報を提供するはずの例外を記録しています。これにより、問題を解決するための例外情報に基づいて、問題の根本原因を見つけることができます。
記録の例外について多くのことを議論しましたが、これらに重点を置いていると、開発者がより混乱します。 1つの良い方法は、システムに例外処理フレームワークを提供することです。フレームワークは、例外を記録するかどうか、例外を記録する方法を決定します。決定するのは普通のプログラマー次第ではありません。しかし、何かを知ることは有益です。
5。J2EEプロジェクトでの例外処理
現在、J2EEプロジェクトは通常、論理的に複数の層に分割されています。古典的なものは、プレゼンテーションレイヤー、ビジネスレイヤー、統合レイヤー(データベースアクセスと外部システムアクセスを含む)の3つのレイヤーに分かれています。
J2EEプロジェクトには複雑さがあり、J2EEプロジェクトで例外を処理する際には、いくつかの問題を特に注意する必要があります。
分散アプリケーションを使用する場合、多くのチェックされた例外が発生します。すべてのRMI呼び出し(EJBリモートインターフェイスコールを含む)は、java.rmi.remoteexceptionをスローします。同時に、Remoteexceptionはチェックされた例外です。ビジネスシステムでリモートコールを行うとき、これらのチェックされた例外を処理するために大量のコードを作成する必要があります。 Remoteexceptionが発生すると、これらのチェックされた例外はシステムにとって非常に深刻であり、再試行する可能性はほとんどありません。言い換えれば、Remoteexceptionなどのこれらのひどいチェックされた例外が表示される場合、再試行する必要はありませんが、多くの試みを書く必要があります...それを処理するためのコードをキャッチします。一般的に、下位レベルでRMI呼び出しを行います。 RMIコールがある限り、すべての上位レベルのインターフェイスには、リモートエクセプションをスローする必要があります。 Remoteexceptionに対処する方法は、それを引き続き続けることだからです。これにより、ビジネスインターフェイスが破壊されます。 RemoteexceptionこれらのJ2EEシステムレベルの例外は、当社のビジネスインターフェイスに深刻な影響を与えます。システムの階層化の目的は、システム間の依存性を減らすことであり、各レイヤーの技術的変化は他の層に影響しません。
// public class usersoimplimples usersoa {public userInfo getUserInfo(String userId)throws Remoteexception {//…リモートメソッドコール。////……} publicインターフェイスusermanager {public userInfo getUserInfo(String userid)Throws RemoteException;};}同様に、JDBCアクセスは、sqlexceptionのチェックされた例外をスローします。
システムレベルのチェックされた例外がビジネスシステムに深く侵入することを避けるために、ビジネス方法に関するビジネスシステム独自の例外を定義できます。 SqlexceptionやRemoteexceptionなどの非常に深刻な例外のために、新しいチェックされていない例外を定義し、SqlexceptionとRemoteexceptionを未確認の例外にカプセル化してスローできます。
このシステムレベルの例外を以前の発信者に引き渡して処理する場合、チェックされたビジネス例外を新しく定義し、システムレベルの例外をビジネスレベルの例外に封印してからスローできます。
一般に、統合レイヤーインターフェイスのすべてのメソッドがこの未チェックの例外をスローすることを宣言するように、未確認の例外を定義する必要があります。
public dataChesexceptionExtends runtimeexception {...} public interface userdao {public string getPassword(string userid)throws dataaccessexception;} public class userdaoimplimplite userdao {public string getPassword(string userid)Throws slows dataaccessexception {string sqursionfo '"+userid+"' "; try {…// jdbcはS.executequery(sql);…} catch(sqlexception ex){throw new DataCcesSexception(" Database Query Failed "+sql、ex);}}}}}チェックされたビジネス例外を定義して、ビジネス層インターフェイスのすべての方法がチェックされた例外をスローすることを宣言します。
Public Class BusinessExceptionの例外{…..} public interface usermanager {public userinfo copyuserInfo(userInfo user)throws businessexception {userinfo newuser = null; try {userinfo)user.clone();} catch(cloneNotsupportedexception ex)サポート: "+userInfo.class.getName()、ex);}}} J2EE表現層は非常に薄いレイヤーである必要があり、その主な機能は次のとおりです。ページ要求を取得し、ページパラメーターをPOJOオブジェクトに組み立て、対応するビジネスメソッドを呼び出してから、ページを転送し、対応するビジネスデータをページに表示します。プレゼンテーションレイヤーは、1つの問題に注意を払う必要があります。プレゼンテーションレイヤーは、一部の入力フィールドが空にすることはできないなど、データの正当性を検証する必要があります。
J2EEからページの背景に渡されたすべてのパラメーターは、文字タイプです。数値または日付型のパラメーターの入力が必要な場合、文字値は対応する数値または日付値に変換する必要があります。
表現レイヤーコード検証パラメーターが有効でない場合は、元のページに返され、ユーザーがデータに再入力できるようにし、関連するエラー情報を求めてください。
通常、ページから渡されたパラメーターは数値に変換され、そのようなコードが表示されます
modeandview handlerequest(httpservletrequest request、httpservletresponse応答)スロー例外{string agestr = request.get.getparameter( "age"); int age = integer.parse(agestr); SimpledateFormat format = new SimpledateFormat( "mm/dd/yyyy"); date Birthday = format.parse(birthdaystr);}上記のコードは頻繁に表示される必要がありますが、ユーザーがページから整数に変換できない文字または誤った日付値を入力するとき。
integer.parse()メソッドは、numberformatexceptionを使用して未チェックの例外をスローされます。ただし、この例外は間違いなく致命的な例外ではありません。一般に、ページエントリフィールドにユーザーが入力した値が違法である場合、ユーザーに再入力を促す必要があります。しかし、未確認の例外がスローされると、再試行する機会はありません。このようなコードにより、ページに大量の例外情報が表示されます。私たちのシステムを非常に壊れやすいようにします。
同様に、SimpleDateFormat.Parse()メソッドは、ParSeExceptionの未確認の例外もスローします。
この場合、これらの未確認の例外をキャッチし、ユーザーに再入力を促す必要があります。
modeandview handlerequest(httpservletrequest request、httpservletresponse応答)スロー例外{string agestr = request.getparameter( "age"); string birthdaystr = request.getparameter( "brienth"); int age = 0; date Birthday = null; try {agester.persex(agester); ed){error.reject( "age"、 "は法的整数値ではありません") 'mm/dd/yyy' format ");}}プレゼンテーションレイヤーでは、これらの例外がどのような状況でスローされ、正しい処理を行うか、呼び出し方法が未チェックの例外をスローするかどうかを把握する必要があります。
プレゼンテーションレイヤーでは、一般的に例外をキャッチする必要はありません。呼び出されたビジネス方法によってスローされた例外が2番目の返品値に相当する場合、この場合はキャプチャする必要があります。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。