- PR -

java.util.Collection インターフェイスについて

投稿者投稿内容
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-10-19 12:56
Collection インターフェイスに任意のオペレーションとして add() や remove() が定義されているのは何故なのでしょうか? Collection には add() や remove() などの任意のオペレーションを定義せずに、MutableCollection などのサブインターフェイスを作ったうえで、add() や remove() を定義すべきだったのではないでしょうか。

たとえば、Arrays#asList(Ojbect[]) が返す List は要素の追加/削除ができません。自分で Collection を引数に取り、add() や remove() で加工するような汎用メソッドを設計する場合も常に、UnsupportedOperationException を意識していなければなりません。

インターフェイスとはメソッドの実装保証を行うものではないのでしょうか。インターフェイスに「任意のオペレーション」などというものが存在していること自体が、インターフェイスの本質と矛盾しているように思えます。 Java のコレクションフレームワークでは、多態性のメリットが十分に活かされていないと諦めるほかないのでしょうか。

[ メッセージ編集済み 編集者: 未記入 編集日時 2004-10-19 13:00 ]
佐々木
大ベテラン
会議室デビュー日: 2003/03/30
投稿数: 121
投稿日時: 2004-10-19 13:15
引用:

未記入さんの書き込み (2004-10-19 12:56) より:
Collection インターフェイスに任意のオペレーションとして add() や remove() が定義されているのは何故なのでしょうか? Collection には add() や remove() などの任意のオペレーションを定義せずに、MutableCollection などのサブインターフェイスを作ったうえで、add() や remove() を定義すべきだったのではないでしょうか。



Java コレクション API の設計に関する FAQによると、これは、「API 全体でもっとも議論の余地のある設計上の決定事項」らしいです。

APIが複雑になりすぎない適当な妥協点が今の形である、ということらしいですね。
僕はJoshua Blochの大ファンなのでこのFAQの説明でコロッと納得しました…
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-10-19 14:00
unibon です。こんにちわ。

引用:

未記入さんの書き込み (2004-10-19 12:56) より:
たとえば、Arrays#asList(Ojbect[]) が返す List は要素の追加/削除ができません。自分で Collection を引数に取り、add() や remove() で加工するような汎用メソッドを設計する場合も常に、UnsupportedOperationException を意識していなければなりません。


私も、この状況は変だと思います。しかし、これは、コレクション API の問題、というよりも、Arrays#asList(Ojbect[]) の問題、と(言い様によっては)言えるかもしれません。
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/util/Arrays.html#asList(java.lang.Object[])
を見ると javadoc には、「固定サイズのリストを返します」とは書かれています。しかし、これが add/remove ができないことを意味するとは、かならずしも読み取れないかもしれません。javadoc にはむしろ、「java.util.Arrays.ArrayList クラスのインスタンスを返します」と書くべきのような気もします。こうすれば少なくとも、(API の内部コードを見ずとも)API の外部仕様を見さえすれば、UnsupportedOperationException の発生は避けることが可能です。
もっともこの場合は java.util.Arrays.ArrayList クラスの javadoc も提供する必要がありますが。
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-10-19 14:50
引用:

javadoc にはむしろ、「java.util.Arrays.ArrayList クラスのインスタンスを返します」と書くべきのような気もします。こうすれば少なくとも、(API の内部コードを見ずとも)API の外部仕様を見さえすれば、UnsupportedOperationException の発生は避けることが可能です。


内部クラス ArrayList について明文化するだけでは何も解決しないような気がします。内部クラス ArrayList が AbstractList を継承している以上、add() や remove() の呼出可能性を持っているわけですから。Collection インターフェイスを持つ AbstractList を継承せずに
独自の内部クラス ImmutableList などを作れば、add() や remove() などの呼出可能性を完全に排除できます。…が、これでは Java標準のコレクションフレームワークから完全に仲間外れになってしまいます。

引用:

APIが複雑になりすぎない適当な妥協点が今の形である、ということらしいですね。


このFAQはじめて読みました。ありがとうございます。ただ、FAQを読んでもやはり納得はできませんでした。インターフェイスが増えすぎるという煩雑さを回避するメリットのために多態性を捨ててしまったというのは残念でなりません。

FAQ では、全組み合わせが必要という視点で煩雑さをアピールしていますが、本当に Collection, Set, List, Map に対して、それぞれ ModifiableCollection、ModifiableSet、ModifiableList、ModifiableMap が必要なのでしょうか。「可変性」だけをインターフェイス Modifiable として切り出し、Collection + Modifiable, Set + Modifiable, List + Modifiable, Map + Modifiable とするような設計は難しかったのでしょうか。そうすると、また別の矛盾を生み出してしまうのかな。
顔爺
ベテラン
会議室デビュー日: 2003/10/03
投稿数: 52
投稿日時: 2004-10-19 15:05
面白い話題ですので、参加します。

