情報学部 菅沼ホーム 全体目次 演習解答例 付録 索引

第10章 クラスライブラリ

  1. 10.1 入出力クラス
    1. 10.1.1 標準入出力
      1. (プログラム例 10.1 ) 標準入出力
    2. 10.1.2 書式付き入出力
      1. (プログラム例 10.2 ) 書式付き出力
    3. 10.1.3 ファイル入出力
      1. (プログラム例 10.3 ) ファイル入出力
  2. 10.2 java.util パッケージ 内のクラス
  3. 10.3 Math クラス
  4. 演習問題10

  ここでは,入出力クラス,Java の代表的機能を含む java.util パッケージ内のクラス,及び,科学技術計算などに良く使用される Math クラスについて説明します.ただし,その量は膨大ですので,入出力クラスに関しては簡単な例を提示,また,それ以外に関しては,クラスやメソッドの簡単な機能の説明に留めます.詳細に関しては,付録や Java のマニュアルを参照して下さい.

10.1 入出力クラス

10.1.1 標準入出力 

  C++ の標準入出力に対応するものが,System クラスの static なフィールド(メンバー変数)として用意されている System.inSystem.out,および,System.err です.System.in では,C++ の cin とは異なり,1 行内のデータをスペースなどで分離し,適切な型に変換するといったことを行ってくれません.1 行を文字列として読み込むだけです.従って,以下の例にあるように,int や double に変換したい場合は,parseInt や parseDouble といったメソッドを使用しプログラム上で変換してやる必要があります.

  InputStreamReader は,Reader のサブクラスであり,バイトストリームから文字ストリームへの橋渡しを行います.バイト列を読み込み,文字コードにしたがって文字列に変換します.

  BufferedReader は,Reader のサブクラスであり,文字ストリームからデータを読み込み,それらをバッファリングします.

(プログラム例 10.1 ) 標準入出力

  コメントになっているように,メソッド printf を使用することも可能です.

/****************************/
/* 標準入出力               */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;

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

		System.out.print("1行,適当な文字列を入力して下さい(半角スペースを含んでも可) ");
		String line = in.readLine();
		System.out.println(line);
//		System.out.printf("%s\n", line);

		System.out.print("整数データを1つ入力して下さい ");
		int i = Integer.parseInt(in.readLine());
		System.out.print("実数データを1つ入力して下さい ");
		double x = Double.parseDouble(in.readLine());
		System.out.print("文字列を入力して下さい ");
		String c = in.readLine();
		System.out.println("整数 " + i + " 実数 " + x + " 文字列 " + c);
//		System.out.printf("整数 %d 実数 %f 文字列 %s\n", i, x, c);
	}
}
		

  このプログラムの出力は,例えば,以下のようになります(入力部分は除く).
test input
整数 10 実数 3.14 文字列 suzuki		
  コンソールから入出力を行う場合は,以下の例に示すように,Console クラスを利用した方が便利かもしれません.ただし,この方法ですと,入出力に対するリダイレクトができなくなります.

/****************************/
/* 標準入出力               */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;

public class Test {
	public static void main(String args[])
	{
		Console con = System.console();

		String line = con.readLine("1行,適当な文字列を入力して下さい(半角スペースを含んでも可) ");
		con.printf("%s\n", line);

		int i = Integer.parseInt(con.readLine("整数データを1つ入力して下さい "));
		double x = Double.parseDouble(con.readLine("実数データを1つ入力して下さい "));
		String c = con.readLine("文字列を入力して下さい ");
		con.printf("整数 %d 実数 %f 文字列 %s\n", i, x, c);
	}
}
		

  以上の例においては,1 行に 1 つのデータだけを入力して処理を行いました.以下の例においては,整数,実数,及び,文字列を,半角スペースで区切り,1 行で入力する場合に対する処理を行っています.最初は,Console クラスと StringTokenizer クラスを利用した場合の例です( Console クラスを利用しない場合も同様).

/****************************/
/* 標準入出力               */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.util.*;

public class Test {
	public static void main(String args[])
	{
		Console con = System.console();

		String line = con.readLine("1行,適当な文字列を入力して下さい(半角スペースを含んでも可) ");
		con.printf("%s\n", line);

		line = con.readLine("整数,実数,文字列を,半角スペースで区切って入力してください ");
		StringTokenizer str = new StringTokenizer(line, " ");
		int i    = Integer.parseInt(str.nextToken());
		double x = Double.parseDouble(str.nextToken());
		String c = str.nextToken();
		con.printf("整数 %d 実数 %f 文字列 %s\n", i, x, c);
	}
}
		

  次は,Console クラスと String クラスの split メソッドを利用した場合の例です( Console クラスを利用しない場合も同様).

/****************************/
/* 標準入出力               */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;

public class Test {
	public static void main(String args[])
	{
		Console con = System.console();

		String line = con.readLine("1行,適当な文字列を入力して下さい(半角スペースを含んでも可) ");
		con.printf("%s\n", line);

		line = con.readLine("整数,実数,文字列を,半角スペースで区切って入力してください ");
		String str[] = line.split(" ");
		int i    = Integer.parseInt(str[0]);
		double x = Double.parseDouble(str[1]);
		String c = str[2];
		con.printf("整数 %d 実数 %f 文字列 %s\n", i, x, c);
	}
}
		

  最後は,Scanner クラスを利用した場合の例です.この場合は,C/C++ の scanf と同様,3 つのデータを半角スペースで区切っても,改行で区切っても構いません.

/****************************/
/* 標準入出力               */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.util.*;

public class Test {
	public static void main(String args[])
	{
		Scanner sc = new Scanner(System.in);

		System.out.printf("1行,適当な文字列を入力して下さい(半角スペースを含んでも可) ");
		String line = sc.nextLine();
		System.out.printf("%s\n", line);

		System.out.printf("整数,実数,文字列を,半角スペースまたは改行で区切って入力してください ");
		int i    = sc.nextInt();
		double x = sc.nextDouble();
		String c = sc.next();
		System.out.printf("整数 %d 実数 %f 文字列 %s\n", i, x, c);
	}
}
		

10.1.2 書式付き出力 

  Java においては,DecimalFormat クラス を使用します.

(プログラム例 10.2 ) 書式付き出力

/****************************/
/* 書式付き出力             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.text.*;

public class Test {
	public static void main(String args[]) throws IOException
	{
		double x = 123.45, y = 3.141592654;

		DecimalFormat df = new DecimalFormat("+0.000000E000");
		System.out.println(df.format(x) + " " + df.format(y));
		df = new DecimalFormat("+0.0000E000");
		System.out.println(df.format(x) + " " + df.format(y));
					// 全体の桁数を指定することは不可能
		df = new DecimalFormat("+0.0000E000");
		System.out.println(df.format(x) + " " + df.format(y));
	}
}
		

  全体の桁数を指定したいような場合,PrintStream クラスPrintWriter クラスConsole クラスなどに C/C++ の printf 関数と同様の働きをする printf メソッドがありますので,以下の例のように簡単に記述できます(ただし,左側のスペースを「*」ではなく「0」で埋めている).

import java.io.*;

public class Test {
	public static void main(String args[]) throws IOException
	{
		double x = 123.45, y = 3.141592654;

		System.out.printf("%+e %+e\n", x, y);
		System.out.printf("%+10.4e %+10.4e\n", x, y);
		System.out.printf("%0+15.4e %+15.4e\n", x, y);
	}
}
		
  このプログラムの出力は以下のようになります.
+1.234500e+02 +3.141593e+00
+1.2345e+02 +3.1416e+00
+00001.2345e+02     +3.1416e+00		
  左側の空白部分を「*」で埋めたいような場合は,例えば,以下のようなプログラムを書く必要があります.

/****************************/
/* 書式付き出力             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.text.*;

public class Test {
	public static void main(String args[]) throws IOException
	{
		int a = 123, b = 12345678;
		double x = 123.4567, y = 3.14;
		String str1, str2, str3, str4, str5, str6;

		str1 = Format.Edit(x, 0, 4, 15, " ");
		str2 = Format.Edit(y, 0, 4, 15, "*");
		System.out.println(str1 + str2);
		str3 = Format.Edit(x, 1, 4, 15, " ");
		str4 = Format.Edit(y, 1, 4, 15, "*");
		System.out.println(str3 + str4);
		str5 = Format.Edit(a, 15, " ");
		str6 = Format.Edit(b, 15, "*");
		System.out.println(str5 + str6);
	}
}

/**********************/
/* クラスFormatの定義 */
/**********************/
class Format {

	/***********************************************/
	/* 整数を指定した長さの文字列に変換            */
	/*      data : 整数データ                      */
	/*      n : 文字列の長さ                       */
	/*      f : 左側を埋める文字(「.」を除く)    */
	/*      return : 文字列                        */
	/*                 長すぎるときは「*」で埋める */
	/***********************************************/
	static String Edit(int data, int n, String f)
	{
		int i1, len;
		String str;

		str = String.valueOf(data);
		len = str.length();

		if (len != n) {
					// 長さが短い
			if (len < n) {
				for (i1 = 0; i1 < n-len; i1++)
					str = f + str;
			}
					// 長さが長すぎる
			else {
				char c[] = new char [n];
				for (i1 = 0; i1 < n; i1++)
					c[i1] = '*';
				str = String.copyValueOf(c);
			}
		}

		return str;
	}

	/***********************************************/
	/* 実数を指定した長さの文字列に変換            */
	/* (オーバーフローのチェックは行っていない)  */
	/*      data : 実数データ                      */
	/*      sw : 表現方法                          */
	/*             =0 : ±xxxx.xx                  */
	/*             =1 : ±x.xxxxxE±xxx            */
	/*      p : 小数点以下の桁数                   */
	/*      n : 文字列の長さ                       */
	/*      f : 左側を埋める文字(「.」を除く)    */
	/*      return : 文字列                        */
	/*                 長すぎるときは「*」で埋める */
	/***********************************************/
	static String Edit(double data, int sw, int p, int n, String f)
	{
		double x;
		int i1, k, k1, len;
		String str, s1, s2, s3;

		str = String.valueOf(data);   // 元のデータの文字列表現
/*
	 固定小数点表示
*/
		if (sw == 0) {
					// 入力データが固定小数点表示の場合
			if (str.indexOf('E') < 0 && str.indexOf('e') < 0) {
						// 小数点以上と以下を取り出す
				k   = str.indexOf('.');
				s1  = str.substring(0, k);
				s2  = str.substring(k+1);
						// 全体の文字列の作成
				str = Append(data, p, n, s1, s2, f);
			}
					// 入力データが浮動小数点表示の場合
			else {
						// 仮数部と指数部
				k = str.indexOf('E');
				if (k < 0)
					k = str.indexOf('e');
				s1 = str.substring(0, k);
				s2 = str.substring(k+1);
						// 指数部の値
				k1 = Integer.parseInt(s2);
						// 仮数部の小数点以上と以下
				k  = s1.indexOf('.');
				s2 = s1.substring(k+1);
				s1 = s1.substring(0, k);
						// 小数点以上と以下の調整
				if (k1 != 0) {
					if (k1 > 0) {
						len = s2.length();
						if (k1 == len) {
							s1 += s2;
							s2  = "0";
						}
						else {
							if (k1 < len) {
								s1 += s2.substring(0, k1-1);
								s2  = s2.substring(k1);
							}
							else {
								s1 += s2;
								for (i1 = 0; i1 < k1-len; i1++)
									s1 += "0";
								s2 = "0";
							}
						}
					}
					else {
						len = s1.length();
						k1  = -k1;
						if (k1 == len) {
							s2 = s1 + s2;
							s1 = "0";
						}
						else {
							if (k1 < len) {
								s2 = s1.substring(len-k1) + s2;
								s1 = s1.substring(0, len-k1);
							}
							else {
								s2 = s1 + s2;
								for (i1 = 0; i1 < k1-len; i1++)
									s2 = "0" + s2;
								s1 = "0";
							}
						}
					}
				}
						// 全体の文字列の作成
				str = Append(data, p, n, s1, s2, f);
			}
		}
/*
	 浮動小数点表示
*/
		else {
					// 入力データが固定小数点表示の場合
			if (str.indexOf('E') < 0 && str.indexOf('e') < 0) {
						// 指数部と仮数部を決める
				k1 = 0;
				x  = Math.abs(data);
				if (x >= 10.0) {
					while (x >= 10.0) {
						x /= 10.0;
						k1++;
					}
				}
				else {
					if (x < 1.0) {
						while (x < 1.0) {
							x *= 10.0;
							k1--;
						}
					}
				}
						// 指数部の調整
				if (k1 >= 0) {
					s3  = String.valueOf(k1);
					len = s3.length();
					if (len < 3) {
						for (i1 = 0; i1 < 3-len; i1++)
							s3 = "0" + s3;
					}
					s3 = "+" + s3;
				}
				else {
					s3  = String.valueOf(-k1);
					len = s3.length();
					if (len < 3) {
						for (i1 = 0; i1 < 3-len; i1++)
							s3 = "0" + s3;
					}
					s3 = "-" + s3;
				}
						// 仮数部の小数点以上と以下
				str = String.valueOf(x);
				k   = str.indexOf('.');
				s1  = str.substring(0, k);
				s2  = str.substring(k+1);
						// 仮数部の調整
				str = Append(x, p, n-5, s1, s2, f);
						// 桁数オーバー
				k = str.indexOf('.');
				if (k < 0) {
					for (i1 = 0; i1 < 5; i1++)
						str += "*";
				}
						// 全体の文字列
				else
					str = str + "E" + s3;
			}
					// 入力データが浮動小数点表示の場合
			else {
						// 仮数部と指数部
				k = str.indexOf('E');
				if (k < 0)
					k = str.indexOf('e');
				s1 = str.substring(0, k);
				s2 = str.substring(k+1);
				x  = Double.parseDouble(s1);
						// 指数部の調整
				k1 = Integer.parseInt(s2);
				if (k1 >= 0) {
					s3  = String.valueOf(k1);
					len = s3.length();
					if (len < 3) {
						for (i1 = 0; i1 < 3-len; i1++)
							s3 = "0" + s3;
					}
					s3 = "+" + s3;
				}
				else {
					s3  = String.valueOf(-k1);
					len = s3.length();
					if (len < 3) {
						for (i1 = 0; i1 < 3-len; i1++)
							s3 = "0" + s3;
					}
					s3 = "-" + s3;
				}
						// 仮数部の小数点以上と以下
				k  = s1.indexOf('.');
				s2 = s1.substring(k+1);
				s1 = s1.substring(0, k);
						// 仮数部の調整
				str = Append(x, p, n-5, s1, s2, f);
						// 桁数オーバー
				k = str.indexOf('.');
				if (k < 0) {
					for (i1 = 0; i1 < 5; i1++)
						str += "*";
				}
						// 全体の文字列
				else
					str = str + "E" + s3;
			}
		}

		return str;
	}

	/********************************************************/
	/* 小数点以上,及び,以下の文字列から全体の文字列を作成 */
	/*      data : 実数データ                               */
	/*      p : 小数点以下の桁数                            */
	/*      n : 文字列の長さ                                */
	/*      s1 : 小数点以上の文字列                         */
	/*      s2 : 小数点以下の文字列                         */
	/*      f : 左側を埋める文字(「.」を除く)             */
	/*      return : 文字列                                 */
	/********************************************************/
	static String Append(double data, int p, int n, String s1, String s2, String f)
	{
		long L;
		int i1, k, len;
		String str;

					// 小数点以下の桁数の調整
		if (p == 0) {
			L = (long)data;
			if ((data-(double)L) >= 0.5) {
				L  = Long.parseLong(s1) + 1;
				s1 = String.valueOf(L);
			}
		}

		else {

			len = s2.length();

			if (len != p) {
				if (len < p) {
					for (i1 = 0; i1 < p-len; i1++)
						s2 += "0";
				}
				else {
					L = Long.parseLong(s2.substring(0, p));
					k = Integer.parseInt(s2.substring(p, p+1));
					if (k >= 5)
						L++;
					s2 = String.valueOf(L);
				}
			}
		}
					// 全体の長さの調整
		if (p == 0)
			str = s1;
		else
			str = s1 + "." + s2;

		len = str.length();

		if (len != n) {
			if (len < n) {
				for (i1 = 0; i1 < n-len; i1++)
					str = f + str;
			}
			else {
				char c[] = new char [n];
				for (i1 = 0; i1 < n; i1++)
					c[i1] = '*';
				str = String.copyValueOf(c);
			}
		}

		return str;
	}
}
		

  このプログラムの出力は以下のようになります.
       123.4567*********3.1400
    1.2346E+002****3.1400E+000
            123*******12345678		

