SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

J2SE 5.0のコレクションの使い方を覚える

ジェネリック型とオートボクシングによって改良されたコレクションへのアクセス

  • X ポスト
  • このエントリーをはてなブックマークに追加

J2SE 5.0のコレクションは、よりシンプルに生まれ変わり、コードの記述量が減っただけでなく、プログラミング技法も変化しました。本稿では、J2SE 5.0で追加されたコレクションAPIの新機能を紹介します。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 コレクションAPIは、これまでずっとJava開発キット(JDK)の最も重要な要素の1つでした。ほとんどすべてのJavaプログラムは、HashMapArrayListTreeSetといったコレクションクラスを利用します。これらのクラスはそれぞれ異なる方法でデータを格納するため、たいていのJavaプログラマは、こうしたクラスがどのように動作するかや、どんな場合に利用すべきかをよく理解していました。しかし、J2SE 5.0のリリースによって、コレクションクラスの使い方はすっかり変わってしまいました。

 ありがたいのは、学習曲線が緩やかになったことです。実際、J2SE 5.0のコレクションAPIは、多くの点で簡素化されています。また、J2SE 5.0で採り入れられたさまざまな変更によって、必要なコードの記述量は旧バージョンのJavaよりも少なくなっています。

コレクションに関わるJ2SE 5.0の新機能

 本稿では、コレクションAPIに影響を及ぼす新機能を紹介します。具体的には、次の機能について説明していきます。

  • ジェネリック型
  • 拡張されたforループ
  • オートボクシング

 これらの技術はコレクションAPIに影響を与えています。本稿では、この3つの技術を利用したコレクションクラスのサンプルを紹介します(ソースコードについてはダウンロードサンプルを参照してください)。ここで、新しいコレクションAPIの機能を詳しく説明する前に、ジェネリック型の基本的な部分を解説しておきましょう。

ジェネリック型

 ジェネリック型は、コレクションAPIに追加された最も重要な要素です。拡張されたforループやオートボクシングの機能は、ジェネリック型に強く依存しています。ある程度C++に詳しい方には、Javaのジェネリック型とは「C++のテンプレートに相当するが、多くの点でテンプレートより優れたもの」と説明しておきましょう。ジェネリック型を使うと、コレクションに特定の型を関連付けることができます。J2SE 5.0より前のJavaコレクションは特定の型に関連付けることができず、これが原因で問題がいくつか起こっていました。なぜ問題が起きるのか、次のコードを参照しながら説明します。

import java.util.*;

public class BasicCollection {
  public static void main(String args[]) {
    ArrayList list = new ArrayList();

    list.add( new String("One") );
    list.add( new String("Two") );
    list.add( new String("Three") );

    Iterator itr = list.iterator();
    while( itr.hasNext() ) {
      String str = (String)itr.next();
      System.out.println( str );
    }
  }
}

 これは、J2SE 5.0より前のJavaでよく見られるコレクションクラスのサンプルコードです。このクラスでは、ArrayListを作成し、そこに3つの文字列を追加しています。しかし、このArrayListには特定の型が関連付けられていないことに注意してください。Objectクラスを継承しているクラスでさえあれば、どんなクラスでもArrayListに追加できます。

 次に、ArrayListから文字列を取り出すwhileループに注目してみましょう。

while( itr.hasNext() ) {
   String str = (String)itr.next();
   System.out.println( str );
}

 このループはArrayList内のすべてのアイテムに対して繰り返し処理を行います。ただし、取り出した各要素に対して必ず型変換をしなければなりません。なぜなら、このArrayListは格納すべき型を知らないからです。この問題は、Javaのジェネリック型によって解決されます。ジェネリック型を使えば、このArrayListに特定の型を関連付けることができます。そのため、このBasicCollectionクラスをジェネリック型を使って書き換えれば、さきほどの問題はなくなります。次に示すGenericCollectionクラスは、ジェネリック型を使って書き換えたものです。

import java.util.*;

