Məqalə " Java Collections haqqında ən yaxşı 10 sual " məqaləsinin tərcüməsidir . Aşağıda Stackowerflow-da verilən və müzakirə edilən Java-da kolleksiyalar haqqında ən populyar suallar verilmişdir. Bu suallara baxmazdan əvvəl sinif iyerarxiya diaqramına baxmaq yaxşı olardı. 1. ArrayList əvəzinə LinkedList-dən nə vaxt istifadə edilməlidir? ArrayList əslində massivdir, onun elementlərinə birbaşa indekslə daxil olmaq olar. Massiv daşarsa, daha çox yerə malik yenisi lazım olur. Bütün elementlərin yerləşdirilməsi və daşınması O(n) vaxt aparacaq. Həmçinin, massivdə mövcud elementləri köçürmək üçün elementləri əlavə etmək və silmək lazımdır. Bu, bəlkə də ArrayList-dən istifadənin ən böyük narahatlığıdır. LinkedList element keçidlərinin ikiqat siyahısıdır. Beləliklə, mərkəzdəki elementə daxil olmaq üçün vərəqin əvvəlindən sonuna qədər axtarış etməlisiniz. Digər tərəfdən, LinkedList-ə element əlavə etmək və silmək daha sürətli olur, çünki bu əməliyyatlar yalnız siyahının özünü dəyişir. Ən pis vaxtlar aşağıda müqayisə edilir:
Metod
Arraylist
LinkedList
almaq (indeks)
O(1)
O(n)
əlavə et(E)
O(n)
O(1)
əlavə et (E, indeks)
O(n)
O(n)
sil (indeks)
O(n)
O(n)
Iterator.remove()
O(n)
O(1)
Iterator.add(E)
O(n)
O(1)
İşləmə müddətinə baxmayaraq, yaddaş istifadəsi böyük siyahılar üçün fərdi olaraq nəzərə alınmalıdır. LinkedList-də hər bir node əvvəlki və sonrakı qovşaqları əlaqələndirmək üçün ən azı iki əlavə göstəriciyə malik olmalıdır, ArrayList-də isə yalnız elementlər massivi lazımdır.
ArrayList, LinkedList və Vektor siyahılarının daha çox müqayisəsi .
2. Kolleksiya iterasiyası zamanı elementləri silmək üçün effektiv ekvivalent. İterasiya zamanı kolleksiyanı dəyişdirməyin (elementləri silməyin) yeganə düzgün yolu Iterator.remove() funksiyasından istifadə etməkdir . Məsələn: Ən çox rast gəlinən xəta: Yuxarıdakı kodu işləyərkən
ConcurrentModificationException alacaqsınız . Bu, iteratorun bütün siyahıda hərəkət etmək üçün yaradıldığına görə baş verir, lakin eyni zamanda vərəq Iterator.remove() çağırılmaqla dəyişdirilir. Bu istisna üçün sənədlərdə yazıldığı kimi,
Iterator
itr = list.iterator(); while(itr.hasNext()) { // do something itr.remove(); }
for(Integer i: list) { list.remove(i); }
"Bir mövzunun kolleksiyanı dəyişdirməsi, başqa bir iplik onun üzərində təkrarlanırsa, ümumiyyətlə icazə verilmir."
Ümumilikdə, bir mövzunun kolleksiyanı dəyişdirməsi yolverilməzdir, digər mövzu isə kolleksiyadan keçərkən.
3. Siyahını int[] massivinə necə çevirmək olar? Bunun ən asan yolu Apache Commons Lang kitabxanasında yerləşən
ArrayUtils proqramından istifadə etməkdir . JDK-da bu ifadə üçün qısa yol yoxdur. Unutmayın ki, siz List.toArray() funksiyasından istifadə edə bilməzsiniz, çünki bu ifadə Siyahısını Tam[]-a çevirir (bu, primitiv tip
deyil ). Düzgün yol aşağıdakı seçim olardı:
4. int[] massivini Siyahıya necə çevirmək olar? Ən asan yol həm də yuxarıdakı kimi
Apache Commons Lang kitabxanasında
ArrayUtils-dən istifadə etməkdir . Həmçinin, JDK-da bu ifadə üçün qısa yol yoxdur.
5. Kolleksiyanı süzgəcdən keçirməyin ən yaxşı yolu hansıdır? Funksionallığı artırmaq üçün
Guava və ya
Apache Commons Lang kimi üçüncü tərəf paketlərindən istifadə edə bilərsiniz . Bu paketlərin hər ikisində filter() metodu var ( Guava-dan
Collections2 sinifində və Apache-dən
CollectionUtils -də). filter() metodu verilmiş Predikata uyğun elementləri qaytaracaq. JDK-da hər şey daha mürəkkəbdir. Yaxşı xəbər odur ki, predikatlar Java 8-də əlavə olunacaq
, lakin hələlik bütün kolleksiyanı təkrarlamaq üçün İteratordan istifadə etməlisiniz. Əlbəttə ki, siz yeni Predicate interfeysi ilə tanış olmaqla Guava və Apache-nin izlədiyi yolu təqlid edə bilərsiniz. İndi kolleksiyanı filtrləmək üçün aşağıdakı koddan istifadə edə bilərik:
6. List-i Set-ə necə asanlıqla çevirmək olar? Bərabərliyi necə təyin etmək istədiyinizdən asılı olaraq bunu etməyin iki yolu var. İlk kod parçası siyahını HashSet-ə qoyur. Bu halda dublikat əsasən hashCode() ilə müəyyən edilir. Adətən bu işləyəcək. Ancaq müqayisə yolunu nəzərə almaq lazımdırsa, kodun ikinci hissəsindən istifadə etmək daha yaxşı olardı, burada öz komparatorunuzu təyin edə bilərsiniz.
7. ArrayList-dən dublikat elementləri necə silə bilərəm? Bu sual bir qədər yuxarıdakı sualla bağlıdır. ArrayList-dəki elementlərin sırası sizin üçün əhəmiyyət kəsb etmirsə, dublikatları silmək üçün vərəqi Dəstdə yerləşdirmək və sonra onu yenidən Siyahıya qaytarmaq ağıllı bir addım olardı. Aşağıda bir nümunə verilmişdir. Elementlərin sırası sizin üçün vacibdirsə, siyahı standart JDK-da olan
LinkedHashSet- ə yerləşdirməklə sifariş təmin edilə bilər. 8. Sıralanmış kolleksiyaint[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));int[] array = new int[list.size()]; for(int i=0; i < list.size(); i++) { array[i] = list.get(i); }List list = Arrays.asList(ArrayUtils.toObject(array));int[] array = {1,2,3,4,5}; List
list = new ArrayList
(); for(int i: array) { list.add(i); }
Iterator
itr = list.iterator(); while(itr.hasNext()) { int i = itr.next(); if (i > 5) { // filter all ints bigger than 5 itr.remove(); } }
public interface Predicate
{ boolean test(T o); } public static
void filter(Collection
collection, Predicate
predicate) { if ((collection != null) && (predicate != null)) { Iterator
itr = collection.iterator(); while(itr.hasNext()) { T obj = itr.next(); if (!predicate.test(obj)) { itr.remove(); } } } }
filter(list, new Predicate
() { public boolean test(Integer i) { return i <= 5; } });
Set
set = new HashSet
(list);
Set
set = new TreeSet
(aComparator); set.addAll(list);
ArrayList** list = ... // initial a list with duplicate elements Set
set = new HashSet
(list); list.clear(); list.addAll(set);
Java-da çeşidlənmiş kolleksiyanı dəstəkləməyin bir neçə yolu var. Onların hamısı təbii qaydada və ya müəyyən bir müqayisəçi ilə kolleksiya təqdim edir. Təbii qaydada, elementdə
Müqayisəli interfeysi də həyata keçirməlisiniz.
Collections.sort() Siyahını çeşidləyə bilər. Java sənədlərində qeyd edildiyi kimi, bu növ sabitdir və n log(n) performansına zəmanət verir.
PriorityQueue nizamlı növbə təmin edir. PriorityQueue və Collections.sort() arasındakı fərq ondan ibarətdir ki, PriorityQueue hər zaman növbə sırasını saxlayır, lakin siz yalnız növbənin ilk elementini əldə edə bilərsiniz. PriorityQueue.get(4) kimi elementə təsadüfi daxil ola bilməzsiniz.
Kolleksiyada heç bir dublikat yoxdursa, siz TreeSet seçə bilərsiniz . PriorityQueue kimi, TreeSet də hər zaman sifarişli dəsti saxlayır. Siz TreeSet-dən ən kiçik və ya ən böyük elementi əldə edə bilərsiniz, lakin hələ də elementlərə təsadüfi giriş əldə edə bilməzsiniz.
Sadəcə olaraq, Collections.sort() birdəfəlik sifarişli siyahı təqdim edir. PriorityQueue və TreeSet elementlərə indeksləşdirilmiş girişin olmaması hesabına hər zaman sifarişli kolleksiya saxlayır.
9. Collections.emptyList() və ya yeni instansiya Eyni sual emptyMap() və emptySet() üçün də tətbiq olunur. Hər iki üsul boş siyahı qaytarır, lakin Collections.emptyList() dəyişməz siyahıdır. Bu o deməkdir ki, siz "boş" siyahıya yeni elementlər əlavə
edə bilməzsiniz . Arxa planda Collections.emptyList() metoduna edilən hər bir zəng əslində boş siyahının yeni nümunəsini yaratmır. Bunun əvəzinə o, artıq mövcud olan boş nümunəni yenidən istifadə edəcək.
Bir dizayn nümunəsi kimi Singleton ilə tanışsınızsa , nə demək olduğunu başa düşməlisiniz. Bu , tez-tez çağırıldıqda
daha yaxşı performans göstərməlidir .
10 Kolleksiyanın kopyalanması, Collections.copy() Mənbə siyahısını təyinat siyahısına köçürməyin iki yolu var. Bunun bir yolu ArrayList konstruktorundan istifadə etməkdir.
Başqa bir yol Collections.copy() metodundan istifadə etməkdir . Birinci sətirdə qeyd edin: biz ən azı orijinal siyahının uzunluğu ilə eyni uzunluqda bir siyahı ayırırıq, çünki kolleksiyalar haqqında Java sənədlərində deyilir:
ArrayList
dstList = new ArrayList
(srcList);
Təyinat siyahısı ən azı mənbə siyahısı qədər uzun olmalıdır.
Bu o deməkdir ki, yekun siyahı orijinaldan qısa olmamalıdır. Hər iki üsul dayaz kopyalamadır. Beləliklə, bu iki üsul arasındakı fərq nədir? Birincisi, Collections.copy() hətta dstList-də srcList-in bütün elementlərini ehtiva etmək üçün kifayət qədər yer olmasa belə, dstList-in kolleksiya tutumunu yenidən bölüşdürməyəcək.
Bunun əvəzinə IndexOutOfBoundsException atacaq . Bunun bir faydası olub-olmadığını soruşmaq olar. Səbəb odur ki, bu, metodun vaxtında xətti işləməsini təmin edir. Bu, ArrayList konstruktorunda yaddaşı yenidən bölüşdürmək əvəzinə massivlərdən təkrar istifadə etmək istədiyiniz zaman da uyğundur.
Nəticə əvəzinə məqaləni oxuduqdan sonra hələ də suallarınız varsa, şərhlərdə onlardan soruşun. Həmçinin tərcümədə hər hansı qeyri-dəqiqlik və ya başqa xəta aşkar etsəniz, PM-ə yazın, düzəldiləcək, sizə təşəkkür ediləcək.
Orijinal.ArrayList
dstList = new ArrayList
(srcList.size()); Collections.copy(dstList, srcList);
GO TO FULL VERSION