[小西ホームページ]   [目次・索引]   [前の授業]

情報処理技法(Javaプログラミング)I 第14回

目次
索引

数と文字列

文字列から数への変換

Javaでは、整数100と文字列"100"は区別されます。 整数を文字列とみなしたければ、整数を文字列に変換すればよいです。 逆に、文字列を整数とみなしたければ、文字列を整数に変換すればよいです。

実数についても同様に、実数1.23と文字列"1.23"は区別されます。 実数を文字列とみなしたければ、実数を文字列に変換し、文字列を実数とみなしたければ、文字列を実数に変換します。

文字列から整数への変換は、式

Integer.parseInt(文字列)

で行います。

次のプログラムは、文字列"100"を整数に変換してから出力します。 ただし、そのまま出力すると、整数なのか文字列なのか分からないので、自分自身をプラスで結んで、整数なのか文字列なのか分かるようにします。

StringIntegerTest.java
/*  1*/ class StringIntegerTest { // 文字列から整数への変換
/*  2*/     public static void main (String[] args) {
/*  3*/         String str = "100"; // 文字列
/*  4*/         int x = Integer.parseInt(str); // 整数に変換
/*  5*/         System.out.println(x + x); // 整数の足し算
/*  6*/     }
/*  7*/ }
コンソール
200

Completed with exit code: 0

文字列から実数への変換は、式

Double.parseDouble(文字列)

で行います。

次のプログラムは、文字列"1.23"を実数に変換してから出力します。 整数の場合と同様に、自分自身をプラスで結んで、実数なのか文字列なのか分かるようにします。

StringDoubleTest.java
/*  1*/ class StringDoubleTest { // 文字列から実数への変換
/*  2*/     public static void main (String[] args) {
/*  3*/         String str = "1.23"; // 文字列
/*  4*/         double d = Double.parseDouble(str); // 実数に変換
/*  5*/         System.out.println(d + d); // 実数の足し算
/*  6*/     }
/*  7*/ }
コンソール
2.46

Completed with exit code: 0

ここで、整数を入力するときに使う式

Integer.parseInt(br.readLine())

を思い出してください。 この式の仕組みは、 br.readLine() が入力された文字列で、それを Integer.parseInt( 文字列 ) で整数に変換しているのです。

実数を入力するときに使う式

Double.parseDouble(br.readLine())

についても同様で、 br.readLine() が入力された文字列で、それを Double.parseDouble( 文字列 ) で実数に変換しているのです。

数から文字列への変換

文字列から数への変換を行ったので、次に逆の変換をします。 整数から文字列への変換は、式

String.valueOf(整数)

で行います。

次のプログラムは、整数100を文字列に変換してから出力します。 自分自身をプラスで結んで、整数なのか文字列なのか分かるようにします。

IntegerStringTest.java
/*  1*/ class IntegerStringTest { // 整数から文字列への変換
/*  2*/     public static void main (String[] args) {
/*  3*/         int x = 100; // 整数
/*  4*/         String str = String.valueOf(x); // 文字列に変換
/*  5*/         System.out.println(str + str); // 文字列の連結
/*  6*/     }
/*  7*/ }
コンソール
100100

Completed with exit code: 0

実数から文字列への変換も、式

String.valueOf(実数)

で行います。

次のプログラムは、実数1.23を文字列に変換してから出力します。 自分自身をプラスで結んで、実数なのか文字列なのか分かるようにします。

DoubleStringTest.java
/*  1*/ class DoubleStringTest { // 実数から文字列への変換
/*  2*/     public static void main (String[] args) {
/*  3*/         double d = 1.23; // 実数
/*  4*/         String str = String.valueOf(d); // 文字列に変換
/*  5*/         System.out.println(str + str); // 文字列の連結
/*  6*/     }
/*  7*/ }
コンソール
1.231.23

Completed with exit code: 0

数から文字列への変換には、「裏技」があります。 「文字列の連結は、一方だけが文字列ならば、他方を文字列に変換してから連結する」という決まりを利用すると、式、

"" + 

で、数から文字列への変換となるのです。 「裏技」なので、自分でプログラムを書くときは、使わないほうがよいですが、他人のプログラムを読むときは、理解できるようにしてください。


例外

エラーと例外