10.1.3 ファイル入出力 

(プログラム例 10.3 ) ファイル入出力

  このプログラムは,ファイル input からデータを読み込み,ファイル output へ出力するためのものです.その際,1 行に書かれた複数のデータ(スペースで区切られている)を,1 行に一つずつ書いて出力しています.このプログラムの場合,PrintStream,PrintWriter のいずれを使用しても同じ結果が得られます.

  FileReader は,InputStreamReaderReader のサブクラス)のサブクラスであり,文字からなるファイルを読むためのものです.

  FileOutputStream は,OutputStream のサブクラスであり,データをファイルへ書き込むための出力ストリームを生成するクラスです.

  PrintStream は,FilterOutputStream( OutputStream のサブクラス)のサブクラスであり,様々な型のデータを表示するためのものです.文字として出力したい場合は,PrintWriter クラスを使用すべきです.

  FileWriter は,OutputStreamWriterWriter のサブクラス)のサブクラスであり,文字からなるファイルを生成するためのクラスです.

  PrintWriter は,Writer のサブクラスであり,機能的には PrintStream とほとんど同じですが,flush の方法が少しだけ異なります.

/****************************/
/* ファイル入出力           */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.util.StringTokenizer;

/************************************/
/* mainメソッドを含んだクラスの定義 */
/************************************/
public class Test {
	public static void main(String args[]) throws IOException
	{
		String line, data;
		StringTokenizer str;

		BufferedReader in = new BufferedReader(new FileReader("input"));
		PrintStream out = new PrintStream(new FileOutputStream("output"));
//		PrintWriter out = new PrintWriter(new FileWriter("output"));   このようにしても,同じ結果になる

		while ((line = in.readLine()) != null) {
			str = new StringTokenizer(line, " ");
			while (str.hasMoreTokens())
				out.println(str.nextToken());
		}

		in.close();
		out.close();
	}
}
		

  ファイル input に,例えば,
データ1 111 データ2 222
10
データ3 333		
のように書いてあると,ファイル output の内容は以下のようになります.
データ1
111
データ2
222
10
データ3
333		

10.2 java.util パッケージに内のクラス

  最初に,java.util パッケージに含まれるクラスの例として,ArrayList クラスの使用例を示します.

(プログラム例 10.4 ) ファイル入出力( ArrayList クラス)

  今まで扱った多くの例においては,あらかじめデータ数が分かっていました.データの数が分からないような場合はどのようにしたらよいでしょうか.次のプログラムはそのような場合の例です.今,あるファイル input.txt に学籍番号,英語の点,及び,数学の点が,
1 50 70
2 30 80
3 100 90
4 0 80
5 10 20		
のような形で,任意の数だけ保存されているものとします.そして,結果もファイル output.txt に保存するものとします.これを実現したのが,以下に示すプログラムです.
01	/***************************************/
02	/* ファイル入出力( ArrayList クラス) */
03	/*      coded by Y.Suganuma            */
04	/***************************************/
05	import java.io.*;
06	import java.util.*;
07	public class Test {
08		public static void main(String args[])
09		{
10			double mean1, mean2, sum1 = 0.0, sum2 = 0.0;
11			int n = 0, m = 0, i1, no, x, y;
12			String line;
13			StringTokenizer str;
14			ArrayList  data = new ArrayList  ();
15			try {
16						// データの読み込みと点数の和の計算
17				BufferedReader in = new BufferedReader(new FileReader("input.txt"));
18				while ((line = in.readLine()) != null) {
19					str   = new StringTokenizer(line, " ");
20					no    = Integer.parseInt(str.nextToken());
21					x     = Integer.parseInt(str.nextToken());
22					y     = Integer.parseInt(str.nextToken());
23					sum1 += x;
24					sum2 += y;
25					data.add(new Integer(no));
26					data.add(new Integer(x));
27					data.add(new Integer(y));
28					n++;
29				}
30				in.close();
31						// 平均点の計算と平均点以下の人
32				if (n <= 0)
33					System.out.println("データが存在しません!");
34				else {
35					mean1 = sum1 / n;
36					mean2 = sum2 / n;
37					PrintStream out = new PrintStream(new FileOutputStream("output.txt"));
38					out.println("英語平均 " + mean1 + " 数学平均 " + mean2);
39					out.println("いずれかの科目が平均点以下の人の学籍番号");
40					for (i1 = 0; i1 < n; i1++) {
41						no = (data.get(3*i1)).intValue();
42						x  = (data.get(3*i1+1)).intValue();
43						y  = (data.get(3*i1+2)).intValue();
44						if (x <= mean1 || y <= mean2) {
45							out.println("    " + no);
46							m++;
47						}
48					}
49					out.println("該当学生数 " + m + " 人");
50					out.close();
51				}
52			}
53			catch (IOException io) {
54				System.out.println(io.getMessage());
55			}
56		}
57	}
		
14 行目

  ArrayList クラスは,サイズ変更可能な配列を実装するためのクラスです.ここでは,Integer クラスのオブジェクトを要素とする ArrayList クラスのオブジェクト data を生成しています.

17 行目

  入力データをファイル input.txt から読み込むために,そのファイル名を引数として FileReader クラスのオブジェクトを生成し,それを引数として,BufferedReader クラスのオブジェクトを生成しています.

18 行目

  データがなくなるまで,ファイル input.txt から 1 行ずつデータを読み込みます.

25~27 行目

  ファイル input.txt から読み込んだ 1 行分のデータに含まれる学籍番号,英語の点,及び,数学の点を,ArrayList クラスのメソッド add を使用して data に追加しています.

30 行目

  データの読み込みが終了したので,ファイルをクローズしています.

37 行目

  データをファイル output.txt に出力するため,その名前を引数として FileOutputStream クラスのオブジェクトを生成し,それを引数として,PrintStream クラスのオブジェクトを生成しています.

41~43 行目

  学籍番号,英語の点,及び,数学の点を,ArrayList クラスのメソッド get を使用して data から取り出しています.

50 行目

  データの出力が終了したので,ファイルをクローズしています.
  先に示した入力例に対して上のプログラムを実行すると,ファイル output.txt の内容は以下のようになります.
英語平均 38.0 数学平均 68.0
いずれかの科目が平均点以下の人の学籍番号
    2
    4
    5
該当学生数 3 人			

  java.util パッケージ 内には,ArrayList クラスだけではなく,乱数,ベクトル等,有用なユーティリティを扱う以下に示すようなクラスが含まれています.

10.3 Math クラス

  Math クラスは,数学関係の多くのメソッド(三角関数,対数関数,指数関数など)や定数(π,e )を含む static なクラスです.<math.h> ヘッダ内の C の標準関数,及び,<cmath> ヘッダ内の C++ の標準ライブラリ内の関数が相当します.

演習問題10

[問1]特定の月のカレンダーを出力するプログラムを書け.

[問2]任意の数のテキストファイルを連結して出力する,つまり,
cat file1 file2 ・・・
を実現するプログラムを書け.

情報学部 菅沼ホーム 全体目次 演習解答例 付録 索引