引用:

未記入さんの書き込み (2004-10-19 14:50) より:

FAQ では、全組み合わせが必要という視点で煩雑さをアピールしていますが、本当に Collection, Set, List, Map に対して、それぞれ ModifiableCollection、ModifiableSet、ModifiableList、ModifiableMap が必要なのでしょうか。「可変性」だけをインターフェイス Modifiable として切り出し、Collection + Modifiable, Set + Modifiable, List + Modifiable, Map + Modifiable とするような設計は難しかったのでしょうか。そうすると、また別の矛盾を生み出してしまうのかな。


同じ事を考えましたが、
「編集可能な List を返す」、「編集不能な List を返す」メソッドを表現するには、
ModifiableList,List の両方のインターフェースが必要だと思います。

# ミスタイプを修正

[ メッセージ編集済み 編集者: 顔爺 編集日時 2004-10-19 15:07 ]
あいつー
ベテラン
会議室デビュー日: 2004/05/20
投稿数: 89
投稿日時: 2004-10-19 15:07
あいつーです。

本質的な議論には参加できないのですが、
(べき論、というか三者三様になってしまいそうなので)

少なくとも、
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/util/Arrays.html#asList(java.lang.Object[])
の、返り値として内部クラスではなく、
単にListを記述しているのは混乱の元の様な気もします。
unibonさんが仰るように「固定サイズ」という文言だけでは不十分だと思われます。
というか、実装を見ないとそれが実質内部クラスである、
ということすらわからないのは如何なものかと思います。

[ メッセージ編集済み 編集者: あいつー 編集日時 2004-10-19 15:07 ]

[ メッセージ編集済み 編集者: あいつー 編集日時 2004-10-19 15:08 ]
未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2004-10-19 15:39
引用:

というか、実装を見ないとそれが実質内部クラスである、
ということすらわからないのは如何なものかと思います。


これこそが多態性の良さじゃないでしょうか。裏を返せば「実装を見なくても良い」ということになるわけですから。Arrays#asList(Object[]) は、List インターフェイスを返しているのですから、実装など気にせずに List として扱えばいいのです。本来は。

Arrays#asList(Object[]) は正しく List インターフェイスを実装したインスタンスを返しています。ですから、javadoc 記述含め Arrays にはなんら罪はないと思います。やはり、List インターフェイスであるにも関わらず、実装機能を見定めることができないという List インターフェイスの設計自体に問題があるように思えます。これでは、インターフェイスとしての役割を果たしるとは言えないのではないかと。

※ 多数のデータベースを統一的に扱う JDBC で Unsupported が存在するのは、まあ分からないでもないですが…。コレクションというコア部分で、インターフェイスが正しく機能していないのは残念です。昔は Java ってソフトウェア工学ヲタが作っているのかなー、と思っていましたが、最近は実装に合わせ妥協が結構あるなあ、と感じるようになりました。
あいつー
ベテラン
会議室デビュー日: 2004/05/20
投稿数: 89
投稿日時: 2004-10-19 16:30
あいつーです。

FAQを見る限り、Collection FrameWorkの思想としては、
なるべく簡便に使用できること、ということがあるように見受けられます。
それを考えるとある程度の妥協は致し方ないのかな、とも思えますね。
やはり考えていくと個々のインターフェースに対応する
「固定/変動」インターフェースが必要になってしまうと思います。
そうした場合、実装する際にもその冠をつけた名前で書くことになり
簡便に使用するという思想にそぐわなくなってしまう、とも言えるのかな、と。
# 意識しない場合はCollection、意識する場合はModifiableCollectionとつければ良い、という話もありますが。

インターフェースが幾ら増えても良いから、原理に基づいて実装してくれ、
というニーズがどれほどあるか、ということも考える必要がありそうですし。

・・・って、これこそべき論になってしまっているので、
自分はこの辺にしておきます。

--以下脇道--
個人的にはArrays.asListとCollection.toArrayの関連が微妙な気がしますが。
両方「橋渡し」として書かれているにもかかわらず、
参照元への反映の有無が異なるというのはどういうことなんでしょうかね。
単に新しいListを返すんじゃ駄目だったんでしょうか。
# 話がそれてしまいそうですが、まぁ、愚痴ということで

スキルアップ/キャリアアップ(JOB@IT)