Javaには多くのクラスライブラリが用意されています。 もとより、クラスライブラリをすべて覚える必要はありません。 必要に応じて仕様書(注)を参照すれば良いのです。 しかしどんなものがあるかくらいは知っている必要があります。 ライブラリに用意されているメソッドを自分で作ってしまうほど、つまらないことはありません。 ここでは、特に重要なクラスに限り、そのまたさらに一部の仕様だけ説明します。

(注)インターネットが使えれば、Javaの仕様書は容易に参照できます。 例えば Google で「Math java」などとキーワードを入力し、 I'm feeling Luckyをクリックすると、Mathクラスの仕様書(javadoc)が表示されます。 この仕様書にはMathクラスで使えるメソッドの一覧と使い方(パラメーター群)が記述されています。

Mathクラス

Mathクラスは、指数関数、対数関数、平方根、および三角関数といった基本的な数値処理を実行するためのメソッドを含んでいます。 Mathクラスのメソッドはすべてstaticメソッドなので、new文でインスタンスを生成すること無しに使用できます。

        double a = Math.sqrt(2);        // aには2の平方根の値が入ります
		

以下の例では、y と z がint型なら x もint型となり、double型なら x もdouble型になります。 int型とdouble型とでは、異なるプログラムが実行されますが、オーバーロードの機能によって実行するプログラムが選択されるわけです。 maxにはこの他にlong型とfloat型の演算もあります。

        x = Math.max(y, z);
		

Stringクラス

Stringクラスはこれまで何度も出てきました。 Stringクラスには多数のメソッドがありますが、それらのうち、ごく一部の良く使われるメソッドを示します。

        String substring(int start)
          文字列のstartの位置(先頭0)から最後までの文字列を切り出して返します。
      ★String substring(int start, int end)
          文字列のstartの位置(先頭0)からend-1までの文字列を切り出して返します。
        static String valueOf(int a)
          整数値aを文字列に変換します。
          staticなので String.valueOf(a) のように使います。
        int indexOf(String str)
          文字列の中でstrと一致する文字列が(最初に)存在する位置を返します。
          文字列が存在しない場合は-1を返します。
        int length()
          文字列の長さを返します。
          Javaでは全文字が16ビットなので半角/全角の区別はありません。

        使用例
        String s = "ABCDEF";
        s = s.substring(2,5)    // sは"CDE"
		

Stringクラスの生成の仕組み

Stringクラスでは一度作成した文字列の中身を変更することができません。 前述の使用例の s は"ABCDEF"から"CDE"に変更していると思われるかもしれませんが、 これは一度作った"ABCDEF"を捨て、新たな領域を確保して、そこに"CDE"をセットし、そのアドレスを s にセットしているのです。 捨てられた"ABCDEF"はガベージコレクションの機能により、自動的にメモリ領域に返却されます。

また内容が同じ場合は値を共有します。 例えば以下の場合は、"ABC"の実体は1つしか作らず、s1とs2が(アドレスとして)同じ値になります。

        String s1 = "ABC";
        String s2 = "ABC";
		

nullリテラル ★

2章で説明したようにStringは参照型で変数には文字列ではなく、文字列へのアドレスが格納されているのでした。 このような参照型の変数には以下の 01: のようにnullを代入することができます。 nullはtrueやfalseとともに、Java言語で定義されている特別な値で(1章の予約語リスト参照)、nullリテラルと呼ばれることがあります。

	  01:   String s = null;
	  02:   System.out.println(s);  // nullと出力される
	  03:   s = s.substring(1,3);
		

01: のようにすると s はメモリ上に場所だけは確保されるのですが、その場所には実効的なアドレスは格納されず、どこもポイントしていない状態になります。 この状態で 02: のように s を出力するとnullと出力されます。 s に文字列"null"が代入されているときと、出力結果は同じですが、状況は違うので注意してください。

またこの状態で 03: のようにStringクラスのメソッドを実行しようとすると、NullPointerExceptionという例外が発生します。 実際のプログラムではこの例外がよく発生し、初心者のJavaプログラマーを悩ませます。 nullリテラルは参照型に代入できるので、String型だけでなく、配列やその他のすべてのクラスから作成したインスタンスに代入できます。 これらにnullリテラルを代入すると、インスタンスの利用終了とみなされ、ガベージコレクションの対象になります。 したがって、使い終わったインスタンスに積極的にnullを代入すると、メモリの効果的な利用が図れます。

StringBuilderクラス

Stringクラスでは一度作成した文字列の中身の変更ができないので、文字列を変更するような場合には、StringBuilderクラスを使う方が良いでしょう。

StringBuilderクラスには、文字列の追加(append)、削除(delete)、指定位置への挿入(insert)、置き換え(replace)など、多数のメソッドが用意されています。

【確認問題】 8.1

strの内容が"dog cat rabbit"のとき、以下のプログラムを実行するとstr1とstr2はそれぞれどうなりますか。
        String str1 = str.substring(0, str.indexOf(" "));
        String str2 = str.substring(str.indexOf(" ")+1);
		
※ Stringクラスのsplitメソッドを使うと、このような文字列分割がスマートに実行できます。


Integerクラス

Javaには32ビット整数を扱うデータ型としてint型の他にIntegerという型(クラス)があります。 Integerクラスはint型の数値を1つだけ変数として持つとともに、int型の計算に役立つメソッドを備えています。 これはint型のデータをラップ(wrap:包み込む)していると言う意味でラッパークラスと呼ばれます。 以下にIntegerクラスの主要なコンストラクタとメソッドを示します。 Integerクラスのメソッドにはstaticメソッドとインスタンスメソッドとがあります

     コンストラクタ
        Integer(int i)
          整数値iをInteger型に変換する。

     メソッド
        static Integer valueOf(String s)
          文字列sを10進数と見なしてInteger型に変換する。
          数字に変換できないとNumberFormatExceptionという例外を発行する。
      ★static int parseInt(String s)
          文字列sを10進数と見なしてint型に変換する。
          数字に変換できないとNumberFormatExceptionという例外を発行する。
        int intValue()
          Integer型の数値をint型に変換する。
		

以下に使用例を示します。 staticメソッドはInteger.xxxと書き、インスタンスメソッドはインスタンス名.yyyと書くことに注意してください。 01: はコンストラクタの例です。 02: をまとめて 03: のように書けます。 またparseIntメソッドを使えば、02: や 03: のような処理が 04: のように一度で書けます。 parseとは構文解析をすると言う意味です。

	  01:   Integer obj = New Integer(123);

	  02:   String s ="123";
	        Integer obj = Integer.valueOf(s);
	        int i = obj.intValue();

	  03:   String s ="123";
	        int i = Integer.valueOf(s).intValue();

	  04:   String s ="123";
	        int i = Integer.parseInt(s);
		

オートボクシング/アンボクシング機能

かつては上の例のようにint型とInteger型はいちいち明示的に変換しなければなりませんでした。 しかし、これは大変煩わしいので、これらの型を自動的に変換する機能が追加されました。 int型からInteger型へ変換するオートボクシング機能と、その逆のオートアンボクシング機能です。 この機能があるので前項の 01: と 02: の3行目は次のように書くことができます。

	  01:           Integer obj = 123;
	  02の3行目:    int i = obj;
		

もう1つ例を挙げます。 Integer型同士では計算ができないので、これまではInteger型の変数の加算は 03: のようにint型に変換してから加算しなければなりませんでした。

	  01:   Integer a = new Integer(12);
	  02:   Integer b = new Integer(34);
	  03:   Integer c = new Integer( a.intValue() + b.intValue() );
		

これに対しオートボクシング/アンボクシング機能が働くと次のように簡単に記述できます。

	  01:   Integer a = 12;
	  02:   Integer b = 34;
	  03:   Integer c = a + b;
		

【確認問題】 8.2

コマンドラインから2つの数字を受け取り、その和を表示するプログラムを作成してください。
(ヒント) コマンドラインからのパラメーターはargsで受け取るのでした。 ここではargsで受け取ったString型のパラメーターを数字(int型)に変換するのがポイントです。


その他のラッパークラス

ラッパークラスにはint型だけでなく、すべての基本データ型に対するものがあります。 それを全部挙げると、

        Boolean、Character、Byte、Short、Integer、Long、Float、Double
		

となります。 これに対応する基本データ型を列挙してみると、

        boolean、     char、byte、short、    int、long、float、double
		

となっています。 比べてみるとCharacterとIntegerは省略型だったcharとintがフルスペルになり、その他は先頭が大文字になっただけでつづりは同じであることがわかります。 Javaでは大文字と小文字は区別されますので、これらは当然違ったモノとして扱われます。

