2017-07-07 4 views
25

リストの一部が固定サイズかどうかを調べることはできますか? Iは、例えば、このコードを意味する:配列によって裏付けサイズList固定一部のリストが固定サイズかどうかを調べることはできますか?

String[] arr = {"a", "b"}; 
List<String> list = Arrays.asList(array); 

戻ります。しかし、要素を追加/削除して例外をキャッチしないで、Listが固定サイズかどうかをプログラムで理解することは可能ですか?たとえば:

try { 
    list.add("c"); 
} 
catch(UnsupportedOperationException e) { 
    // Fixed-size? 
} 
+0

例外を使用できないのはなぜですか? @RC。 –

+6

彼はそれができないと言わなかったが、それを行う別の方法があれば理想的ではない。例外は遅く、例外的な条件です。 – Michael

+7

有権者を閉じるには、これがどのように不明であるか説明してください。私は彼が求めていることを完全に理解しています。 – Michael

答えて

6

は、それはいくつかのリストが固定サイズであるかどうかを調べることはできますか?

理論上 - いいえ。固定サイズは、リストクラスの実装の緊急の特性です。要素を追加しようとすると、リストにそのプロパティがあるかどうかだけを判断できます。

単純な動作テストでは、固定サイズのリストと制限付きリストまたは永続的にあったリ​​スト、または一時的にの読み取り専用を確実に区別できないことに注意してください。実際に


、固定サイズのリストは通常は通常のものと異なるクラスを持つことになります。オブジェクトのクラスをテストして、それが特定のクラスであるかどうかを調べることができます。したがって、のクラスがの固定サイズのリストをコードベースに実装するのに使用されるクラスを理解していれば、特定のリストが固定サイズかどうかをテストできます。

たとえば、Arrays.asList(...)メソッドは、実際のクラスがjava.util.Arrays.ArrayListListオブジェクトを返します。これはプライベートネストされたクラスですが、リフレクションを使用して見つけてObject.getClass().equals(...)を使用してテストしてください。

しかし、このアプローチは脆弱です。 Arraysの実装が変更された場合や、他の形式の固定サイズのリストを使用した場合でも、コードが壊れる可能性があります。例えばnew ArrayList()ためにより作成された一つが囲みクラスを持っていないであろうしながら

List<String> list = Arrays.asList(array); 

によってString[]から作成

14

リストは、クラスを囲むようArraysを有するであろう。

static <T> boolean wasListProducedAsAResultOfCallingTheFunctionArrays_asList(List<T> l) { 
    return Arrays.class.equals(l.getClass().getEnclosingClass()); 
} 

は、この方法が文書化されていない動作に依存していることに注意してください:だから次はリストがArrays.toList()を呼び出した結果として生成されたかどうかを確認するために動作するはずです。 Arraysクラスに別のネストされたListサブクラスを追加すると、破損します。

+2

いいです。 'isFixedSize'はその関数の誤った名前です。 – Michael

+0

@マイケルありがとう。より良い名前がありますか? – baao

+10

[多分 'wasListProducedAsAResultOfCallingTheFunctionArrays_asList'](https://martinfowler.com/bliki/TwoHardThings.html)を自由に編集できますか? – Michael

2

リストAPIは、関係なく、リストは拡張可能であるかどうかのかdeliberateた何か同じです。

List APIには、この機能を判断するためにクエリを実行できるものもありません。

この情報は、実装の内部の詳細に依存するため、固定サイズの可能性のある無限の数のクラスが存在するため、完全に信頼できるものではありません。たとえば、Arrays.asListに加えて、Arrays.asList().subListもあります。この場合、別のクラスが返されます。ベースリストの周りには、Collections.checkedList,Collections.synchronizedListCollections.unmodifiableListのようなラッパーもあります。他の固定サイズのリスト:Collections.emptyList,Collections.singletonList、およびCollections.nCopiesもあります。標準ライブラリの外には、GuavaのImmutableListのようなものがあります。 AbstractListを拡張することで何かのリストをハンドリングすることも非常に簡単です(固定サイズのリストの場合は、size()get(int)メソッドを実装するだけです)。

あなたのリストが固定サイズではないことが検出されたとしても、List.addの指定により、他の理由で要素を拒否することができます。たとえば、Collections.checkedListラッパーは、不要な要素の要素に対してClassCastExceptionをスローします。

あなたのリストが拡張可能であり、任意の要素を許可していることを知っていても、それはあなたがそれを使いたいというわけではありません。おそらく、同期されているか、同期されていない、またはシリアライズ可能ではない、またはリンクが遅いリスト、または望まないいくつかの品質があります。

リストの型、変更可能性、シリアル化可能性、またはスレッドセーフティを制御したい場合や、他のコードが参照を保持していないことを確認したい場合は、新しいものを作成することですあなた自身。不要なとき(memcopiesが高速化しているとき)にはコストがかからず、実行時に実際にコードが実行されることをより確実に推論できます。不要なコピーを避けたい場合は、リストクラスをブラックリストにする代わりに、ホワイトリスト登録を試してみてください。 (注意:これはgetClass代わりのinstanceofを使用して、instanceofArrayListのいずれかの奇妙なサブクラスのための真になるので)

if (list.getClass() != ArrayList.class) { 
    list = new ArrayList<>(list); 
} 

:たとえば

+0

素晴らしい答え。 – Michael

0

のjava-9で不変コレクションがありますが、そこですやはり共通の@Immutable注釈や、この情報を得るために照会できる一般的なマーカーインターフェースはありません。

私は考えることができる最も簡単な方法は、このようなインスタンスのクラス名を取得するには、単に次のようになります。

String nameList = List.of(1, 2, 3).getClass().getName(); 
System.out.println(nameList.contains("Immutable")); 

が、それは一般的なクラスの名前を照会するので、まだ、内部の詳細に依存していることImmutableCollections、これは一般に公開されておらず、明らかに予告なく変更することがあります。