web-dev-qa-db-ja.com

リストから要素を削除しようとすると、UnsupportedOperationExceptionが発生するのはなぜですか?

私はこのコードを持っています:

public static String SelectRandomFromTemplate(String template,int count) {
   String[] split = template.split("|");
   List<String> list=Arrays.asList(split);
   Random r = new Random();
   while( list.size() > count ) {
      list.remove(r.nextInt(list.size()));
   }
   return StringUtils.join(list, ", ");
}

私はこれを得ます:

06-03 15:05:29.614: ERROR/AndroidRuntime(7737): Java.lang.UnsupportedOperationException
06-03 15:05:29.614: ERROR/AndroidRuntime(7737):     at Java.util.AbstractList.remove(AbstractList.Java:645)

これはどのように正しい方法でしょうか。 Java.15

412
Pentium10

あなたのコードにかなりの数の問題があります:

Arrays.asListが固定サイズのリストを返すとき

APIから:

Arrays.asList :指定された配列を元にした 固定サイズのリスト を返します。

あなたはそれをaddすることはできません。あなたはそこからremoveできません。 Listを構造的に変更することはできません。

修正する

高速なLinkedListをサポートするremoveを作成します。

List<String> list = new LinkedList<String>(Arrays.asList(split));

正規表現を取っているsplit

APIから:

String.split(String regex) :この文字列を与えられた 正規表現 のマッチの周りで分割します。

|は正規表現のメタキャラクタです。リテラル|を分割したい場合は、それを\|にエスケープする必要があります。これは、Javaストリング・リテラルとしての"\\|"です。

修正:

template.split("\\|")

より良いアルゴリズムについて

ランダムなインデックスでremoveを一度に1つずつ呼び出すのではなく、範囲内で十分な乱数を生成してから、listIterator()Listを1回トラバースし、適切なインデックスでremove()を呼び出します。与えられた範囲でランダムだが異なる数を生成する方法については、スタックオーバーフローについての質問があります。

これで、あなたのアルゴリズムはO(N)になるでしょう。

885

これは私を何度も燃やしました。 Arrays.asListは変更不可能なリストを作成します。 Javadocから:指定された配列を基にした 固定長 のリストを返します。

同じ内容の新しいリストを作成します。

newList.addAll(Arrays.asList(newArray));

これは少し余分なゴミを作成しますが、あなたはそれを変異させることができるでしょう。

118
Nick Orton

おそらくあなたが 修正不可能なラッパー を使っているからです。

この行を変更してください。

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

この行に:

List<String> list = new LinkedList<>(Arrays.asList(split));
45
Roman

私はそれを置き換えると思います:

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

List<String> list = new ArrayList<String>(Arrays.asList(split));

問題を解決します。

11
Salim Hamidi

Arrays.asList()によって返されるリストは不変かもしれません。試してもらえますか

List<String> list = new ArrayList(Arrays.asList(split));
4
Pierre

AsListメソッドのJavaDocを読んでください。

指定された配列内のオブジェクトの{@code List}を返します。 {@code List}のサイズは変更できません。つまり、追加と削除はサポートされていませんが、要素は設定できます。要素を設定すると、基になる配列が変更されます。

これはJava 6からのものですが、Android Javaでも同じです。

_編集_

結果のリストの型はArrays.ArrayListです。これはArrays.class内のプライベートクラスです。実際には、これはArrays.asListで渡した配列のリストビューに他なりません。その結果、配列を変更するとリストも変更されます。また、配列はサイズ変更できないため、削除と追加の操作はサポートされていません

4
Andreas_D

Arrays.asList()は、サイズに影響する操作を許可しないリストを返します(これは「変更不可能」と同じではないことに注意してください)。

実際のコピーを作成するためにnew ArrayList<String>(Arrays.asList(split));を実行することもできますが、自分が何をしようとしているのかを確認するための追加の提案があります(その下にO(n^2)アルゴリズムがあります)。