一般的に、プログラムの間違いは エラー error )とよばれます。 プログラムの書き方が間違っていて、コンパイルや実行ができないエラーもありますが、プログラムを実行している途中で発生するエラーもあります。 Javaでは、そのようなエラーを 例外 exception )とよびます。

例えば、整数はゼロで割ることができないので、ゼロで割ると例外が発生します。

ExceptionTest1.java
/*  1*/ class ExceptionTest1 { // 例外のテスト1
/*  2*/     public static void main (String[] args) {
/*  3*/         System.out.println(100 / 0); // ゼロで割る
/*  4*/     }
/*  5*/ }
コンソール
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at ExceptionTest1.main(ExceptionTest1.java:3)

Completed with exit code: 1

エラー・メッセージにあるArithmeticExceptionは、算術的な例外という意味です。

また、要素数5の配列 a の添字は0から4までなので、 a [5]にアクセスしようとすると例外が発生します。

ExceptionTest2.java
/*  1*/ class ExceptionTest2 { // 例外のテスト2
/*  2*/     public static void main (String[] args) {
/*  3*/         int[] a = {10, 11, 12, 13, 14}; // 要素数5
/*  4*/         System.out.println(a[5]); // 添字は0から4まで
/*  5*/     }
/*  6*/ }
コンソール
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
        at ExceptionTest2.main(ExceptionTest2.java:4)

Completed with exit code: 1

エラー・メッセージにあるArrayIndexOutOfBoundsExceptionは、配列の添字が範囲を越えている例外という意味です。

今日説明した、文字列を整数に変換する場合でも、文字列にアルファベットが混じっていたりすると、例外が発生します。

ExceptionTest3.java
/*  1*/ class ExceptionTest3 { // 例外のテスト3
/*  2*/     public static void main (String[] args) {
/*  3*/         int x;
/*  4*/         String str = "OK"; // アルファベットが混じった文字列
/*  5*/         x = Integer.parseInt(str); // 整数に変換
/*  6*/         System.out.println(x);
/*  7*/     }
/*  8*/ }
コンソール
Exception in thread "main" java.lang.NumberFormatException: For input string: "OK"
        at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        at java.base/java.lang.Integer.parseInt(Integer.java:652)
        at java.base/java.lang.Integer.parseInt(Integer.java:770)
        at ExceptionTest3.main(ExceptionTest3.java:5)

Completed with exit code: 1

エラー・メッセージにあるNumberFormatExceptionは、数の書式に関する例外という意味です。

try文

プログラムの実行中に例外が発生すると、エラー・メッセージが表示されて実行中止となるわけですが、実は「もし例外が発生したら何々する」というプログラムも書けます。 これによって、例外が発生したときに分かりやすいメッセージを表示することや、例外が発生してもプログラムを続行することができます。

try文 try statement )を使えば、「もし例外が発生したら何々する」というプログラムが書けます。 最も簡単な書き方は以下のとおりです。

try {
    例外が発生するかもしれない文; ...
} catch (Exception e) {
    例外を処理する文; ...
}

プログラムを実行すると、 try の「 例外が発生するかもしれない文 」が実行されます。 そして、 try の途中で例外が発生したら、残りはスキップして、 catch の「 例外を処理する文 」が実行されます。

なお、 catch の「 例外を処理する文 」が実行されても、プログラムは実行中止になりません。 実行中止にするには、文

System.exit(1);

を書きます。 ここで、 1 はエラーによる終了を意味しています。

以下のプログラムは、文字列"OK"を整数に変換して出力しようとするものです。 "OK"は整数に変換できないので6行目で例外が発生しますが、 try に囲まれているので7行目をスキップして catch に飛び、分かりやすいエラー・メッセージを出力して実行中止にします。

TryTest.java
/*  1*/ class TryTest { // try文のテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         int x;
/*  4*/         String str = "OK";
/*  5*/         try { // 例外が発生するかもしれない
/*  6*/             x = Integer.parseInt(str); // 整数に変換
/*  7*/             System.out.println(x);
/*  8*/         } catch (Exception e) { // 例外が発生したら
/*  9*/             System.out.println("整数ではありません。");
/* 10*/             System.exit(1); // 実行中止
/* 11*/         }
/* 12*/     }
/* 13*/ }
コンソール
整数ではありません。

