例外

<概要>例外処理の概要を学びます。いつにも増してボリューム満点でお届け(笑)!

例題13-1 例外を発生させる。

○プログラム

public class ExceptionTest1{
  public static void main(String[] args){
    int[] myarray=new int[3];
    System.out.println("代入します");
    myarray[100]=0;
    System.out.println("代入しました");
    System.out.println("終了します");
  }
}


○実行結果

D:\atsushi\Java\List13-1>java ExceptionTest1
代入します
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
at ExceptionTest1.main(ExceptionTest1.java:5)
-- Press any key to exit (Input "c" to continue) --

○解説

3 行目で作られた配列 myarray は、長さが 3 しかありません。
4 行目は“代入します”という文字列を表示しています。
5 行目で添字を 100 にして代入しようとして、例外が発生しています。
例外が起こると、そこで実行が中断されて終了します。

コンパイラによるメッセージの意味は以下のようになっています。

Exception in thread "main"
 → main スレッドで例外が発生しました。

java.lang.ArrayIndexOutOfBoundsException: 100
 → 配列の添字 100 は有効な範囲を越えています。

ExceptionTest1.java:5
 → 5 行目で例外が発生しました。

例題13-2 例外処理を追加する。

○プログラム

public class ExceptionTest2{
  public static void main(String[] args){
    int[] myarray=new int[3];
    try{
      System.out.println("代入します");
      myarray[100]=0;
      System.out.println("代入しました");
    }catch(ArrayIndexOutOfBoundsException e){
      System.out.println("代入できませんでした");
      System.out.println("例外は"+e+"です");
    }
    System.out.println("終了します");
  }
}


○実行結果

D:\atsushi\Java\List13-2>java ExceptionTest2
代入します
代入できませんでした
例外はjava.lang.ArrayIndexOutOfBoundsException: 100です
終了します
-- Press any key to exit (Input "c" to continue) --

○解説