前項で述べたオートボクシング/アンボクシング機能はint型とInteger型間の変換以外に、上記のラッパークラスと基本データ型間の変換にも適用されます。

ラッパークラスの用途

次項で述べるArrayListなどのコレクションクラスでは、基本データ型のデータは格納できません。 参照型のデータしか格納できないのです。 そこでint型の整数値をこれらに格納するときは、そのラッパークラスであるInteger型に変換して格納します。

またラッパークラスには、前項で述べた文字列をint型に変換するparseIntメソッドや10進→16進変換など基数の変換をするメソッドなどそれぞれの数値の処理に役立つメソッド群が用意されています。

ArrayListクラス

複数のデータを扱う時には配列が便利でした。 しかし配列は初期化時に指定したサイズを変更することができません。 また、配列の並びの途中に新たなデータを挿入するのはかなり大変です。 このような問題を解決するためにJavaではコレクションフレームワークと言う便利なクラス群が用意されています。 これを使うとデータを様々な構成でグルーピングすることができます。

ArrayListは代表的なコレクションフレームワークです。 ArrayListはサイズが変更できる配列といえます。 生成時に一定サイズを確保し、その後、要素の追加に応じてサイズを自動的に拡張します。 ArrayListでは、データの追加(add)、取得(get)、検索(indexOf)、削除(remove)、置換(set)などの操作が可能です。

ArrayListの生成

配列では生成時にサイズの指定が必要でした。 以下は2章で提示した配列を生成するコードですが、サイズとして 5 を指定しています。

        String[] str = new String[5];
		

ArrayListは配列と違って生成時に格納サイズを指定する必要がありません。 以下はString型のデータを格納するArrayListを生成する例です。

        List<String> ar = new ArrayList<>();
		

ただしArrayListでもサイズの初期値は指定できます。 以下は初期値として 30 を指定する例です。 使うサイズが予測できる場合は、このように初期サイズを指定することで性能を向上させることができます。 この場合 30 を越える数のデータを格納しようとすると、Javaの処理系が自動的にサイズを拡張します。 (配列では範囲を越えるとArrayIndexOutOfBoundsExceptionという例外が発生するのでした)

        List<String> ar = new ArrayList<>(30);
		

ArrayListには参照型のデータしか格納できません。 int型など基本データ型のデータは前項で説明した「ラッパークラス」にして格納する必要があります。

使い方の例

ArrayListの使い方を例で示します。 ArrayListクラスはjava.utilパッケージ内にあるので、使うときはjava.util.*;をimportしておく必要があります。

		List<String> ar = new ArrayList<>(); // arを生成
		ar.add("東京");                 // arの先頭(位置0)に"東京"を追加
		ar.add("大阪");                 // 次の位置(位置1)に"大阪"を追加
		int ix = ar.indexOf("大阪");    // "大阪"の位置を検索, ixは1になる
		String st = ar.get(ix);         // 位置ixの要素を取得, stは"大阪"になる
		ar.set(ix,"横浜");              // 位置ixの要素を"横浜"に置き換える
		int n = ar.size();              // arの要素数を取得, nには2が入る
		System.out.println(ar);         // arの内容 [東京, 横浜] が出力される
		

int型のデータを格納する例
前述のようにint型のような基本データ型は直接は格納できないので、intのラッパークラスであるInteger型を指定して生成します。 そして、本来は 01: のようにIntegerインスタンスを生成してそれを格納すべきですが、02: のように書いてもオートボクシング機能が働いてちゃんと処理してくれます。

	  01:   int_ar.add(new Integer(12));
	  02:   int_ar.add(12);
		

また、読み出し時にも本来は以下の 03: のようにintValueメソッドでInteger型をint型に変換して格納すべきですが、オートアンボクシング機能が働くので 04: のようにint型への変換指示を省略することもできます。

	  03:   int i1 = int_ar.get(0).intValue();
	  04:   int i2 = int_ar.get(1);
		

その他のコレクションフレームワーク

コレクションフレームワークにはArrayListの他にも多くのクラスがあります。 ここではその中で主なものを紹介します。

LinkedListクラス

LinkedListはArrayListと同じように、順序データを管理しますが、次のような違いがあります。 すなわち、ArrayListはデータの追加や削除が列の末尾を除いて得意でないのに対し、LinkedListは列の先頭へのデータの挿入、削除も得意です。

逆にArrayListは位置(index)を指定してのデータの取り出しが高速なのに対し、LinkedListは、これが苦手です。 それは、LinkedListはその名の通りLink構造になっているからです。 LinkedListでは、データの登録(add、addFirst、addLast)、取得(get、getFirst、getLast)、登録確認(contains)、検索(indexOf)、削除(remove)、置換(set)などの操作が可能です。

LinkedListの使い方を例で示します。 LinkedListクラスもjava.utilパッケージ内にあるのでjava.util.*;をimportしておく必要があります。 LinkedListでも格納できるのはObject型だけです。

	01:   LinkedList<String> lk = new LinkedList<>();       // lkを生成
	02:   lk.add("aaa");                  // lkに"aaa"が格納される
	03:   lk.add("bbb");                  // "aaa"の次に"bbb"が格納, "aaa""bbb"の順
	04:   lk.addFirst("ccc");             // 先頭に"ccc"が格納, "ccc""aaa""bbb"の順
	05:   lk.addFirst("ddd");             // 先頭に"ddd"が格納, "ddd""ccc""aaa""bbb"の順
	06:   String sf = lk.getFirst();      // sfには先頭の要素"ddd"が代入される
	07:   String sl = lk.getLast();       // slには末尾の要素"bbb"が代入される
		

HashMapクラス

HashMapクラスにはキー(key)と値(value)とがペアで格納できます。 HashMapでは、データの登録(put)、値の取得(get)、登録確認(containsKey)、削除(remove)などの操作が可能です。 HashMapでも格納できるのは(キー、値ともに)Object型だけです。

Listではデータに順番(アドレス)を付けて管理していましたが、Mapではデータ(value)にはアドレスは付けず、その代わりにキー(key)という文字列を付加して管理します。 またHashとは与えられたデータから整数値を算出する技術のことです。 すなわちHashMapという名前はHash技術を使ったMap構造のデータを扱うことを示しています。Mapには、この他にTree(木)技術を使ってデータを管理するTreeMapというクラスもあります。

HashMapの使い方を例で示します。 HashMapクラスもjava.utilパッケージ内にあるのでjava.util.*;をimportしておく必要があります。 すでに登録されているキーが再度登録されると、新しい値(value)が古い値に上書きされます。 未登録のキーでgetしようとすると、nullが返ります。

	01:   Map<String,String> hm = new HashMap<>();       // hmを生成
	02:   hm.put("one", "onett");
	03:   hm.put("two", "twoson");
	04:   hm.put("one", "threek");        // 当初のonettは上書きされ消えてしまう
	05:   String s = hm.get("two");       // sにはtwosonが代入される
	06:   System.out.println(hm);         // [one=threek, two=twoson] と出力される
		

コレクションインターフェース ★

コレクションフレームワークは、データの基本的な構成法に対応したインターフェースを定め、それを実装する形でクラスが提供されています。 例えばArrayListとLinkedListは同じListインターフェースを実装しています。 したがって、これらにはListインターフェースが規定したadd、get、remove、setなどのメソッドを備えていることが保証されています。 主なコレクションインターフェースとそれを実装したクラスは次の通りです。

        List    順序のある要素を扱う。(ArrayList,LinkedListなど)
        Map     キーと値のペアで管理。順序は保証されない。(HashMapなど)
        Set     重複を許さない要素を扱う。(HashSet,TreeSetなど)
		

イテレータ

繰り返し処理を巧みに行う手段としてIterator(イテレータ)インターフェースが準備されています。 hasNext()メソッドで次の要素の有無を調べ、存在すればnext()メソッドでそれを取り出すことができます。 next()メソッドは取り出した後、要素の位置を1つ進めます。 以下はlistの内容をすべて出力するプログラムの例です。

	01:   Iterator<String> it = list.iterator();
	02:   while (it.hasNext()) {
	03:     String str = it.next();
	04:     System.out.println (str);
	05:   }
		

【確認問題】 8.3

以下の説明のうち正しいものを全部選択してください。


(1)HashMapクラスに格納できるのは文字列型のみである。
(2)LinkedListはArrayListに比べてデータの更新が得意である。
(3)Mapインターフェースではデータの登録の順序は保証されない。


列挙型

関連する定数をまとめ全体に名前をつけて管理することができます。 これを列挙型と言います。 列挙型はenumというキーワードを使って宣言します。 列挙型を宣言する例を挙げます。

        enum Janken {
          GU,CHOKI,PA   // ジャンケンで使う"手"の名前を列挙
        }
		