Completed with exit code: 1

try文が役に立つのは、例えば、プログラムの利用者が変な入力をする場合です。 「 整数を入力してください: 」と聞いているのに、利用者が整数でない文字列を入力すると、try文を使わなければ、英語のエラー・メッセージを出力してプログラムが止まってしまいます。 これでは実用的ではありません。 せめて日本語でメッセージを出して止まるか、できれば再び聞くようにしたいものです。

以下のプログラムは、入力された整数をそのまま出力するものです。 try文を使っていないので、整数でない文字列を入力すると、英語のエラー・メッセージを出力してプログラムが止まります。

TryInputTest1.java
/*  1*/ import java.io.*;
/*  2*/ 
/*  3*/ class TryInputTest1 { // try文と入力のテスト1
/*  4*/     public static void main (String[] args) throws IOException {
/*  5*/         InputStreamReader isr = new InputStreamReader(System.in);
/*  6*/         BufferedReader br = new BufferedReader(isr);
/*  7*/         int x;
/*  8*/         System.out.print("整数を入力してください: ");
/*  9*/         x = Integer.parseInt(br.readLine()); // 例外が発生するかもしれない
/* 10*/         System.out.println(x);
/* 11*/     }
/* 12*/ }
コンソール
整数を入力してください: 100
100

Completed with exit code: 0
コンソール
整数を入力してください: OK
Exception in thread "main" java.lang.NumberFormatException: For input string: "OK"
        at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        at java.base/java.lang.Integer.parseInt(Integer.java:652)
        at java.base/java.lang.Integer.parseInt(Integer.java:770)
        at TryInputTest1.main(TryInputTest1.java:9)

Completed with exit code: 1

整数でない文字列を入力したら再び聞くようにするには、while文を使って繰り返し入力するようにし、入力の部分はtry文の中に入れ、入力の後にbreak文を置きます。 すると、入力で例外が発生しなければbreak文で繰返しを終了し、例外が発生すれば入力を繰り返すようになります。

TryInputTest2.java
/*  1*/ import java.io.*;
/*  2*/ 
/*  3*/ class TryInputTest2 { // try文と入力のテスト2
/*  4*/     public static void main (String[] args) throws IOException {
/*  5*/         InputStreamReader isr = new InputStreamReader(System.in);
/*  6*/         BufferedReader br = new BufferedReader(isr);
/*  7*/         int x;
/*  8*/         while (true) { // 無条件に繰り返す
/*  9*/             System.out.print("整数を入力してください: ");
/* 10*/             try {
/* 11*/                 x = Integer.parseInt(br.readLine()); // 例外が発生したらcatchへ
/* 12*/                 System.out.println(x);
/* 13*/                 break; // 途中で繰返しを終了
/* 14*/             } catch (Exception e) {
/* 15*/                 System.out.println("整数ではありません。");
/* 16*/             }
/* 17*/         }
/* 18*/     }
/* 19*/ }
コンソール
整数を入力してください: OK
整数ではありません。
整数を入力してください: 100
100

Completed with exit code: 0

例外の種類

try文を使うと、「もし例外が発生したら何々する」というプログラムが書けますが、例外にも、配列の添字が範囲を越えることや、数の書式に関することなど、色々な種類があります。 実は、try文は例外の種類で場合分けをすることができます。

ここで、あらかじめ配列に整数をいくつか格納しておき、添字を入力すると、その配列要素の値を出力するというプログラムを考えます。

TryArrayTest1.java
/*  1*/ import java.io.*;
/*  2*/ 
/*  3*/ class TryArrayTest1 { // try文と配列のテスト1
/*  4*/     public static void main (String[] args) throws IOException {
/*  5*/         InputStreamReader isr = new InputStreamReader(System.in);
/*  6*/         BufferedReader br = new BufferedReader(isr);
/*  7*/         int x;
/*  8*/         int[] a = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29};
/*  9*/         System.out.print("添字を入力してください: ");
/* 10*/         x = Integer.parseInt(br.readLine()); // 例外が発生するかもしれない
/* 11*/         System.out.println("a[" + x + "] = " + a[x]); // 例外が発生するかもしれない
/* 12*/     }
/* 13*/ }
コンソール
添字を入力してください: 3
a[3] = 23

Completed with exit code: 0

このプログラムは、入力が整数でなかったり、添字が範囲を越えていたりすると、エラーになってしまいます。

コンソール
添字を入力してください: OK
Exception in thread "main" java.lang.NumberFormatException: For input string: "OK"
        at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
        at java.base/java.lang.Integer.parseInt(Integer.java:652)
        at java.base/java.lang.Integer.parseInt(Integer.java:770)
        at TryArrayTest1.main(TryArrayTest1.java:10)

Completed with exit code: 1
コンソール
添字を入力してください: 10
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10
        at TryArrayTest1.main(TryArrayTest1.java:11)

Completed with exit code: 1

そこで、try文を使ってみますが、以下のプログラムでは、添字が整数でないことと範囲を越えていることの区別がつきません。

TryArrayTest2.java
/*  1*/ import java.io.*;
/*  2*/ 
/*  3*/ class TryArrayTest2 { // try文と配列のテスト2
/*  4*/     public static void main (String[] args) throws IOException {
/*  5*/         InputStreamReader isr = new InputStreamReader(System.in);
/*  6*/         BufferedReader br = new BufferedReader(isr);
/*  7*/         int x;
/*  8*/         int[] a = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29};
/*  9*/         System.out.print("添字を入力してください: ");
/* 10*/         try {
/* 11*/             x = Integer.parseInt(br.readLine());
/* 12*/             System.out.println("a[" + x + "] = " + a[x]);
/* 13*/         } catch (Exception e) {
/* 14*/             System.out.println("添字が整数でないか、範囲を越えています。");
/* 15*/             System.exit(1);
/* 16*/         }
/* 17*/     }
/* 18*/ }
コンソール
添字を入力してください: 3
a[3] = 23

Completed with exit code: 0
コンソール
添字を入力してください: OK
添字が整数でないか、範囲を越えています。

Completed with exit code: 1
コンソール
添字を入力してください: 10
添字が整数でないか、範囲を越えています。

Completed with exit code: 1

実は、 catch Exception は例外の種類を表しています。 catch を複数回書き、 Exception の部分に例外の種類を書けば、例外を区別することができます。

TryArrayTest3.java
/*  1*/ import java.io.*;
/*  2*/ 
/*  3*/ class TryArrayTest3 { // try文と配列のテスト3
/*  4*/     public static void main (String[] args) throws IOException {
/*  5*/         InputStreamReader isr = new InputStreamReader(System.in);
/*  6*/         BufferedReader br = new BufferedReader(isr);
/*  7*/         int x;
/*  8*/         int[] a = {20, 21, 22, 23, 24, 25, 26, 27, 28, 29};
/*  9*/         System.out.print("添字を入力してください: ");
/* 10*/         try {
/* 11*/             x = Integer.parseInt(br.readLine());
/* 12*/             System.out.println("a[" + x + "] = " + a[x]);
/* 13*/         } catch (NumberFormatException e) {
/* 14*/             System.out.println("添字が整数ではありません。");
/* 15*/             System.exit(1);
/* 16*/         } catch (ArrayIndexOutOfBoundsException e) {
/* 17*/             System.out.println("添字が範囲を越えています。");
/* 18*/             System.exit(1);
/* 19*/         } catch (Exception e) {
/* 20*/             System.out.println("その他の例外が発生しました。");
/* 21*/             System.exit(1);
/* 22*/         }
/* 23*/     }
/* 24*/ }
コンソール
添字を入力してください: 3
a[3] = 23

Completed with exit code: 0
コンソール
添字を入力してください: OK
添字が整数ではありません。

Completed with exit code: 1
コンソール
添字を入力してください: 10
添字が範囲を越えています。

Completed with exit code: 1

try文の一般的な書き方は以下のとおりです。

try {
    例外が発生するかもしれない文; ...
} catch (例外の種類1 変数1) {
    例外を処理する文1; ...
} catch (例外の種類2 変数2) {
    例外を処理する文2; ...
}
...
  catch (例外の種類n 変数n) {
    例外を処理する文n; ...
} finally {
    例外が発生してもしなくても実行する文; ...
}

プログラムを実行すると、 try の「 例外が発生するかもしれない文 」が実行されます。 そして、 try の途中で例外が発生したら、残りはスキップして、 catch の「 例外の種類1 」、「 例外の種類2 ... と順番にチェックします。 最初にマッチした「 例外の種類i 」に対して、「 変数i 」に例外に関する情報が格納され、「 例外を処理する文i 」が実行されます。

例外の種類の並べ方は、特殊な例外を先に、一般的な例外を後にします。 すると、最も特殊な例外に対する、例外を処理する文が実行されます。

finally には、例外が発生してもしなくても実行する文を書きます。 finally は、必要なければ省略できます。

例外の使用例

例外の使用例として、レジの計算の要領で、整数を次々と入力して合計を計算するプログラムを考えます。 ただし、ゼロを入力すると、入力の終わりと見なして合計を出力します。 また、整数でない文字列を入力すると、入力をやり直すようにします。

プログラムの要点は、入力された整数を x に代入し、合計を表す変数 total の値を x だけ増加させる、ということをwhile文で繰り返すのですが、繰返しの内容をtry文に入れることによって、例外が発生したら繰返しをやり直すようにしています。

TryInputTotal.java
/*  1*/ import java.io.*;
/*  2*/ 
/*  3*/ class TryInputTotal { // try文を使った入力の合計
/*  4*/     public static void main (String[] args) throws IOException {
/*  5*/         InputStreamReader isr = new InputStreamReader(System.in);
/*  6*/         BufferedReader br = new BufferedReader(isr);
/*  7*/         int x, total = 0;
/*  8*/         while (true) { // 無条件に繰り返す
/*  9*/             try {
/* 10*/                 System.out.print("整数を入力してください: ");
/* 11*/                 x = Integer.parseInt(br.readLine());
/* 12*/                 if (x == 0) {
/* 13*/                     break; // 途中で繰返しを終了
/* 14*/                 }
/* 15*/                 total += x;
/* 16*/             } catch (Exception e) {
/* 17*/                 System.out.println("整数ではありません。");
/* 18*/             }
/* 19*/         }
/* 20*/         System.out.println("合計は" + total + "です。");
/* 21*/     }
/* 22*/ }
コンソール
整数を入力してください: 100
整数を入力してください: 200
整数を入力してください: OK
整数ではありません。
整数を入力してください: 300
整数を入力してください: 0
合計は600です。

Completed with exit code: 0

演習14

上記のプログラムを、よりレジの計算に近づけるために、値段を入力して個数を入力する、ということを繰り返すようにしてください。 合計を計算するには、値段と個数の掛け算をして、その値だけ合計を増加させます。 ただし、値段でゼロを入力すると、入力の終わりと見なして合計を出力します。 また、値段や個数で整数でない文字列を入力すると、「 整数ではありません 」と出力して、値段の入力からやり直すようにします。

PriceCountTotal.java
import java.io.*;

class PriceCountTotal {
    public static void main (String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);



    }
}
コンソール
値段を入力してください: 150
個数を入力してください: 1
値段を入力してください: OK
整数ではありません。
値段を入力してください: 120
個数を入力してください: OK
整数ではありません。
値段を入力してください: 120
個数を入力してください: 3
値段を入力してください: 0
合計は510です。

Completed with exit code: 0

余力のある人は、最後に合計を出力するのではなく、値段と個数を入力したら、例外が発生してもしなくても、毎回それまでの合計を出力するようにしてください。

コンソール
値段を入力してください: 150
個数を入力してください: 1
合計は150です。
値段を入力してください: OK
整数ではありません。
合計は150です。
値段を入力してください: 120
個数を入力してください: OK
整数ではありません。
合計は150です。
値段を入力してください: 120
個数を入力してください: 3
合計は510です。
値段を入力してください: 0
合計は510です。

Completed with exit code: 0

レポート課題

今日の演習14の答案(Javaプログラム)をメールで提出してください。 差出人は大学発行のメール・アドレス(学生番号@cis.twcu.ac.jp)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(1月20日)を明記してください。


提出期限

すべてのレポートの提出期限を、1月30日(月)とします。


参考文献


[小西ホームページ]   [目次・索引]   [前の授業]

2023年1月20日更新
小西 善二郎 <konishi@cis.twcu.ac.jp>
Copyright (C) 2023 Zenjiro Konishi. All rights reserved.