例外

<本章の目的>例外処理を習得する。いつにも増してボリューム満点でお届け(笑)!

例題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 にして代入しようとして、例外が起こっています。
例外が起こると、そこで実行が中断されて終了します。

java.lang.ArrayIndexOutOfBoundsException: 100

配列の添字 100 は範囲を越えています。

ExceptionTest1.java:5

5 行目で例外が起こりました。

○補足

ArrayIndexOutOfBoundsException ……配列の長さを越えた要素の参照(ランタイム時の例外)
FileNotFoundException ……ファイルが見つからなかった(チェックされる例外)
IllegalArgumentException ……引数が異常な値だった(ランタイム時の例外)
OutOfMemoryError ……メモリが足りなくなった(仮想マシンエラー)


例題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) --

○解説

メソッド呼び出しの中で起きた例外でもキャッチできます。
どこでキャッチされるのか、詳細は後ほど。

例題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) --

○解説

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

○補足

以下はマニュアルより抜粋しています。

public static int parseInt(String s)
  throws NumberFormatException

throws 節で NumberFormatException という例外が投げられるということが表現されています。

例題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
-- Press any key to exit (Input "c" to continue) --
-- Input "exit" to exit from CommandPrompt --

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>

○解説

public FileReader(String fileName)
  throws FileNotFoundException
例外: FileNotFoundException - 指定されたファイルが見つからない場合

public String readLine()
  throws IOException
例外: IOException - 入出力エラーが発生した場合

public void close()
  throws IOException
例外: IOException - 入出力エラーが発生した場合

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

例題13-7 ファイル例外処理で、例題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
-- Press any key to exit (Input "c" to continue) --
-- Input "exit" to exit from CommandPrompt --

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 int read()
  throws IOException
単一の文字を読み込みます。
オーバーライド: クラス 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
-- Press any key to exit (Input "c" to continue) --
-- Input "exit" to exit from CommandPrompt --

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 URL(String spec)
  throws MalformedURLException
String 表現から URL オブジェクトを作成します。
このコンストラクタは、1 番目の引数に null を指定して、引数が 2 つのコンストラクタを呼び出すことと同じです。
パラメータ: spec - URL として解析される String
例外: MalformedURLException - 文字列に指定されたプロトコルが未知である場合
関連項目: URL(java.net.URL, java.lang.String)

public final InputStream openStream()
  throws IOException
この URL への接続を確立し、その接続から読み込みを行うための InputStream を返します。
このメソッドは次のメソッドの短縮形です。
openConnection().getInputStream()
戻り値: URL 接続から入力を読み込むための入力ストリーム
例外: IOException - 入出力例外が発生した場合
関連項目: openConnection(), URLConnection.getInputStream()

○補足

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

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 new IOException();

予約語 throw の後ろに、投げたい例外のインスタンスを書きます。

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 クラスのコンストラクタは
Reader クラスのインスタンスを引数としているのに、
Reader クラスのサブクラスである InputStreamReader クラスのインスタンスを渡していること。
サブクラスのインスタンスをスーパークラスのインスタンスに代入することは可能でしたが、
あえて違うクラスのインスタンスを渡している理由は何か?
そもそも、new 演算子を適用しても Reader クラスのインスタンスだと見なされるのか?

まだ完全解明とはいきませんでしたが(汗)、だいたい理解できましたよね。

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

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

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

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

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

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


戻る / ホーム