標準入出力

ここではJavaのアプリケーションについて,コンソール画面への出力やキーボードからの入力を勉強します。

コンソールへの出力

コンソール(WindowsならMS-DOSプロンプトやコマンドプロンプトの画面)への出力は,標準出力と標準エラー出力の2系統があります。

class Test {
    public static void main(String[] args) {
        System.out.println("標準出力です");
        System.err.println("標準エラー出力です");
    }
}

これを通常通り java Test として実行すると

標準出力です
標準エラー出力です

と画面に出力されます。

しかし,java Test >xxx のようにリダイレクトすると,

標準エラー出力です

だけ画面に出力され,

標準出力です

のほうはファイル xxx に出力します。

つまり,

System.out.println()
通常はコンソールに出力するが,リダイレクトするとファイルに出力する
System.err.println()
いつもコンソールに出力する

ということになります。

なお,System.out.println("何々") は出力の後で改行しますが,System.out.print("何々") は改行しません。 特別な場合として,引数なしの System.out.println() は改行だけします。

入力(文字コード)

System.out.read() が,キーボードからの入力を読むための最も基本的な命令です。 これは,リターンキー(Enterキー)が押されるまでブロック(block,待つこと)します。 リターンキーが押されたら,最初に入力したキーの文字コード値を返します。

たとえば次のプログラムを考えましょう。

class Test {
    public static void main(String[] args)
            throws java.io.IOException {  // 入出力エラーがありうる
        while (true) {                    // 以下を繰り返す:
            int c = System.in.read();     //   キー入力を c に代入
            if (c == -1) break;           //   c が -1 ならループ脱出
            System.out.println(c);        //   c を出力
        }
    }
}

main(...) の直後の throws ... については少し後で説明します。

このプログラムを実行すると,入力待ちの状態になります。 キーボードからたとえば abc リターン と入力すると, 画面には

    97
    98
    99
    10

と出ます。これは,

だからです。

System.in.read() は,「入力の終わり」を意味する特別なキー操作をすると,-1 という値を戻してきます。 その特別なキー操作とは

です。 上のプログラムは,この値が戻ってきたらループを脱出します。

さて,main の最初に戻って,通常は

    public static void main(String[] args) {

でよかったのに,このプログラムでは

    public static void main(String[] args)
            throws java.io.IOException {

のように throws java.io.IOException を付けてあります。 これは,I/O(アイオー,Input/Output,入出力)でException(例外状態,要するにエラー)が起こるかもしれないことの宣言です。 データ入力を伴うプログラムでは,このような宣言が必要です。 もしこれを忘れたら,コンパイル時に次のようなエラーメッセージが出ます。

Test.java:4: 例外 java.io.IOException は報告されません。スローするにはキャッチまたは、スロー宣言をしなければなりません。
            int c = System.in.read();
                             ^
エラー 1 個

ちなみに,java.io.IOException のような長い名前を書くのは面倒なので,通常はプログラムの最初に

    import java.io.*;

と書いておきます。 そうすば,java.io の部分が省略できて,単に

    public static void main(String[] args) throws IOException {

と書くだけでよくなります。 以下ではこの書き方をよく使います。

上のプログラムは次のように書くこともできます。

import java.io.*;
class Test {
    public static void main(String[] args) throws IOException {
        int c;
        while ((c = System.in.read()) != -1)
            System.out.println(c);
    }
}

これは,System.in.read() の値を c に入れるのと同時に,それが -1 かどうか調べ,-1 でなければ System.out.println(c); を実行し,これを繰り返します。 結局,さきほどのプログラムとまったく同じことです。

入力(文字列)

次のプログラムを実行すると「お名前は?」と尋ねてきますので,キーボードからたとえば 花子 と入れてリターンキーを押してください。 「こんにちは,花子さん」と答えてくれるはずです。

import java.io.*;
class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader r =
            new BufferedReader(new InputStreamReader(System.in), 1);
                                        // データ入力の準備
        System.out.print("お名前は? "); // 画面出力
        System.out.flush();             // 強制出力
        String s = r.readLine();        // 文字列の入力
        System.out.println("こんにちは," + s + "さん");
    }
}

ここでも import java.io.*; が出てきましたね。 これを書かないと,

IOExceptionjava.io.IOException
BufferedReaderjava.io.BufferedReader

のように正式名を使わなければなりません。

キーボードから文字列を入力するには,System.in を補強するための次のような命令が必要です。

    BufferedReader r =
        new BufferedReader(new InputStreamReader(System.in), 1);

これは,System.in(標準入力)を引数として InputStreamReader というクラスのインスタンスを作り,これをさらに引数として BufferedReader というクラスのインスタンスを作り,これを r という変数に代入しています。 要するに,System.in を補強した r というものを作っているわけです。 これは決まり文句として憶えておくといいでしょう。 BufferedReader の最後の引数 1 は,バッファ(入力を一時保管しておくところ)のサイズ(文字数)です。 キーボード入力の場合は,入力してEnter(リターン)キーを打つとすぐ反応してほしいので,バッファのサイズを1にするとよいでしょう。

次の画面出力

    System.out.print("お名前は? ");

には,最後に改行する System.out.println(...) の代わりに,改行しない System.out.print(...) を使いました。 ところが,Java言語の System.out では,効率化のため,改行が来るまでデータを内部に溜めておき,改行が来たらまとめて出力するしくみになっています。 そこで,行の途中で強制出力するために

    System.out.flush();           // 強制出力

が必要なのです。

文字列の入力は,さきほどの r を使って,

    String s = r.readLine();      // 文字列の入力

とします。

プログラムの実行が r.readLine() のところまで来ると,コンピュータは入力待ちの状態になります。 そこで例えば 花子 と打ち込み,リターンキーを押せば,s に「花子」という文字列が入ります。

入力(int 型)

次のプログラムを実行すると「あなたは何歳ですか?」と尋ねてきますので,例えば40歳なら,キーボードから 40 と入れてリターンキーを押してください。 「きっと去年は 39 歳だったでしょう」と教えてくれるはずです。

import java.io.*;
class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader r =
            new BufferedReader(new InputStreamReader(System.in), 1);
                                        // データ入力の準備
        System.out.print("あなたは何歳ですか? ");
        System.out.flush();             // 強制出力
        String s = r.readLine();        // 文字列の入力
        int a = Integer.parseInt(s);    // 整数に変換
        System.out.println("きっと去年は " + (a - 1) +
                           " 歳だったでしょう");
    }
}

整数の入力は,まず

    String s = r.readLine();        // 文字列の入力

で文字列を入力してから,

    int a = Integer.parseInt(s);    // 整数に変換

で整数に変換しています。もちろんこれを

    int a = Integer.parseInt(r.readLine());

のようにまとめて書いてもかまいません。

入力(long 型)

次のプログラムは,金額を入力すると,消費税(入力額の5%)と税込み価格を出力します。 int 型(32ビット)では20億円程度しか扱えませんので,long 型(64ビット)を使います。

import java.io.*;
class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader r =
            new BufferedReader(new InputStreamReader(System.in), 1);
                                        // データ入力の準備
        System.out.print("金額? ");     // 画面出力
        System.out.flush();             // 強制出力
        String s = r.readLine();        // 文字列の入力
        long x = Long.parseLong(s);     // long型に変換
        long tax = x / 20;              // 消費税を求める(切捨て)
        long total = x + tax;           // 合計金額を求める
        System.out.println("金額: " + x +
                           "  消費税: " + tax +
                           "  合計: " + total);
    }
}

11行目では入力金額を20で割って消費税を求めています。 整数の割り算ですので,小数点以下は切捨てになります。

これを四捨五入にするには,

    long tax = (x + 10) / 20;   // 消費税を求める(四捨五入)

とします。 また,切上げにするには,

    long tax = (x + 19) / 20;   // 消費税を求める(切上げ)

とします。

入力(double 型)

次のプログラムを実行すると,円の半径を聞いてきます。 半径を入力すると円の面積を出力します。

import java.io.*;
class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader r =
            new BufferedReader(new InputStreamReader(System.in), 1);
                                        // データ入力の準備
        System.out.print("半径? ");     // 画面出力
        System.out.flush();             // 強制出力
        String s = r.readLine();        // 文字列の入力
        double x = Double.valueOf(s).doubleValue();
                                        // double型に変換
        double a = Math.PI * x * x;     // Math.PI は円周率
        System.out.println("半径 " + x + " の円の面積は "
                           + a + " です。");
    }
}

実行すると「半径?」と聞いてきます。 半径を例えば 5 のように打ち込むと,

    半径 5 の円の面積は 78.53981633974483 です。

のように出力されます。

★ 実数(double 型)の精度は15〜16桁です。

java.text.DecimalFormat を使えば表示形式が細かく指定できます。 たとえば小数第3位まで表示するなら次のようにします。

import java.text.*;
class Test {
    public static void main(String[] args) {
        DecimalFormat f = new DecimalFormat("0.000");
        double x = 3.141592653589793;
        System.out.println(f.format(x));
    }
}

奥村晴彦

Last modified: 2005-09-22 15:40:03