enumはenumerationの略です。 enumerationは辞書を引くと数え上げること、列挙、一覧などと書かれています。 enumはイーナムとかイニューム、エナムなど人によって様々な読み方をします。 列挙型は最上位のレベル(クラスと同レベル)およびクラスの中(メソッドと同レベル)の2種類の場所で記述できます。 メソッドの中では記述できません。

列挙型で宣言するのは定数なので、その名前は上の例のように全部を大文字で書くのが普通です(1章の 識別子の命名規則の慣用規則参照)。 上で定義した列挙型の利用法の例を示します。

        Janken j = Janken.GU;   // 代入
        System.out.println(j);  // GUと表示される

        if (j == Janken.PA){    // 比較

        switch(j) {             // switch文の評価式として使う
          case CHOKI:           // case文には Janken. は不要

        j = Janken.GUU;         // GUUが未定義なのでコンパイルエラーになる
                // コンパイルの段階で誤りを発見できる→誤りの少ないプログラムになる
		

このように、列挙型として宣言すると定数が統一的に管理でき、誤りの少ないプログラムを書くことができます。

書式付きプリント文(printf文)

書式付きプリント文(printf文)を使うと印刷の縦位置や小数点位置がきれいに揃った表を簡単に印刷することができます。 printfメソッドは以下のように記述します。

        printf(書式文字列, データを与える引数…);
		

最初の引数は書式を指定するための書式文字列、それ以降の引数はデータを与える引数です。 データを与える引数はデータの数だけ指定できます。 可変長引数ですね。

printf文の例を示します。

        System.out.println("商品コード|  単価 | 個数 |    小計   ");
        System.out.println("----------+-------+------+-----------");
        System.out.printf("%-10s|%7.2f|%6d|%,10.2f\n","JDK700207",33.3,102,3396.6);
        System.out.printf("%-10s|%7.2f|%6d|%,10.2f\n","AP2546",57.0,28,1596.0);
		

これらの文を実行すると、次のようにきれいに出力されます。

        商品コード|  単価 | 個数 |    小計
        ----------+-------+------+-----------
        JDK700207 |  33.30|   102|  3,396.60
        AP2546    |  57.00|    28|  1,596.00
		

書式文字列には、データの前後にどの程度の余白を取るか、小数点以下の桁数をいくつにするか、3桁ごとにカンマを入れるかなどの書式が指定できます。 書式文字列にはそのまま出力する固定のテキスト(上の例では |)と、その中に埋め込まれた書式指示子からなります。

書式指示子は % で始まり s,f,d などのアルファベットで終わります。 このアルファベットを変換文字と言い、出力する値の形式を指定します。 書式指示子は次のような構造になっています。

        % [フラグ] [幅] [.詳細] 変換文字
		

書式指示子の各要素の主な意味を示します。

  • フラグ - 以下のような書式に関するオプションを指定します。
    -:左揃え、0:頭に0を詰める、+:常に符号を付加、,:3桁ごとにカンマを付加
    上記で「-」以外は数字のみに適用されます。
  • 幅 - 出力エリアの最小幅を示します。 データの幅がこれより大きければこの値を越えて印刷されます。
  • 詳細 - 文字列の時は出力する文字数、数字の時は小数点以下の桁数を指定します。
  • 変換文字 - 出力する値の形式を指定します。 以下はその例です。
    c:文字、d:10進整数、f:浮動小数点数、x:16進整数、s:文字列

書式指示子の使用例とその印刷結果を示します。 以下で ¥n は改行を表します。

        int a = 68;
        double b = 68.5;
        System.out.printf(" 1: %c\n", a);
        System.out.printf(" 2: %d\n", a);
        System.out.printf(" 3: %+5d\n", a);
        System.out.printf(" 4: %7.2f\n", b);
        System.out.printf(" 5: %04x\n", a);
        System.out.printf(" 6: |%s|\n", "January");
        System.out.printf(" 7: |%10s|\n", "January");
        System.out.printf(" 8: |%-10s|\n", "January");
        System.out.printf(" 9: |%.3s|\n", "January");
        System.out.printf("10: |%-10.3s|\n", "January");
		

印刷結果

         1: D
         2: 68
         3:   +68
         4:   68.50
         5: 0044
         6: |January|
         7: |   January|
         8: |January   |
         9: |Jan|
        10: |Jan       |
		
ページの先頭へ