今度は例外が起こっても途中で終了しません。
6 行目 myarray[100]=0; で例外が発生すると、
8 行目 }catch(ArrayIndexOutOfBoundsException e){ で受け止められ、
catch ブロックの中の文が実行されます。
chatch ブロックを抜けると、try 文全体が終わります。
例外処理が終わると、通常の処理に戻ります。

例外が起きたことを「例外が投げられた」または「例外が throw された」と言います。
また、例外処理を行うことを「例外を受ける」または「例外を catch する」と言います。

○補足

ArrayIndexOutOfBoundsException はクラスの名前です。
通常「例外 ArrayIndexOutOfBoundsException を投げる」と言いますが、
実際に投げられているのは ArrayIndexOutOfBoundsException クラスではなく、インスタンスです。
catch 節に書かれている e は、そのインスタンスを受け取る変数です。
ちょうどメソッドの仮引数の役割と似ていますね。

例題13-3 メソッド呼び出しの中で例外が発生したらどうなる?

○プログラム

public class ExceptionTest3{
  public static void main(String[] args){
    int[] myarray=new int[3];
    try{
      System.out.println("代入します");
      myAssign(myarray,100,0);
      System.out.println("代入しました");
    }catch(ArrayIndexOutOfBoundsException e){
      System.out.println("代入できませんでした");
      System.out.println("例外は"+e+"です");
    }
    System.out.println("終了します");
  }
  static void myAssign(int[] arr,int index,int value){
    System.out.println("myAssignに来ました");
    arr[index]=value;
    System.out.println("myAssignから帰ります");
  }
}


○実行結果

D:\atsushi\Java\List13-3>java ExceptionTest3
代入します
myAssignに来ました
代入できませんでした
例外はjava.lang.ArrayIndexOutOfBoundsException: 100です
終了します
-- Press any key to exit (Input "c" to continue) --

○解説

メソッド呼び出しの中で発生した例外でもキャッチできます。
どこでキャッチされるのかが重要なのですが、詳しくは「例外2」で解説します。

例題13-4 数への変換で起こる例外を処理する。

○プログラム

public class NumberTest{
  public static void main(String[] args){
    try{
      String numstr="XYZ";
      int val=Integer.parseInt(numstr);
      System.out.println("val="+val);
    }catch(NumberFormatException e){
      System.out.println("例外:"+e);
    }
  }
}


○実行結果

D:\atsushi\Java\List13-4>java NumberTest
例外:java.lang.NumberFormatException: For input string: "XYZ"
-- Press any key to exit (Input "c" to continue) --

○解説

あるメソッドが投げる例外は定義されています。
マニュアルより Integer クラスの parseInt メソッドの定義を見てみましょう。

public static int parseInt(String s) throws NumberFormatException  //Integer クラス
例外: NumberFormatException - 文字列が構文解析可能な整数型を含まない場合

throws の後ろに書かれたクラスが投げられる例外になります。
throws は「例外2」で詳しく解説します。

例題13-5 0 で割った場合に発生する例外を処理する。

○プログラム

public class ZeroTest{
  public static void main(String[] args){
    try{
      System.out.println("int val=1/0");
      int val=1/0;
      System.out.println("val="+val);
    }catch(ArithmeticException e){
      System.out.println("例外:"+e);
    }
    System.out.println("");
    try{
      System.out.println("double val=1.0/0.0");
      double val=1.0/0.0;
      System.out.println("val="+val);
    }catch(ArithmeticException e){
      System.out.println("例外:"+e);
    }
      System.out.println("");
    try{
      System.out.println("double val=1/0");
      double val=1/0;
      System.out.println("val="+val);
    }catch(ArithmeticException e){
      System.out.println("例外:"+e);
    }
  }
}


○実行結果

D:\atsushi\Java\P87>java ZeroTest
int val=1/0
例外:java.lang.ArithmeticException: / by zero

double val=1.0/0.0
val=Infinity

double val=1/0
例外:java.lang.ArithmeticException: / by zero
-- Press any key to exit (Input "c" to continue) --

○解説

整数の割り算において、0 で割ると ArithmeticException という例外がスローされます。
しかし、浮動小数点数の割り算では例外がスローされることはありません。

例題13-6 ファイル操作で起こる例外を処理する。

○プログラム

import java.io.*;

public class DisplayFile{
  public static void main(String[] args){
    for(int i=0;i<args.length;i++){
      System.out.println("ファイル名:"+args[i]+"=====");
      try{
        BufferedReader reader=new BufferedReader(new FileReader(args[i]));
        while(true){
          String line=reader.readLine();
          if(line==null){
            break;
          }
          System.out.println(line);
        }
        reader.close();
      }catch(FileNotFoundException e){
        System.out.println("ファイルが見つかりません:"+e);
      }catch(IOException e){
        System.out.println("I/Oエラーです:"+e);
      }
    }
  }
}


○実行例

D:\atsushi\Java\List13-5>java DisplayFile DisplayFile.java nofile
ファイル名:DisplayFile.java=====
import java.io.*;

public class DisplayFile{
  public static void main(String[] args){
    for(int i=0;i<args.length;i++){
      System.out.println("ファイル名:"+args[i]+"=====");
      try{
        BufferedReader reader=new BufferedReader(new FileReader(args[i]));
        while(true){
          String line=reader.readLine();
          if(line==null){
            break;
          }
          System.out.println(line);
        }
        reader.close();
      }catch(FileNotFoundException e){
        System.out.println("ファイルが見つかりません:"+e);
      }catch(IOException e){
        System.out.println("I/Oエラーです:"+e);
      }
    }
  }
}
ファイル名:nofile=====
ファイルが見つかりません:java.io.FileNotFoundException: nofile (指定されたファイルが見つかりません。)

D:\atsushi\Java\List13-5>

○解説

1. import java.io.*;

FileReader クラスと BufferedReader クラスは java.io というパッケージに含まれているので、
これらを使うためには java.io パッケージを取り込まなければなりません。
プログラムで表現すれば import という予約語に続いて取り込みたいパッケージの名前を書くだけです。
* は「そのパッケージに含まれる全てのクラスを取り込む」という意味です。
詳しくは「パッケージ」で解説します。

public class FileReader extends InputStreamReader  //java.io パッケージ
 文字ファイルからの読み込みのための簡易クラスです

public FileReader(String fileName) throws FileNotFoundException  //FileReader クラス ← java.io パッケージ
 読み込み元のファイルの名前を指定して、新規 FileReader を作成します。
パラメータ: fileName - 読み込み元のファイルの名前
例外: FileNotFoundException - 指定されたファイルが見つからない場合

public class BufferedReader extends Reader  //java.io パッケージ
 文字、配列、行をバッファリングすることによって、文字型入力ストリームからテキストを効率良く読み込みます。

public String readLine() throws IOException  //BufferedReader クラス ← java.io パッケージ
 1 行のテキストを読み込みます。
 1 行の終端は、改行 ('\n') か、復帰 ('\r')、または復行とそれに続く改行のどれかで認識されます。
戻り値: 行の内容を含む文字列、ただし行の終端文字は含めない。ストリームの終わりに達している場合は null
例外: IOException - 入出力エラーが発生した場合

public void close() throws IOException  //BufferedReader クラス ← java.io パッケージ
 ストリームを閉じます。
定義:クラス Reader 内の close
例外: IOException - 入出力エラーが発生した場合

FileReader を直接使うのではなく、BufferedReader を介すと、
データを読み込む際にバッファリングが行われて、スピードが速くなります。

例題13-7 FileReader クラスを直接使ったファイル操作(例題13-6の別プログラム)。

○プログラム

import java.io.*;

public class FileTest{
  public static void main(String[] args){
    for(int i=0;i<args.length;i++){
      System.out.println("ファイル名:"+args[i]+"=====");
      try{
        FileReader reader=new FileReader(args[i]);
        while(true){
          int c=reader.read();
          if(c==-1){
            break;
          }
          System.out.print((char)c);
        }
        System.out.println("");
        reader.close();
      }catch(FileNotFoundException e){
        System.out.println("ファイルが見つかりません:"+e);
      }catch(IOException e){
        System.out.println("I/Oエラーです:"+e);
      }
    }
  }
}


○実行例

D:\atsushi\Java\P87-2>java FileTest FileTest.java nofile
ファイル名:FileTest.java=====
import java.io.*;

public class FileTest{
  public static void main(String[] args){
    for(int i=0;i<args.length;i++){
      System.out.println("ファイル名:"+args[i]+"=====");
      try{
        FileReader reader=new FileReader(args[i]);
        while(true){
          int c=reader.read();
          if(c==-1){
            break;
          }
          System.out.print((char)c);
        }
        System.out.println("");
        reader.close();
      }catch(FileNotFoundException e){
        System.out.println("ファイルが見つかりません:"+e);
      }catch(IOException e){
        System.out.println("I/Oエラーです:"+e);
      }
    }
  }
}
ファイル名:nofile=====
ファイルが見つかりません:java.io.FileNotFoundException: nofile (指定されたファイルが見つかりません。)

D:\atsushi\Java\P87-2>

○解説

public class InputStreamReader extends Reader  //java.io パッケージ
 InputStreamReader はバイトストリームから文字ストリームへの橋渡しの役目を持ちます。

public int read() throws IOException  //InputStreamReader クラス ← java.io パッケージ
 単一の文字を読み込みます。
オーバーライド: クラス Reader 内の read
戻り値: 読み込まれた文字。ストリームの終わりに達した場合は -1
例外: IOException - 入出力エラーが発生した場合

例題13-8 ホームページのHTMLを表示する。

○プログラム

import java.io.*;
import java.net.*;

public class DisplayURL{
  public static void main(String[] args){
    for(int i=0;i<args.length;i++){
      System.out.println("URL= "+args[i]);
      try{
        URL url=new URL(args[i]);
        BufferedReader reader=new BufferedReader(new InputStreamReader(url.openStream()));
        while(true){
          String line=reader.readLine();
          if(line==null){
            break;
          }
          System.out.println(line);
        }
        reader.close();
      }catch(MalformedURLException e){
        System.out.println("URLの形式が誤っています:"+e);
      }catch(IOException e){
        System.out.println("I/Oエラーです:"+e);
      }
    }
  }
}


○実行例

D:\atsushi\Java\List13-6>java DisplayURL http:/
URL= http:/
I/Oエラーです:java.net.ConnectException: Connection refused: connect

D:\atsushi\Java\List13-6>java DisplayURL abcdef
URL= abcdef
URLの形式が誤っています:java.net.MalformedURLException: no protocol: abcdef

D:\atsushi\Java\List13-6>java DisplayURL http://www13.plala.or.jp/kymats/
URL= http://www13.plala.or.jp/kymats/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<META name="GENERATOR" content="IBM WebSphere Studio Homepage Builder Version 8.0.0.0 for Windows">
<META http-equiv="Content-Style-Type" content="text/css">
<TITLE>Windowsプログラミング研究所</TITLE>
……以下省略……

○注意

あらかじめインターネットに接続しておいて下さい。

○解説

public final class URL extends Object implements Serializable  //java.net パッケージ
 URL クラスは、World Wide Web 上の「リソース」を指すポインタである URL (Uniform Resource Locator) を表します。

public URL(String spec) throws MalformedURLException  //URL クラス ← java.net パッケージ
 String 表現から URL オブジェクトを作成します。
パラメータ: spec - URL として解析される String
例外: MalformedURLException - 文字列に指定されたプロトコルが未知である場合

public final InputStream openStream() throws IOException  //URL クラス ← java.net パッケージ
 この URL への接続を確立し、その接続から読み込みを行うための InputStream を返します。
戻り値: URL 接続から入力を読み込むための入力ストリーム
例外: IOException - 入出力例外が発生した場合

○補足

インターネットに接続していない場合の実行結果は以下のようになります。

D:\atsushi\Java\List13-6>java DisplayURL http://www13.plala.or.jp/kymats/
URL= http://www13.plala.or.jp/kymats/
I/Oエラーです:java.net.UnknownHostException: www13.plala.or.jp

D:\atsushi\Java\List13-6>

自分で例外を投げる

予約語 throw の後ろに、投げたい例外のインスタンスを書きます。
例えば、IOException を投げたい場合は次のように書きます。

throw new IOException();

*=*=*=*=*=*=*=*=*=*= 多態性を利用したインスタンス作成 *=*=*=*=*=*=*=*=*=*=

BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));

キーボード入力を受け取る BufferedReader クラスのインスタンスを作成しています。
いまこそ、この謎の一文を理解するときがやってきたっ(笑)!
マニュアルを読めばだいだいのことは分かりますよね。

public class BufferedReader extends Reader
コンストラクタ:public BufferedReader(Reader in)

public class InputStreamReader extends Reader
コンストラクタ:public InputStreamReader(InputStream in)

public final class System extends Object
フィールド:public static final InputStream in

先ずは BufferedReader クラスのインスタンスを作成しようとしています。
BufferedReader クラスのコンストラクタが求めているのは Reader クラスのインスタンスです。
その引数として作成しようとしているのが InputStreamReader クラスのインスタンスです。
InputStreamReader クラスは Reader クラスのサブクラスですから、
「多態性」のときに学んだように、Reader クラスの変数に代入することが出来ます。
したがって、BufferedReader クラスのコンストラクタが求めている
Reader クラスのインスタンスを無事渡せたことになります。
次に、InputStreamReader クラスのコンストラクタが求めているのは InputStream クラスのインスタンスです。
その引数として渡しているのが System クラスのクラスフィールド in です。
in は、InputStream クラスの変数ですから、
文句なしに InputStreamReader クラスのコンストラクタが求めているものと一致します。

これにて一件落着(笑)!
以下の文も同様に解析できます。

BufferedReader reader=new BufferedReader(new FileReader(args[i]));

ファイル入力を受け取る BufferedReader クラスのインスタンスを作成しています。

public class FileReader extends InputStreamReader
コンストラクタ:public FileReader(String fileName)

BufferedReader クラスのインスタンスが求めているのは Reader クラスのインスタンスでしたね。
FileReader クラスは InputStreamReader クラスを継承しています。
そして、InputStreamReader クラスは Reader クラスを継承しています。

BufferedReader reader=new BufferedReader(new InputStreamReader(url.openStream()));

HTMLファイル入力を受け取る BufferedReader クラスのインスタンスを作成しています。

public final class URL extends Object
メソッド:public final InputStream openStream()


戻る / ホーム