JavaRush /Blog Java /Random-PL /nowa ArrayList(????) jak i gdzie lepiej zainicjować
Vovan
Poziom 22

nowa ArrayList(????) jak i gdzie lepiej zainicjować

Opublikowano w grupie Random-PL
Pisanie kodu bez użycia frameworka kolekcji byłoby szaleństwem. To wspaniały kawałek Javy z wieloma fajnymi rozwiązaniami. Co ważniejsze, w przeciwieństwie do tablic, nie musisz martwić się o rozmiary. ArrayList będzie rosła, aż skończy się pamięć. Programista nie musi martwić się początkowym rozmiarem i błędem ArrayIndexOutOfBoundsException . Ale co, jeśli istnieje warunek monitorowania ilości pamięci? Czy możemy efektywnie wykorzystywać pamięć podczas pracy z kolekcjami?
Powstaje standardowe pytanie: jak zainicjować listę? Poniższy kod nie będzie działać: Spowoduje to błąd kompilacji: Nazwy zmiennych lokalnych mogły nie zostać zainicjowane . Specyfikacja Java wymaga, aby wszystkie zmienne lokalne (te, które istnieją na stosie) były inicjalizowane odpowiednimi wartościami. Można to zrobić w następujący sposób: Bez wątpienia lista musi zostać zainicjowana. Możesz albo utworzyć listę w pierwszym wierszu, albo zrobić coś mądrzejszego i zastosować leniwą inicjalizację , tak jak zrobiliśmy to w metodzie getAllNames() . W takim przypadku lista zostanie utworzona tylko wtedy, gdy będzie to konieczne - jeśli warunki początkowe nie zostaną spełnione, lista nigdy nie pojawi się na stercie. Tu dochodzimy do głównego pytania: jaki rozmiar ustawić dla listy? Najlepszą opcją jest podanie mu dokładnego rozmiaru. Przykład: W tym przypadku musi zostać zwróconych dokładnie n nazw, w wyniku czego zostanie utworzona kolekcja n elementów. Jednak dokładna wartość n nie zawsze jest znana. Nawet w podanym przykładzie, co by było, gdyby n=1000 i dostępnych było tylko 100 nazw? Podczas pracy z kolekcjami najpopularniejszą metodą jest wywołanie konstruktora domyślnego. Jeśli spojrzeć na kod źródłowy Java (wersja 1.6) Jak widać, domyślnie tworzona jest lista 10 elementów . Oznacza to, że możemy bezpiecznie użyć konstruktora domyślnego, gdy nie planujemy przechowywać na liście więcej niż 10 elementów. Co się stanie, jeśli spróbujesz dodać jedenasty element? No cóż, nic złego... element zostanie pomyślnie dodany. Przyjrzyj się metodzie: Rozmiar tablicy jest kontrolowany przez metodę zapewnieniaCapacity . Rozmiar zwiększa się 1,5 razy . Tworzona jest nowa tablica i elementy są do niej przenoszone. Jeśli ustawimy rozmiar na 10, to na 11 elemencie:
public List getAllNames() { List names; if (/*необходимые условия выполнены*/) { names = new ArrayList (); /*заполнение списка*/ } return names; }
List names = null; List names = new ArrayList (); List names = new ArrayList (0); List names = new ArrayList (size);
public List getTopNames (int n) { List names = null; if ( /*необходимые условия выполнены*/) { names = new ArrayList (n); /*заполнение списка*/ } return names; }
names = new ArrayList ();

/** * Конструирует пустой список с указанной начальной емкостью. * * @param initialCapacity начальная емкость списка * @exception IllegalArgumentException если указанная начальная емкость отрицательна * */ public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) this.elementData = new Object[initialCapacity]; } /** * Конструирует пустой список с начальной емкостью, равной 10. */ public ArrayList() { this(10); }
public Boolean add(E e) { ensureCapacity(size + 1); //увеличивает modCount!! elementData[size++] = e; return true; } public void ensureCapacity (int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { throw new IllegalArgumentException(“Illegal Capacity: ” + initialCapacity); Object oldData[] = elementData; int newCapacity = (oldCapacity * 3) / 2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity обычно ближе к размеру, так что это беспроигрышно: elementData = Arrays.copyOf(elementData, newCapacity); } }
  • rozmiar zmienia się na 10 * 3 / 2 + 1 = 16
  • następny wzrost = 16 * 3 / 2 + 1 = 25
  • następny wzrost = 25 * 3 / 2 + 1 = 39 i tak dalej.
W przypadku 100 elementów JVM będzie musiała kilka razy utworzyć nową tablicę i skopiować do niej elementy. Mając to na uwadze, jeśli przyjmuje się założenie o wymaganej wielkości tablicy, lepiej jest ustawić pojemność wyjściową w jej pobliżu. Oto kilka wskazówek dotyczących działania:
  1. Twórz kolekcję tylko wtedy, gdy jej potrzebujesz , w przeciwnym razie zainicjuj ją na wartość null lub użyj Collections.EMPTY_LIST .
  2. Jeśli znasz dokładny wymagany rozmiar , określ go w konstruktorze kolekcji.
  3. Jeśli masz pewność, że liczba elementów nie przekroczy 10 , możesz skorzystać z konstruktora domyślnego.
  4. Ryzyko związane z tworzeniem kolekcji o zerowym rozmiarze polega na tym, że częstotliwość tworzenia nowych tablic i kopiowania danych może być większa. Musisz bardzo dokładnie przemyśleć, czy korzystanie z kolekcji w rozmiarze zero przyniesie korzyści .
  5. Jeśli na początku metody zainicjowałeś zbyt dużą kolekcję i chcesz ją zmniejszyć, istnieje metoda trimToSize() .
Oczywiście te wytyczne mają zastosowanie podczas pracy z kolekcjami opartymi na tablicach i nic z tego nie ma sensu w przypadku listy połączonej. W rzeczywistości jest mało prawdopodobne, aby te problemy były zabójcami programu, ale jeśli istnieje możliwość zrobienia czegoś lepiej, dlaczego z niej nie skorzystać. Czy masz jakieś inne pomocne wskazówki? Czy znalazłeś sposób na usprawnienie działania? A może to wszystko jest niepotrzebne? Co myślisz?
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION