Początkowy rozmiar ArrayList

257

Możesz ustawić początkowy rozmiar ArrayList, wykonując

ArrayList<Integer> arr=new ArrayList<Integer>(10);

Jednak nie możesz tego zrobić

arr.add(5, 10);

ponieważ powoduje wyjątek poza zakresem.

Po co ustawiać początkowy rozmiar, jeśli nie masz dostępu do przydzielonego miejsca?

Funkcja dodawania jest zdefiniowana w ten add(int index, Object element)sposób, więc nie dodam do indeksu 10.

Cemre
źródło
52
Właściwie, to nie jest oczywiste od docs że lista musi mieć co najmniej n elementów można dodać przed set/addpozycja n-1 .
Postrzeganie
5
Postrzeganie: Nie wiem, czy to oczywiste, ale jest określone. Należy uważnie przeczytać JavaDoc. Rzuty: IndexOutOfBoundsException - jeśli indeks jest poza zakresem (indeks <0 || indeks> = size ()).
Natix
3
Hm, konstruktor mówi „Konstruuje pustą listę o określonej pojemności początkowej”. Biorąc pod uwagę pustą listę, nie mogę być indeksem 5. Ale zgadzam się, że może to nie być widoczne na pierwszy rzut oka ...
quaylar
12
Myślę, że można również powiedzieć, że jeśli zainicjujesz tablicę do określonej wartości, założysz, że indeksy niższe niż ta wartość są dostępne - i to jest ArrayList. Ja osobiście chciałbym metody, która pozwoliłaby mi ustawić taki rozmiar, żebym mógł umieścić rzeczy według określonych wskaźników. Ta metoda wydaje się wyraźnie nieobecna.
Andrew Wyld
1
Jaki numbskull zaprojektował kolekcje w ten sposób ?! Wymusza to nadmiarową pracę dla równoległego tworzenia instancji struktury z elementami o zmiennej długości (tj. ArrayList <String []>, gdzie każda tablica może mieć inną długość). Jeśli pamięć jest już przydzielona, ​​więc lista nie wymaga ponownego przydzielenia po dodaniu N elementów, wskaźniki te powinny być dostępne od samego początku. Czy nikt w Oracle nie nauczył się tego wzoru po C / C ++, C #, Objective C i Swift ?!
patrickjp93

Odpowiedzi:

387

Mylisz rozmiar listy tablic z jej pojemnością:

  • rozmiar jest liczba elementów na liście;
  • pojemność to ile elementów lista potencjalnie może pomieścić bez realokacji swoich wewnętrznych struktur.

Kiedy dzwonisz new ArrayList<Integer>(10), ustawiasz początkową pojemność listy , a nie jej rozmiar. Innymi słowy, przy takiej konstrukcji lista tablic zaczyna życie pusta.

Jednym ze sposobów dodania dziesięciu elementów do listy tablic jest użycie pętli:

for (int i = 0; i < 10; i++) {
  arr.add(0);
}

Po wykonaniu tej czynności możesz teraz modyfikować elementy o indeksach 0..9.

NPE
źródło
51
+1: krótsza pętla: while(arr.size() < 10) arr.add(0);Przydatne może być stwierdzenie, że rozmiar musi wynosić co najmniej 10. np. możesz użyćarr.set(9, n);
Peter Lawrey,
10
+1: Świetna odpowiedź, dałbym +10, gdybym mógł. Z interfejsu API nie jest od razu oczywiste, dlaczego nie można ustawić ZARÓWNO początkowego rozmiaru, jak i początkowej pojemności w jednym wywołaniu konstruktora. W pewnym sensie musisz przeczytać interfejs API i powiedzieć „Och, chyba ArrayList nie ma metody ani konstruktora, aby to zrobić”
demongolem
@PeterLawrey Twój kod może być krótszy, ale zawiera dwa wywołania metod na iterację pętli, a nie tylko jedno.
neuralmer
@neuralmer Oczekiwałbym, że rozmiar () i add () będą wstawione, więc żadne rzeczywiste wywołanie metody nie wystąpi w czasie wykonywania.
Peter Lawrey,
109

Jeśli chcesz listę o zdefiniowanym rozmiarze, możesz także użyć:

List<Integer> arr = Arrays.asList(new Integer[10]);
Gert Jan Schoneveld
źródło
11
Nieznaczna wada tutaj, wynik Listjest pełen zer. Z Guava możemy to zrobić, Ints.asList(new int[10])co zainicjuje naszą listę za pomocą 0s. Jednak czysty wzór, dzięki za przykład.
dimo414,
1
Pytania dotyczą ArrayList <E>. Używasz listy <E>. Nikt tego nie zauważył ??? Co więcej, poparli tę nieistotną odpowiedź! Nie głosuję za twoją odpowiedzią, ponieważ nigdy nie. Po prostu ... Na miłość boską!
Apostolos
3
@Apostolos ArrayListjest implementacją Listinterfejsu i Arrays.asListzwraca an ArrayList. Proponuję spojrzeć na polimorfizm.
Liam Potter
Zwraca jednak Listę o ustalonym rozmiarze. Próbuję dodać więcej rzutów elementówUnsupportedOperationException
Koray Tugay
47

jeśli chcesz użyć Collections.fill (list, obj); w celu wypełnienia listy powtarzającym się obiektem można alternatywnie użyć

ArrayList<Integer> arr=new ArrayList<Integer>(Collections.nCopies(10, 0));

linia kopiuje 10 razy 0 do twojej ArrayList

Farzan Skt
źródło
20

