JavaコレクションフレームワークインターフェイスのUnsupportedOperationException


12

Java Collections Frameworkを調べてみると、かなりの数のインターフェースにコメントがあることがわかりました(optional operation)。これらのメソッドを使用すると、クラスUnsupportedOperationExceptionを実装したくない場合にクラスを実装できます。

この例は、のaddAllメソッドSet Interfaceです。

さて、この一連の質問で述べられているように、インターフェースは、使用が期待できるものを定義する契約です。

インターフェースは、クラスが行うこととそれを行う方法を分離するため、重要です。クライアントが期待できるものを定義する契約により、開発者は契約を維持する限り、自由に実装できます。

そして

インターフェースとは、オブジェクトが実行できるアクションの説明です。たとえば、ライトスイッチをオンにしたとき、ライトが点灯したとき、どのように気にせず、それを行うだけです。オブジェクト指向プログラミングでは、インターフェイスとは、オブジェクトが「X」になるために必要なすべての機能の説明です。

そして

インターフェースベースのアプローチはかなり優れていると思います。その後、依存関係をうまくモックアウトできますが、基本的にはすべてがあまり密結合ではありません。

インターフェースのポイントは何ですか?

インターフェイスとは何ですか?

インターフェイス+拡張(mixin)vs基本クラス

インターフェースの目的はコントラクトを定義し、依存関係を疎結合にすることであるため、一部のメソッドでUnsupportedOperationException目的を達成できない場合がありますか?それは私がもう渡されSetずに使うことができないことを意味しますaddAll。むしろ、どの実装Setが渡されたかを知る必要があるためaddAll、使用できるかどうかを知ることができます。それは私にはかなり価値がないようです。

それで、何のポイントUnsupportedOperationExceptionですか?従来のコードを補うだけで、インターフェースをクリーンアップする必要がありますか?それとも、私が見逃しているより感覚的な目的がありますか?


どのJREを使用しているかわかりませんが、私のOracleバージョン8ではを定義addAllしていませんHashSet。これは、AbstractCollectionほとんど確実にスローしないデフォルトの実装に従いますUnsupportedOperationException

@スノーマンそうですね。ドキュメントを読み忘れました。質問を編集します。
MirroredFate

1
Eclipseを起動してソースコードを確認し、コード参照と定義をバウンスして、正しいことを確認します。JREがリンクされsrc.zipている限り、うまく機能します。JREがときどき実行しているコードを正確に把握し、少し冗長になる可能性のあるJavaDocに遅れをとらないようにするのに役立ちます。

回答:


12

次のインターフェイスを見てください。

これらのインターフェイスはすべて、変更メソッドをオプションとして宣言します。これは、Collectionsクラスが不変のインターフェイスの実装を返すことができるという事実を暗黙的に文書化したものです。つまり、これらのオプションの変更操作は失敗することが保証されています。ただし、JavaDocの規約に従って、これらのインターフェイスのすべての実装は読み取り操作を許可する必要があります。これは、例えば、「正常」実装含むHashSetLinkedList同様に不変ラッパーCollections

キューインターフェイスと比較して:

これらのインターフェイスは、オプションの操作を指定しません。キューは、定義により、FIFO方式で要素を提供およびポーリングするように設計されています。不変のキューは、車輪のない車と同じくらい便利です。


繰り返し登場する一般的なアイデアの1つは、可変オブジェクトと不変オブジェクトの両方を含む継承階層を持つことです。ただし、これらにはすべて欠点があります。複雑さは、実際に問題を解決することなく水を汚します。

  • 架空のSetものには読み取り操作があり、サブインターフェイスにMutableSetは書き込み操作があります。Liskovは、a MutableSetが必要なものに渡される可能性があることを教えてくれますSet。最初はこれで問題ありませんが、読み取り中に基になるセットが変更されないことを期待する方法を考えてください。2つのスレッドが同じセットを使用し、変化しないセットの不変式に違反する可能性があります。これは問題を引き起こす可能性があります。たとえば、メソッドがセットから要素を2回読み取り、2回目ではなく1回目です。

  • Set代わりにクラスを実装するために使用されるサブインターフェースを持ちMutableSetImmutableSetサブインターフェースとして直接実装することはできません。これには上記と同じ問題があります。階層のある時点で、インターフェイスに矛盾する不変条件があります。1つは「このセットは変更可能でなければならない」と言い、もう1つは「このセットは変更できない」と言います。

  • 可変および不変のデータ構造には、2つの完全に独立した階層があります。これは、追加トンの非常に小さなゲインされて終わる何のための余分な複雑さのを。これには、可変性を気にしないメソッドの特定の弱点もあります(たとえば、リストを反復したいだけです)。2つの個別のインターフェイスをサポートする必要があります。Javaは静的に型付けされるため、これは両方のインターフェース階層を処理する追加のメソッドを意味します。

  • 単一のインターフェイスを使用して、メソッドが適用できない場合に実装が例外をスローできるようにすることができます。これはJavaが採用したルートであり、最も理にかなっています。インターフェースの数は最小限に抑えられており、文書化されたインターフェースはいずれにせよ可変性について保証しないため、可変性不変条件はありません。不変性の不変式が必要な場合は、のラッパーを使用しCollectionsます。メソッドでコレクションを変更する必要がない場合は、単に変更しないでください。欠点は、メソッドが外部からコレクションを提供された場合、コレクションが別のスレッドで変更されないことを保証できないことですが、それは呼び出しメソッド(または呼び出しメソッド)の懸念事項です。


関連資料Java 8に不変コレクションが含まれないのはなぜですか?


1
しかし、メソッドがオプションである場合、それらはインターフェースのどこにありますか?たとえば、オプションのメソッドを含む別のインターフェイスはありませんMutableCollectionか?
MirroredFate

いいえ。意味のある方法で、同じ階層に可変オブジェクトと不変オブジェクトを配置する方法はありません。複雑さを示す良い図と、それが悪い考えである理由の説明がある最近の質問がありましたが、それは削除されました。他の誰かがこれを説明するのに役立つ質問を知っているかもしれませんが、何も見つかりません。しかし、少し説明するために回答を更新します。

これは、不変キューに関する一種の大まかな声明です。私が使用し1を解決するためにちょうど数日前にこの問題を
カールビーレフェルト

@Snowmanしかし、それはその可変オブジェクトと不変オブジェクトをお互いの反対として明らかにしているようです。不変オブジェクトとは、実際には、変異する能力のないオブジェクトにすぎないと思います。正直なところ、現在の方法はより複雑で混乱しています。何が可変実装で何がそうでないかを理解する必要があるからです。可変メソッドを分割するのではなく、すべてのメソッドを1つのインターフェイスに配置することの唯一の違いは、明確性の1つです。
MirroredFate

@MirroredFateは私の最新の編集を読みました。

2

基本的にはYAGNIです。標準ライブラリのすべての具象コレクションは可変であり、オプションの操作を実装または継承します。彼らは汎用の不変コレクションを気にせず、Java開発者の大多数も気にしません。不変のコレクションのためだけにインターフェース階層全体を作成するのではなく、実装を含めません。

一方、空のセットnCopiesなど、不変として非常に役立つ可能性のある特殊な値または「仮想」コレクションがいくつかあります。また、既存のJavaコードを呼び出したいサードパーティの不変コレクション(Scalaなど)があるため、不変コレクションを最小限の方法でオープンする可能性を残しました。


OK、それは理にかなっています。それでも、間違った方向から問題に近づいているようです。不変のコレクションインターフェイスを定義することから始めてから、可変のコレクション実装の可変インターフェイスを定義してみませんか?
MirroredFate
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.