Java ランタイム エラーを調べてみる

Feb 26 2023
Java ランタイム エラーの概要 · Java のランタイム エラーとは何ですか? · ランタイム エラー VS コンパイル時エラー · ランタイム エラーの種類 · ランタイム エラーはどのように表示されるか · ランタイム エラーをスローする必要がありますか · スローしないと何が起こるかランタイム例外をキャッチする · ランタイム エラーの例 Java のランタイム エラーとは何ですか? プログラムの実行時に発生するエラーを実行時エラーと呼びます。この種のエラーは、構文に問題がないため、コンパイル時に検出できません。

Java ランタイム エラーの概要

· Java のランタイム エラーとは何ですか?
·実行時エラー VS コンパイル時エラー
·実行時エラーの種類
·実行時エラーはどのように発生するか?
·ランタイム エラーをスローする必要があるか
·ランタイム例外をキャッチしなかった場合に何が起こるか
·ランタイム エラーの例

Java のランタイム エラーとは何ですか?

プログラムの実行時に発生するエラーを実行時エラーと呼びます。この種のエラーは、構文に問題がないため、コンパイル時に検出できません。したがって、プログラムがエラーを出さずに正常にコンパイルされ、「.class」ファイルが作成された場合、ランタイム エラーが発生します。ただし、プログラムは正しく実行されません。これらのエラーは、実行時またはプログラムの実行時に検出されます。

Java コンパイラは実行時エラーを検出しません。これは、Java コンパイラが利用可能なすべての実行時情報を持っていないため、これらのエラーを捕捉する技術がないためです。実行時エラーは、プログラムの実行中にJava 仮想マシン(JVM)によって捕捉されます。

これらの実行時エラーは例外と呼ばれ、プログラムが異常終了し、エラー ステートメントが表示されます。

例外とは、実行時にスローされるエラーです。Java の例外処理テクニックを使用して、これらの実行時エラーを処理できます。例外処理では、プログラマがエラーを生成すると考えたコード部分が try ブロック内に配置され、プログラマは catch ブロック内でエラーをキャッチできます。

実行時エラー VS コンパイル時エラー

コンパイル時エラーは通常、セマンティクスまたは構文に対応するエラーを指します。 実行時エラーとは、実行時のコード実行中に発生するエラーを指します。コードの開発中にコンパイル時エラーを簡単に修正できます。コンパイラは実行時エラーを識別できません。

検出

コンパイラはコードの開発中にコンパイル時エラーを簡単に検出できますが、コンパイラは実行時エラーを簡単に検出できません。したがって、コードの実行中にそれを識別する必要があります。

参照

コンパイル時エラーは通常、セマンティクスまたは構文に対応するエラーを指します。実行時エラーは、コンパイラによって検出されないが、コードの実行中 (実行時) に発生するエラーを指します。

影響

コンパイル時エラーはセマンティクスまたは構文エラーであり、いくつかの構文エラーが検出されるため、コードの実行 (コンパイル) が妨げられます。Weares ランタイム エラーにより、コードが完全に実行されなくなります。

固定

コードの開発中にコンパイル時エラーを簡単に修正できます。コンパイラは実行時エラーを識別できません。ただし、コードを実行して事前にコードを識別した後は修正できます。

ランタイムエラーの種類

プログラムの実行時に直面する可能性のあるランタイム エラーには複数の種類があります。頻繁に発生する実行時エラーを以下に示します。

データ入力エラー : 入出力エラー

ユーザー入力によってアプリケーションが破損する可能性がある方法は無数にあります。

HTML ベースのコメント掲示板で、エンコードされていない小なり記号(<) または大なり記号 (>)を無邪気に送信できるユーザーは、その Web ページの表示機能を完全に台無しにしてしまう可能性があります。同様に、ASCII 形式でのすべての入力を想定して構築されたテキスト処理システムは、絵文字や標準以外の文字入力を受信すると、途中で終了する可能性があります。

さらに悪質なことに、ハッカーが好んで使用する攻撃ベクトルはSQL インジェクションです。SQL インジェクションは、有害な実行可能データベース クエリを、無害な入力フィールド内に隠します。これにより、アプリケーションに障害が発生するだけでなく、データ層全体の制御が放棄される可能性があります。

入力サニタイズ (データ スクラビング)のプロセスは、アプリケーションに入力される可能性のある広範囲のデータを、プログラムが理解できる安全な範囲の値に変換します。このようなライブラリを使用すると、入力サニタイズ失敗によって引き起こされる実行時エラーを軽減するのに役立ちます。

Apache BVal や Hibernate Validator などの一般的な Java フレームワークは、シンプルな注釈ベースの入力クレンジングを実行し、Java ベースのアプリケーションに簡単に統合できます。

ロジックの実装が不十分

コードがコンパイルされたからといって、それが適切に動作するとは限りません。コードには、実行時にアプリケーションの失敗を引き起こす論理的な問題が含まれることがよくあります。

Java には、RuntimeException または未チェック例外と呼ばれる、一般的なコード関連のランタイム エラーのクラスを処理するための組み込み構造が含まれています。Java 17 では、 SDK だけでそのようなエラーが 78 個定義されており、他のプロジェクトやフレームワークでも独自の RuntimeException エラーが定義されています。

  • ランタイム例外
  • ArrayIndexOutOfBoundException
  • ConcurrentModificationException
  • クラスキャスト例外
  • …

少なくとも、すべてのアプリケーションには、考えられるすべての RuntimeException をキャッチし、エラーをログに記録し、アプリケーション全体を中止するのではなく、問題のある実行スレッドを終了させることができる汎用例外ハーネスを含める必要があります。

ランタイムリソースが不十分です

ソフトウェア開発者は、発生するあらゆる種類のランタイム エラーの責任を負うわけではありません。Java のランタイム エラーの多くは、基盤となるインフラストラクチャの問題によって引き起こされるリソース制限に関係しています。例としては、ネットワーク タイムアウト、メモリ不足状態、CPU の過剰使用、プロセッサ上のスレッドをスケジュールできないなどが挙げられます。

リソース関連のランタイム エラーを回避する 1 つの方法は、アプリケーションの CI/CD パイプラインで JMeter や LoadRunner などの負荷テスト ツールを使用することです。これらのツールがパフォーマンス上の問題の可能性を検出した場合、アプリケーションが実稼働環境への展開に向けてパイプラインをさらに進む前にアプリケーションを停止できます。

一部のアプリケーションの負荷は大幅に変化します。たとえば、金融サービス アプリでは、ほとんどの場合負荷が安定していますが、取引日の終わりには非常に混雑する可能性があります。税務サービスは申告期限前に負荷がピークに達する可能性がありますが、それ以外の期間は負荷が比較的少ない場合があります。

DevOps チームは、リソース関連のランタイム エラーを事前に検出して軽減するツールを使用してパフォーマンス メトリクスを監視する必要があります。このようなツールの例には、JDK Flight Recorder やJava Mission Control などがあります。

まったく予測できないワークロードを持つアプリケーションの場合は、クラウドベースの負荷分散テクノロジーを使用して、リソースを弾力的に割り当てます。これにより、リソースの過小割り当てと、高価でめったに使用されないハードウェアを購入するという罠の両方が排除されます。

外部リソース構成

エンタープライズ アプリケーションが孤立したバブルの中に存在することはほとんどありません。通常、これらは NoSQL データベースやリレーショナル システムから Kafka キューや RESTful API まであらゆるものと対話します。残念ながら、アプリケーションが必要な外部システムに接続できない場合、必然的にランタイム エラーが発生します。

呼び出し側プログラムに対応する更新がない状態で次のいずれかの状況が発生した場合、外部リソースによりランタイム エラーが発生する可能性があります。

  • IP アドレスが変更される。
  • 資格情報が変更される。
  • ファイアウォール構成の変更。また
  • 外部システムがメンテナンスのために停止します。

これに関連して、カオス エンジニアリング ツールは、アプリケーションが依存するプロセスをランダムに終了します。このようなツールを使用すると、開発者は、外部システムに障害が発生した場合でも、応答性と回復力を維持できるコードを作成する必要があります。

外部リソースに固有の問題は、開発者が外部リソースを制御できないことですが、外部リソースに障害が発生した場合にアプリケーションがどのように応答するかを制御することはできます。自分が制御していないシステムによって生成される実行時エラーを予測し、それらの外部システムに障害が発生した場合に適切に応答するアプリケーションを作成します。

サードパーティライブラリの脆弱性

重要なエンタープライズ アプリケーションには、ログ記録、監視、入力検証、フォーム処理などの機能を実行するためのサードパーティ ライブラリへの依存関係が多数含まれています。

残念ながら、サードパーティ ライブラリのバグは、展開するアプリケーションのバグになります。広く使用されている Log4j 2 ライブラリの LDAP インジェクトの欠陥により、世界中の JVM がオフラインになったため、これは 2021 年 12 月に Java の世界にとって不快な現実となりました。

ソフトウェアの依存関係によってアプリケーションに実行時エラーが発生する可能性を軽減する 1 つの方法は、 Apache や Eclipse などの組織からの信頼できるライブラリのみを使用することです。

もう 1 つの保護手段は、更新が利用可能になり次第、アプリケーションの依存関係を最新バージョンに定期的に更新することです。

最後に、二次または三次の依存関係 (主な依存関係自体が依存する依存関係) に注意し、それらがもたらすリスクにも注意してください。

ソフトウェア開発の世界では、「完璧」は「完了」の敵です。予期しない実行時エラーの脅威を免れないプログラムはありません。ただし、企業の開発者が考えられる原因についての認識を高め、潜在的な脅威を軽減するための措置を講じれば、実行時エラーが発生する可能性を最小限に抑えるソフトウェアを作成できます。

実行時エラーはどのように表示されますか?

おめでとう!コマンド プロンプトが次のようになっている場合:

これで、プログラムが Java バイトコードに正常にコンパイルされました。これは、コードに構文上の問題がなかったことを意味します。ただし、ファイル名が示すように、このプログラムを実行すると次のようになります。

実行時エラーが発生しました。実行時エラーは通常、コードに論理的に間違った点がある場合に発生します。このドキュメントでは、実行時エラーを読み取り、修正する方法について説明します。

実行時エラーの主な部分は次のとおりです

スレッド「メイン」の例外: この部分は、ほとんどの実行時エラーで表示されます。これは、常に発生するはずの main メソッドで例外が発生したことを示しているだけです。

java.lang.ArrayIndexOutOfBoundsException: 5 : これは発生したエラーです。通常、エラーの名前を見れば、何が起こったのかがわかります。この場合、配列を処理し、配列に割り当てられたスペースを超えてしまうことがわかります。

RunTimeErrors.main(RunTimeErrors.java:10) : これはスタック トレースと呼ばれ、エラーが発生したときに実行されていたメソッドのリストがわかります。

  • RunTimeErrors.main は、このエラーが RunTimeErrors クラスの main メソッド内で発生したことを示しています。
  • RunTimeErrors.java:10 は、この問題が発生したファイルとその行を示します。この場合、これはメインクラスの10行目で発生しました。

システムが単独で実行できない場合にランタイム例外をスローするかどうかを決定するためにチェックを実行する必要がある場合があります。多くの場合、IllegalArgumentExceptionを使用する場合ですが、ほとんどの場合、これはチェックの一部であるため、チェックを実行する必要はありません。 Java が実行する標準のランタイム チェック。

NullPointerException を例として取り上げます。

if(t == null) 
 throw new NullPointerException();

if(t != null) {
  // work with t reference
}

ランタイム例外をキャッチしないとどうなりますか? コンパイラはこれらの例外仕様を強制しないため、RuntimeException が捕捉されずに main() メソッドにまで浸透する可能性は十分に考えられます。この場合に何が起こるかを確認するには、次の例を試してください。

//: exceptions/NeverCaught.java 
// Ignoring RuntimeExceptions. 
// {ThrowsException} 
public class NeverCaught { 
 static void f() { 
 throw new RuntimeException("From f()"); 
 } 
 static void g() { 
 f(); 
 } 
 public static void main(String[] args) { 
 g(); 
 } 
} ///:~

Exception in thread "main" Java.lang.RuntimeException: From f() 
    at NeverCaught.f(NeverCaught.Java:7) 
    at NeverCaught.g(NeverCaught.Java:10) 
    at NeverCaught.main(NeverCaught.Java:13)

コンパイラはすべてのチェックされた例外の処理を慎重に強制するため、コーディングではRuntimeException型の例外(およびサブクラス) のみを無視できることに注意してください。その理由は、RuntimeExceptionは次のようなプログラミング エラーを表すためです。

予想できないエラー。たとえば、制御の外にある null 参照などです。

プログラマとしてコード内でチェックすべきエラー (配列のサイズに注意を払う必要があるArraylndexOutOfBoundsExceptionなど)。ポイント #1 で発生する例外は、多くの場合、ポイントの問題になります。

この場合、例外があることがデバッグ プロセスに役立つため、非常に大きな利点があることがわかります。

Java 例外処理を単一目的のツールとして分類できないことに注目するのは興味深いことです。はい、コードの制御外の力によって発生する厄介なランタイムエラーを処理するように設計されていますが、コンパイラが検出できない特定の種類のプログラミング バグにも不可欠です。

実行時エラーの例

public class Temp {
public static void main(String[] args) {
  Temp t = initT();
  
  t.foo("Hi");
  
 }
 private static Temp initT() {
  return null;
 }
 public void foo(String s) {
  System.out.println(s.toLowerCase());
 }
}

Exception in thread "main" java.lang.NullPointerException
	at Temp.main(Temp.java:7)

このカテゴリには、例外タイプのグループ全体が含まれます。これらは常に Java によって自動的にスローされるため、例外仕様に含める必要はありません。都合の良いことに、これらはRuntimeExceptionという単一の基本クラスの下に置くことですべてグループ化されます。これは継承の完璧な例です。これにより、いくつかの共通の特性と動作を持つ型のファミリーが確立されます。また、メソッドがRuntimeException (またはRuntimeExceptionから継承した型)をスローする可能性があるという例外仕様を記述する必要はありません。これらはチェックされていない例外であるためです。これらはバグを示しているため、通常はRuntimeExceptionをキャッチしません。— それは自動的に処理されます。RuntimeExceptionsをチェックする必要がある場合、コードが非常に煩雑になる可能性があります。通常はRuntimeExceptions をキャッチしませんが、独自のパッケージではRuntimeExceptionsの一部をスローすることを選択する場合があります。

最も一般的なランタイム例外を参照してください。

楽しく学習してください

Mouad Oumous Java WhatsApp グループに参加する

Mouad Oumous Telegram チャンネルに参加する

フォローして私たちの出版物をサポートしてください

Spring Boot を使用した GraphQL 最も一般的な Java ランタイム エラー Spring Boot の開始: 初心者向けの包括的なチュートリアル 生活の質を向上させるための 10 のシンプルだが効果的な方法 最もよく聞かれる Java8 ストリーム ベースの面接の質問 — 最終回 本 を書くことで 300 ドルを稼ぐ2 日で — Java における例外チェーンとは何か |解説します。例外処理 データベース統合を使用した単純な Quarkus プロジェクトの作成方法