Pojemność od ArrayListnie jest taka sama jak jego wielkości . Rozmiar jest równy liczbie elementów zawartych w ArrayList(i każdej innej Listimplementacji).

Pojemność tylko długość podstawowego matrycy, która jest stosowana do wewnętrznie przechowywania elementów ArrayList, i jest zawsze większy lub równy wielkości listy.

Podczas wywoływania set(index, element)listy indexodnosi się do faktycznej liczby elementów listy (= rozmiar) (która jest zerowa w kodzie, dlatego AIOOBEjest wyrzucana), a nie do długości tablicy (= pojemność) (która jest specyficzna dla szczegółów implementacji do ArrayList).

setMetoda jest wspólna dla wszystkich Listimplementacjach, takich jak LinkedList, które nie są faktycznie realizowane przez tablicę, ale jako połączonego łańcucha wpisów.

Edycja : Właściwie nie używasz tej add(index, element)metody set(index, element), ale zasada jest tutaj taka sama.

Natix
źródło
10

Jeśli chcesz dodać elementy z indeksem, możesz zamiast tego użyć tablicy.

    String [] test = new String[length];
    test[0] = "add";
użytkownik3692587
źródło
5
OP chciał początkowo użyć Listy ... a nie tablicy.
Stephan
9

10 to początkowa pojemność AL, a nie wielkość (która wynosi 0). Powinieneś wspomnieć o początkowej pojemności do jakiejś wysokiej wartości, gdy będziesz mieć wiele elementów, ponieważ pozwala to uniknąć narzutu związanego z rozszerzaniem pojemności w miarę dodawania elementów.

Bhesh Gurung
źródło
6

Chyba dokładna odpowiedź na twoje pytanie brzmiałaby:

Ustawienie rozmiaru początkowego na ArrayList zmniejsza liczbę. czasów, w których musi nastąpić ponowne przydzielenie pamięci wewnętrznej. Lista jest wspierana przez tablicę. Jeśli podasz np. Początkową pojemność 0, już przy pierwszym wstawieniu elementu konieczna będzie zmiana rozmiaru tablicy wewnętrznej. Jeśli masz przybliżone wyobrażenie o tym, ile elementów pomieści twoja lista, ustawienie początkowej pojemności zmniejszy liczbę. ponownego przydzielania pamięci podczas korzystania z listy.

nabrzeże
źródło
3

To może komuś pomóc -

ArrayList<Integer> integerArrayList = new ArrayList<>(Arrays.asList(new Integer[10]));
Hrishikesh Kadam
źródło
3

Spóźniam się z tym, ale po Javie 8 osobiście uważam, że to podejście z StreamAPI jest bardziej zwięzłe i może być alternatywą dla zaakceptowanej odpowiedzi .

Na przykład,

Arrays.stream(new int[size]).boxed().collect(Collectors.toList())

gdzie sizejest pożądany Listrozmiar i bez wspomnianej tutaj wady , wszystkie elementy Listsą inicjowane jako 0.

(Przeprowadziłem szybkie wyszukiwanie i nie znalazłem streamw żadnej opublikowanej odpowiedzi - daj mi znać, jeśli ta odpowiedź jest zbędna i mogę ją usunąć)

HT Koo
źródło
1

W tej chwili nie ma żadnych elementów na liście, więc nie można dodać do indeksu 5 listy, jeśli nie istnieje. Mylisz pojemność listy z jej obecnym rozmiarem.

Zadzwoń:

arr.add(10)

aby dodać liczbę całkowitą do ArrayList

Hunter McMillen
źródło
1

Chociaż twoja arraylist ma pojemność 10, prawdziwa lista nie zawiera tutaj elementów. Metoda add służy do wstawiania elementu do prawdziwej listy. Ponieważ nie ma żadnych elementów, nie można wstawić elementu do indeksu 5.

roll1987
źródło
1

Jeśli chcesz dodać 10 elementów ArrayList, możesz spróbować:

for (int i = 0; i < 10; i++)
    arr.add(i);

Jeśli już zadeklarowałeś zmienną rozmiaru tablicy, użyłbyś tej zmiennej sizezamiast liczby „10”

pantera
źródło
1

Miałem do czynienia z podobnym problemem i wiedząc, że arrayList jest implementacją tablicy List o zmiennym rozmiarze, spodziewam się również, że możesz dodać element do dowolnego punktu, ale przynajmniej mam możliwość zdefiniowania początkowego rozmiaru. W każdym razie możesz najpierw utworzyć tablicę i przekonwertować ją na listę taką jak:

  int index = 5;
  int size = 10;

  Integer[] array = new Integer[size];
  array[index] = value;
  ...
  List<Integer> list = Arrays.asList(array);

lub

  List<Integer> list = Arrays.asList(new Integer[size]);
  list.set(index, value);
unk
źródło
0

ArrayList myList = new ArrayList (10);

//  myList.add(3, "DDD");
//  myList.add(9, "III");
    myList.add(0, "AAA");
    myList.add(1, "BBB");

    for(String item:myList){
        System.out.println("inside list : "+item);
    }

/ * Zadeklaruj, że początkowa pojemność arraylist to nic innego jak oszczędzanie czasu na zmiany; kiedy dodajemy element wewnętrznie, sprawdza on pojemność, aby zwiększyć pojemność, można dodać element początkowo o indeksie 0, a następnie 1 i tak dalej. * /

sambhu
źródło
0

Moje dwa centy dalej Stream. Myślę, że lepiej jest używać

IntStream.generate(i -> MyClass.contruct())
         .limit(INT_SIZE)
         .collect(Collectors.toList());

z elastycznością do wprowadzania dowolnych wartości początkowych.

anch2150
źródło