public class GenericCollection {
  public static void main(String args[]) {
    ArrayList<String> list = new ArrayList<String>();

    list.add( new String("One") );
    list.add( new String("Two") );
    list.add( new String("Three") );
    //list.add( new StringBuffer() );

    Iterator<String> itr = list.iterator();
    while( itr.hasNext() ) {
      String str = itr.next();
      System.out.println( str );
    }
  }
}

 ご覧のとおり、J2SE 5.0用に変更されたこのクラスは、元のコードからほんの数行しか変わっていません。最初の変更箇所は、ArrayListの宣言を行っている行です。J2SE 5.0用のバージョンではString型を用いてArrayListを宣言しています。

   ArrayList<String> list = new ArrayList<String>();

 このコードが、どのようにして型とコレクションの名前を結び付けているかに注意してください。ジェネリック型を指定するには、コレクション名のすぐ後ろに山カッコ(<>)を記述し、その中に型の名前を指定します。

 次に、反復子(イテレータ)の宣言では、String型のためのIteratorを宣言します。このイテレータについても、ArrayListとまったく同じようにしてジェネリック型を指定します。たとえば、次のようになります。

Iterator<String> itr = list.iterator();

 この行は、Iteratorの型をStringに指定しています。これで、この反復子のnextメソッドを呼び出すときには、もう型変換を行わずに済みます。次のように普通にnextメソッドを呼び出すだけで、String型が返ってきます。

String str = itr.next();

 たしかにコードの記述量は減りますが、ジェネリック型は型変換を不要にするだけのものではありません。ジェネリック型を指定しておくと、ArrayListに「サポート外の型」を追加しようとしたときにコンパイルエラーが生成されるのです。では、「サポート外の型」とは何でしょうか。たとえば、今回の例ではArrayListStringを受けとるように宣言したため、String以外のクラスまたはStringのサブクラスがサポート外の型と見なされます。

 サポート外の型の一例として、StringBufferクラスを挙げましょう。今回の例では、ArrayListStringのみを受けとるので、StringBufferオブジェクトを格納することはできません。たとえば、次の行をプログラムに追加するのは誤りです。

list.add( new StringBuffer() );

 ここからがジェネリック型のすばらしいところですが、サポート外の型をArrayListに追加するコードを書いても、ランタイムエラーにはなりません。なぜなら、あらかじめコンパイル時にこの誤りが検出されるからです。この場合は、次のようなコンパイルエラーが発生します。

c:\collections\GenericCollection.java:12: 
   cannot find symbol
symbol  : method add(java.lang.StringBuffer)
location: class java.util.ArrayList<java.lang.String>
    list.add( new StringBuffer() );

 こうしたエラーをコンパイル時に検出できることは、バグのないコードを書こうとする開発者にとって非常に好都合です。J2SE 5.0より前のバージョンであれば、実行時になってClassCastExceptionが発生するまでこのエラーが見つからないことが多かったでしょう。どんな場合も、実行時にバグ発生の適切な条件が揃うのを待つより、コンパイル時にエラーを検出できるほうが好ましいはずです。というのも、この「適切な条件」というのは、導入が終わってこのプログラムをユーザが実行するまで発生しないことが多いからです。

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
拡張されたforループの利用

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Jeff Heaton(Jeff Heaton)

ライター、人工知能(AI)研究者、元大学教員。AI、仮想世界、スパイダー、ボットなどの話題を取り上げて執筆した書籍は10冊以上。Java、.Net、Silverlightを対象に、高度なニューラルネットワークおよびAIフレームワークの提供を目的とするオープンソースイニシアチブ、Encogプロジェクトを統括している。また、個人のWebサイトを管理し、人工知能とスパイダー/ボットプログラミングをはじめとする話題について情報発信を行っている。メールの宛先はjheaton@heatonresearch.com。Sun認定Javaプログラマ兼IEEEシニアメンバー。ミズーリ州セントルイスのワシントン大学情報管理修士号を持ち、セントルイス在住。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/278 2006/04/11 19:09

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング