例外はプログラムの一部のエラーですが、すべてのエラーが異常なわけではなく、エラーを回避できる場合もあります。
たとえば、コードにセミコロンがない場合、エラーはjava.lang.Errorとなり、System.out.println(11/0)を使用すると、0で除算されます。 、java.lang.ArithmeticExceptionの例外がスローされます。
異常には多くの理由があり、通常は次のカテゴリが含まれます。
- ユーザーが不正なデータを入力しました。
- 開くファイルが存在しません。
- ネットワーク通信中に接続が中断されたか、JVMメモリーがオーバーフローしました。
これらの例外には、ユーザーエラー、プログラムエラー、および物理エラーが原因で発生するものがあります。-
Javaの例外処理を理解するには、我々は、例外は、次の3種類を把握する必要があり、それがどのように動作するかです:
- チェック可能な異常:最も代表的なチェック可能な異常は、ユーザーのエラーや問題が原因で発生し、プログラマーが予測できないものです。たとえば、存在しないファイルを開こうとすると、例外が発生しますが、これらの例外はコンパイル時には無視できません。
- 実行時例外:実行時例外は、プログラマーが回避できる例外です。チェック例外とは対照的に、ランタイム例外はコンパイル時に無視できます。
- エラー:エラーは例外ではなく、プログラマーが制御できない問題です。エラーは通常、コードでは無視されます。たとえば、スタックがオーバーフローするとエラーが発生し、コンパイル中にエラーが検出されません。
Java例外
Javaには、常に例外を使用してエラーを示す例外処理メカニズムが組み込まれています。
それは継承関係から見ることができます:ThrowableはObjectから継承する異常なシステムのルートです。Throwableには、エラーと例外の2つのシステムがあります。エラーは重大なエラーを表し、プログラムは一般的に役に立ちません。たとえば、次のようになります。
- OutOfMemoryError:メモリ不足
- NoClassDefFoundError:クラスをロードできません
- StackOverflowError:スタックオーバーフロー
と例外は実行時エラーであり、キャッチして処理できます。
一部の例外はアプリケーションの論理処理の一部であり、キャッチして処理する必要があります。たとえば、次のとおりです。 - NumberFormatException:数値型のフォーマットエラー
- FileNotFoundException:ファイルが見つかりません
- SocketException:ネットワークの読み取りに失敗しました
一部の例外は、プログラムロジックの誤ったプログラミングが原因で発生するため、プログラム自体を修復する必要があります。たとえば、次のとおりです。
- NullPointerException:nullオブジェクトのメソッドまたはフィールドを呼び出す
- IndexOutOfBoundsException:配列のインデックスが範囲外です
例外は2つのカテゴリに分類されます:1. RuntimeException
とそのサブクラス;
2. Non-RuntimeException(IOException、ReflectiveOperationExceptionなどを含む)。
Javaの規定:
キャッチする必要のある例外には、Exceptionとそのサブクラスが含まれますが、RuntimeExceptionとそのサブクラスは含まれません。このタイプの例外は、チェック済み例外と呼ばれます。
キャッチする必要のない例外には、Errorとそのサブクラス、RuntimeExceptionとそのサブクラスがあります。
次の表に、Javaの未チェックの例外を示します。
次の表に、java.langパッケージで定義されているJavaのチェック済み例外クラスを示します。
次のリストは、Throwableクラスの主なメソッドです。
例外をキャッチ
例外をキャッチするには、try ... catchステートメントを使用し、例外が発生する可能性のあるコードをtry {...}に配置してから、catchを使用して対応するExceptionとそのサブクラスをキャッチします。
// try...catch
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
byte[] bs = toGBK("中文");
System.out.println(Arrays.toString(bs));
}
static byte[] toGBK(String s) {
try {
// 用指定编码转换String为byte[]:
return s.getBytes("GBK");
} catch (UnsupportedEncodingException e) {
// 如果系统不支持GBK编码,会捕获到UnsupportedEncodingException:
System.out.println(e); // 打印异常信息
return s.getBytes(); // 尝试使用用默认编码
}
}
}
次の例では、2つの要素を持つ配列を宣言しています。コードが配列の3番目の要素にアクセスしようとすると、例外がスローされます。
// 文件名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
tryコードブロックの後に複数のcatchコードブロックが続く場合は、複数キャプチャと呼ばれます。
複数のキャプチャブロックの構文は次のとおりです。
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}
最後に声明
Javaのtry ... catchメカニズムもfinallyステートメントを提供し、finallyステートメントブロックはエラーの有無にかかわらず実行されることが保証されています。
public static void main(String[] args) {
try {
process1();
process2();
process3();
} catch (UnsupportedEncodingException e) {
System.out.println("Bad encoding");
} catch (IOException e) {
System.out.println("IO error");
} finally {
System.out.println("END");
}
}
finallyにはいくつかの特徴があることに注意してください:finally
ステートメントは不要であり、書き込むことも書き込まないこともできます
。
例外が発生しない場合は、通常どおりtry {…}ステートメントブロックを実行してから、最後に実行します。例外が発生すると、try {…}ステートメントブロックの実行が中断され、一致するcatchステートメントブロックの実行がスキップされ、最後に最後の実行が実行されます。
最終的には、いくつかのコードを実行する必要があることを確認するために使用されていることがわかります。
場合によっては、キャッチがなく、試してみてください...最終的には構造化します。たとえば
void process(String file) throws IOException {
try {
...
} finally {
System.out.println("END");
}
}
アサーションを使用する
アサーションは、プログラムをデバッグする方法です。Javaでは、assertキーワードを使用してアサーションを実装します。
public static void main(String[] args) {
double x = Math.abs(-123.45);
assert x >= 0;
System.out.println(x);
}
ステートメントassert x> = 0;はアサーションであり、アサーション条件x> = 0はtrueであることが期待されています。計算結果がfalseの場合、アサーションは失敗し、AssertionErrorがスローされます。
Javaアサーションの特徴は次のとおりです。AssertionErrorは、アサーションが失敗するとスローされ、プログラムが終了します。したがって、アサーションは回復可能なプログラムエラーには使用できません。開発とテストにのみ使用してください。
JDKロギング
Java標準ライブラリには、直接使用できる組み込みのロギングパッケージjava.util.loggingがあります。まず簡単な例を見てみましょう:
// logging
import java.util.logging.Level;
import java.util.logging.Logger;
public class Hello {
public static void main(String[] args) {
Logger logger = Logger.getGlobal();
logger.info("start process...");
logger.warning("memory is running out...");
logger.fine("ignored.");
logger.severe("process will be terminated...");
}
}
运行上述代码,得到类似如下的输出:
Mar 02, 2019 6:32:13 PM Hello main
INFO: start process...
Mar 02, 2019 6:32:13 PM Hello main
WARNING: memory is running out...
Mar 02, 2019 6:32:13 PM Hello main
SEVERE: process will be terminated...
JDKのロギングは、重大から正常までの7つのログレベルを定義します。
- 厳しい
- 警告
- INFO
- 設定
- 良い
- FINER
- FINEST
デフォルトのレベルはINFOですので、そのため、ログのレベル以下の情報は印刷されません。ログレベルを使用する利点は、レベルを調整することで、多くのデバッグ関連のログ出力をマスクできることです。
Java標準ライブラリでの組み込みのLoggingの使用には、次の制限があります
。Loggingシステムは構成ファイルを読み取り、JVMの開始時に初期化を完了します。main()メソッドが開始されると、
構成は変更できません。構成は便利ではなく、JVMの開始時にパラメーターを渡す必要があります
-Djava.util.logging.config.file=<config-file-name>
したがって、Java標準ライブラリに組み込まれているロギングはあまり広く使用されていません。
コモンズロギング
Commons Loggingは、Apacheによって作成されたロギングモジュールであるサードパーティのロギングライブラリです。
Commons Loggingの特徴は、さまざまなロギングシステムに接続でき、ロギングシステムを構成ファイルで指定できることです。デフォルトでは、Commons Logginは自動的にLog4jを検索して使用します(Log4jはもう1つの一般的なロギングシステムです)Log4jが見つからない場合は、JDKロギングが使用されます。
Commons Loggingはサードパーティによって提供されるライブラリであるため、最初にダウンロードする必要があります。ダウンロードした後、解凍してcommons-logging-1.2.jarファイルを見つけ、JavaソースコードMain.javaをディレクトリに配置します。
コンパイルコマンドは次のとおりです。
javac -cp commons-logging-1.2.jar Main.java
このMain.classを実行するには、javaコマンドを使用します。クラスパスも指定する必要があります。コマンドは次のとおりです。
java -cp .;commons-logging-1.2.jar Main
Commons Loggingを使用するには、2つのクラスを処理するだけでよく、2つのステップしかありません。
最初のステップはLogFactoryを介してLogクラスのインスタンスを取得することで、2番目のステップはLogインスタンスメソッドを使用してログを記録することです。
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class Main {
public static void main(String[] args) {
Log log = LogFactory.getLog(Main.class);
log.info("start...");
log.warn("end.");
}
}
Mar 02, 2019 7:15:31 PM Main main
INFO: start...
Mar 02, 2019 7:15:31 PM Main main
WARNING: end.
Commons Loggingは6つのログレベルを定義します。
- 致命的
- エラー
- 警告
- INFO
- デバッグ
- TRACEの
デフォルトレベルはINFOです。
Log4j
Log4jは非常に人気のあるロギングフレームワークであり、最新バージョンは2.xです。
Log4jはコンポーネント設計のログシステムであり、そのアーキテクチャはおおよそ次のとおりです。
Log4jを使用してログを出力すると、Log4jは自動的に同じログを異なるAppenderを介して異なる宛先に出力します。たとえば、次のとおりです。
- コンソール:画面への出力。
- file:ファイルに出力します。
- ソケット:ネットワークを介してリモートコンピュータに出力します。
- jdbc:データベースへ
の出力ログを出力するプロセスでは、Filterを使用して、出力する必要があるログと出力する必要がないログをフィルタリングします。たとえば、ERRORレベルのログのみが出力されます。
最後に、レイアウトを介してログ情報をフォーマットします。たとえば、日付、時刻、メソッド名、その他の情報を自動的に追加します。
上記の構造は複雑ですが、実際に使用する場合は、Log4j APIを気にする必要はありませんが、構成ファイルを使用して構成します。
XML構成を例にとると、Log4jを使用する場合、クラスパスにlog4j2.xmlファイルを配置して、Log4jが構成ファイルを読み取り、構成に従ってログを出力できるようにします。次に、構成ファイルの例を示します。
<?xml version="1.0" encoding="UTF-8"?><Configuration>
<Properties>
<!-- 定义日志格式 -->
<Property name="log.pattern">%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n</Property>
<!-- 定义文件名变量 -->
<Property name="file.err.filename">log/err.log</Property>
<Property name="file.err.pattern">log/err.%i.log.gz</Property>
</Properties>
<!-- 定义Appender,即目的地 -->
<Appenders>
<!-- 定义输出到屏幕 -->
<Console name="console" target="SYSTEM_OUT">
<!-- 日志格式引用上面定义的log.pattern -->
<PatternLayout pattern="${log.pattern}" />
</Console>
<!-- 定义输出到文件,文件名引用上面定义的file.err.filename -->
<RollingFile name="err" bufferedIO="true" fileName="${file.err.filename}" filePattern="${file.err.pattern}">
<PatternLayout pattern="${log.pattern}" />
<Policies>
<!-- 根据文件大小自动切割日志 -->
<SizeBasedTriggeringPolicy size="1 MB" />
</Policies>
<!-- 保留最近10份 -->
<DefaultRolloverStrategy max="10" />
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<!-- 对info级别的日志,输出到console -->
<AppenderRef ref="console" level="info" />
<!-- 对error级别的日志,输出到err,即上面定义的RollingFile -->
<AppenderRef ref="err" level="error" />
</Root>
</Loggers></Configuration>
Log4jの設定は面倒ですが、一度設定すると、非常に便利です。上記の構成ファイルの場合、すべてのINFOレベルのログは自動的に画面に出力され、ERRORレベルのログはファイルと同様に画面にも出力されます。また、ログファイルが指定されたサイズ(1 MB)に達すると、Log4jは自動的に新しいログファイルを切り取り、最大10のコピーを保持します。
Log4jはサードパーティのライブラリでもあるため、構成ファイルを用意するだけでは不十分です。Log4jをダウンロードして解凍し、次の3つのjarパッケージをクラスパスに配置する必要があります。
- log4j-api-2.x.jar
- log4j-core-2.x.jar
- log4j-jcl-2.x.jar
Commons Loggingは自動的にLog4jを検出して使用するため、前のセクションでダウンロードしたcommons-logging-1.2.jarをクラスパスに配置します。
ログを印刷するには、コードを変更せずに、Commons Loggingに従ってログを書き込むだけで、次のようなLog4jのログ出力を取得できます。
03-03 12:09:45.880 [main] INFO com.itranswarp.learnjava.MainStart process...