Mam ten kod:
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, ", ");
}
Rozumiem:
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)
Jak by to było poprawne? Java.15
Odpowiedzi:
Sporo problemów z twoim kodem:
Po
Arrays.asList
zwróceniu listy o stałym rozmiarzeZ interfejsu API:
Nie możesz tego
add
zrobić; nie możeszremove
z tego. Nie możesz modyfikować strukturalnieList
.Naprawić
Utwórz
LinkedList
, który obsługuje szybciejremove
.Po
split
przyjęciu wyrażenia regularnegoZ interfejsu API:
|
jest metaznakiem wyrażenia regularnego; jeśli chcesz podzielić na literał|
, musisz uciec od niego\|
, który jest literałem łańcuchowym Java"\\|"
.Naprawić:
Na lepszy algorytm
Zamiast dzwonić
remove
pojedynczo za pomocą losowych indeksów, lepiej jest wygenerować wystarczającą liczbę liczb losowych w zakresie, a następnie przejśćList
raz za pomocą alistIterator()
, sprawdzającremove()
odpowiednie wskaźniki. Istnieją pytania dotyczące przepływu stosu, jak generować losowe, ale odrębne liczby w danym zakresie.Dzięki temu twój algorytm byłby
O(N)
.źródło
Random
za każdym razem. Zrób tostatic
pole i zasiej je tylko raz.Ten spalił mnie wiele razy.
Arrays.asList
tworzy listę niemodyfikowalną. Z Javadoc: Zwraca listę o stałym rozmiarze wspieraną przez określoną tablicę.Utwórz nową listę o tej samej treści:
Spowoduje to wytworzenie dodatkowego śmieci, ale będziesz mógł je mutować.
źródło
Prawdopodobnie dlatego, że pracujesz z niemodyfikowalnym opakowaniem .
Zmień tę linię:
do tej linii:
źródło
unmodifiable
iimmutable
.unmodifiable
oznacza dokładnie „modyfikowalny, ale nie strukturalnie”.unmodifiableList
opakowanie i spróbowaćset
; rzucaUnsupportedOperationException
. Jestem całkiem pewien,Collections.unmodifiable*
że naprawdę oznacza pełną niezmienność, a nie tylko konstrukcję.Myślę, że zastępując:
z
rozwiązuje problem.
źródło
Lista zwrócona przez
Arrays.asList()
może być niezmienna. Mógłbyś spróbowaćźródło
Po prostu przeczytaj JavaDoc dla metody asList:
To jest z Java 6, ale wygląda na to, że tak samo jest z Androidem Java.
EDYTOWAĆ
Typ wynikowej listy to
Arrays.ArrayList
prywatna klasa Arrays.class. Praktycznie rzecz biorąc, jest to tylko widok listy w tablicy, którą przekazałeśArrays.asList
. W konsekwencji: jeśli zmienisz tablicę, lista również się zmieni. A ponieważ rozmiaru tablicy nie można zmienić, operacja usuwania i dodawania musi być nieobsługiwana.źródło
Arrays.asList () zwraca listę, która nie zezwala na operacje wpływające na jej rozmiar (zwróć uwagę, że nie jest to to samo co „niemodyfikowalne”).
Możesz zrobić,
new ArrayList<String>(Arrays.asList(split));
aby stworzyć prawdziwą kopię, ale widząc, co próbujesz zrobić, oto dodatkowa sugestia (maszO(n^2)
algorytm poniżej).Chcesz usunąć
list.size() - count
(nazwijmy tok
) losowe elementy z listy. Po prostu wybierz tyle losowych elementów i zamień je na końcowek
pozycje listy, a następnie usuń cały zakres (np. Używając subList () i clear ()). To zmieniłoby go w uproszczony i średniO(n)
algorytm (O(k)
jest bardziej precyzyjny).Aktualizacja : Jak zauważono poniżej, ten algorytm ma sens tylko wtedy, gdy elementy są nieuporządkowane, np. Jeśli lista reprezentuje torbę. Z drugiej strony, jeśli lista ma znaczącą kolejność, algorytm nie zachowałby jej (zamiast tego algorytm wieloskładnikowy).
Aktualizacja 2 : Z perspektywy czasu lepszy (liniowy, zachowujący porządek, ale z liczbami losowymi O (n)) byłby mniej więcej taki:
źródło
ArrayList
. O wiele prostsze niż moja sugestia. Myślę jednak, że spowodowałoby to zmianę kolejności elementów.Mam inne rozwiązanie tego problemu:
pracować nad
newList
;)źródło
Ten wyjątek UnsupportedOperationException pojawia się, gdy próbujesz wykonać pewne operacje na zbiorze, w których jest to niedozwolone, aw twoim przypadku, gdy zadzwonisz
Arrays.asList
, nie zwraca ajava.util.ArrayList
. Zwracajava.util.Arrays$ArrayList
listę niezmienną. Nie możesz go dodać i nie możesz go usunąć.źródło
Tak, wł
Arrays.asList
, zwracanie listy o stałym rozmiarze.Inne niż użycie listy połączonej, po prostu użyj
addAll
listy metod.Przykład:
źródło
Zastąpić
do
lub
lub
lub (Lepiej usuń elementy)
źródło
Arraylist narraylist = Arrays.asList (); // Zwraca niezmienną listę arraylistyczną Aby zmienne rozwiązanie było możliwe: Arraylist narraylist = new ArrayList (Arrays.asList ());
źródło
Poniżej znajduje się fragment kodu z tablic
więc co się dzieje, gdy wywoływana jest metoda asList, wówczas zwraca listę swojej prywatnej wersji klasy statycznej, która nie zastępuje dodawania funkcji z AbstractList do przechowywania elementu w tablicy. Więc domyślnie metoda dodawania w liście abstrakcyjnej zgłasza wyjątek.
Nie jest to więc zwykła lista tablic.
źródło
Nie można usunąć ani dodać do listy tablic o stałym rozmiarze.
Ale możesz utworzyć swoją listę podrzędną z tej listy.
list = list.subList(0, list.size() - (list.size() - count));
* Innym sposobem jest
spowoduje to utworzenie ArrayList, który nie ma ustalonego rozmiaru, jak Arrays.asList
źródło
Arrays.asList()
korzysta wewnętrznie z tablicy o stałym rozmiarze.Nie możesz dynamicznie dodawać ani usuwać z tego
Arrays.asList()
Użyj tego
W
narraylist
możesz łatwo dodawać lub usuwać elementy.źródło
Utworzenie nowej listy i wypełnienie prawidłowych wartości na nowej liście działało dla mnie.
Błąd generowania kodu -
Po naprawie -
źródło