リストからlist.size() - count(これをkと呼びましょう)ランダム要素を削除します。無作為の要素をいくつでも選んで、それらをリストの最後のkの位置に交換してから、その範囲全体を削除してください(たとえば、subList()およびclear()を使用して)。それは無駄のないそしてO(n)アルゴリズムを意味するでしょう(O(k)はより正確です)。

更新 :下記のように、このアルゴリズムは要素が順序付けられていない場合にのみ意味を持ちます。リストがバッグを表す場合一方、リストに意味のある順序がある場合、このアルゴリズムはそれを保持しません(代わりにpolygenelubricantsのアルゴリズムが保持します)。

更新2 :それでは振り返ってみると、より良い(線形、順序を維持するがO(n)乱数を使った)アルゴリズムは次のようになるだろう。

LinkedList<String> elements = ...; //to avoid the slow ArrayList.remove()
int k = elements.size() - count; //elements to select/delete
int remaining = elements.size(); //elements remaining to be iterated
for (Iterator i = elements.iterator(); k > 0 && i.hasNext(); remaining--) {
  i.next();
  if (random.nextInt(remaining) < k) {
     //or (random.nextDouble() < (double)k/remaining)
     i.remove();
     k--;
  }
}
4

私はその問題に対する別の解決策を得ました:

List<String> list = Arrays.asList(split);
List<String> newList = new ArrayList<>(list);

newList;)で作業する

3
ZZ 5

このUnsupportedOperationExceptionは、コレクションに対して許可されていない操作を実行しようとしたときに発生します。この場合、Arrays.asListを呼び出してもJava.util.ArrayListは返されません。不変リストであるJava.util.Arrays$ArrayListを返します。あなたはそれに追加することはできませんし、あなたはそれから削除することはできません。

2
Mayank Gupta

はい、Arrays.asListでは固定サイズのリストを返します。

リンクリストを使用する以外に、単にaddAllメソッドリストを使用してください。

例:

String idList = "123,222,333,444";

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

parentRecepeIdList.addAll(Arrays.asList(idList.split(","))); 

parentRecepeIdList.add("555");
2
Sameer Kazi

Arraylist narraylist = Arrays.asList(); //不変の配列リストを返します可変ソリューションを作成するには、Arraylist narraylist = new ArrayList(Arrays.asList());

1
BruceWayne

削除することも、固定サイズの配列リストに追加することもできません。

しかし、あなたはそのリストからあなたのサブリストを作成することができます。

list = list.subList(0, list.size() - (list.size() - count));

public static String SelectRandomFromTemplate(String template, int count) {
   String[] split = template.split("\\|");
   List<String> list = Arrays.asList(split);
   Random r = new Random();
   while( list.size() > count ) {
      list = list.subList(0, list.size() - (list.size() - count));
   }
   return StringUtils.join(list, ", ");
}

*他の方法は

ArrayList<String> al = new ArrayList<String>(Arrays.asList(template));

これは、Arrays.asListのように固定サイズではないArrayListを作成します。

1
Venkat

交換する

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

List<String> list = New ArrayList<>();
list.addAll(Arrays.asList(split));

または

List<String> list = new ArrayList<>(Arrays.asList(split));

または

List<String> list = new ArrayList<String>(Arrays.asList(split));

または(要素を削除する方が良い)

List<String> list = new LinkedList<>(Arrays.asList(split));
1

以下は配列のコードの一部です。

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

    /**
     * @serial include
     */
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, Java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

そのため、asListメソッドが呼び出されると、AbstractListのadd関数を配列の要素に格納することをオーバーライドしない、独自のプライベート静的クラスバージョンのリストが返されます。そのため、デフォルトでは抽象リストのaddメソッドは例外をスローします。

そのため、通常の配列リストではありません。

1
Gagandeep Singh

Arrays.asList()は内部的に固定サイズの配列を使います。
thisArrays.asList()に動的に追加または削除することはできません

これを使って

Arraylist<String> narraylist=new ArrayList(Arrays.asList());

narraylistでは、アイテムを簡単に追加または削除できます。

0
Roushan Kumar