JavaRush /Java blogi /Random-UZ /Java-da to'plamlar haqida eng yaxshi 10 ta savol
FedoraLinux
Daraja
Москва

Java-da to'plamlar haqida eng yaxshi 10 ta savol

Guruhda nashr etilgan
Maqola " Java to'plamlari haqida eng yaxshi 10 ta savol " maqolasining tarjimasi . Quyida Stackowerflow-da berilgan va muhokama qilingan Java-dagi to'plamlar haqidagi eng mashhur savollar mavjud. Ushbu savollarni ko'rib chiqishdan oldin, sinf ierarxiyasi diagrammasini ko'rib chiqish yaxshi bo'lar edi. 1. ArrayList o'rniga LinkedList dan qachon foydalanish kerak? ArrayList aslida massiv bo'lib, uning elementlariga bevosita indeks orqali kirish mumkin. Agar massiv to'lib ketsa, ko'proq bo'sh joy bo'lgan yangisi kerak bo'ladi. Barcha elementlarni joylashtirish va ko'chirish O(n) vaqtni oladi. Bundan tashqari, qatordagi mavjud elementlarni ko'chirish uchun elementlarni qo'shish va olib tashlash kerak. Bu, ehtimol, ArrayList-dan foydalanishning eng katta noqulayligidir. LinkedList - bu elementlar havolalarining qo'sh ro'yxati. Shunday qilib, markazdagi elementga kirish uchun siz varaqning boshidan oxirigacha qidirishingiz kerak. Boshqa tomondan, LinkedList-ga element qo'shish va o'chirish tezroq bo'ladi, chunki bu operatsiyalar faqat ro'yxatning o'zini o'zgartiradi. Eng yomon vaqtlar quyida taqqoslanadi:
Usul Arraylist Bog'langan ro'yxat
olish (indeks) O(1) O(n)
qo'shish (E) O(n) O(1)
qo'shish (E, indeks) O(n) O(n)
olib tashlash (indeks) O(n) O(n)
Iterator.remove() O(n) O(1)
Iterator.add(E) O(n) O(1)
Ishlash vaqtiga qaramay, xotiradan foydalanish katta ro'yxatlar uchun alohida ko'rib chiqilishi kerak. LinkedList-da har bir tugun oldingi va keyingi tugunlarni bog'lash uchun kamida ikkita qo'shimcha ko'rsatkichga ega bo'lishi kerak, ArrayList-da esa faqat elementlar massivi kerak bo'ladi. ArrayList, LinkedList va Vektor ro'yxatlarini ko'proq taqqoslash . 2. To'plamni takrorlash paytida elementlarni o'chirish uchun samarali ekvivalent Iteratsiya paytida to'plamni o'zgartirishning (elementlarni olib tashlashning) yagona to'g'ri usuli Iterator.remove() dan foydalanishdir . Misol uchun: Eng keng tarqalgan xato: Yuqoridagi kodni ishga tushirishda siz ConcurrentModificationException olasiz . Buning sababi, iterator butun ro'yxat bo'ylab harakatlanish uchun yaratilgan, lekin ayni paytda varaq Iterator.remove() ni chaqirish orqali o'zgartiriladi. Ushbu istisno uchun hujjatlarda yozilganidek, Iterator itr = list.iterator(); while(itr.hasNext()) { // do something itr.remove(); } for(Integer i: list) { list.remove(i); }
"Umuman olganda, bitta ip to'plamni o'zgartirishi mumkin emas, boshqa ip esa uning ustida takrorlanadi."
Umuman olganda, bitta ip to'plamni o'zgartirishi mumkin emas, boshqa ip esa uni kesib o'tmoqda. 3. Ro‘yxatni int[] massivga qanday o‘zgartirish mumkin? Buning eng oson yo'li Apache Commons Lang kutubxonasida joylashgan ArrayUtils dan foydalanishdir . JDK da bu ifoda uchun yorliq yo'q. Esda tutingki, List.toArray() funksiyasidan foydalana olmaysiz, chunki bu ifoda Roʻyxatni Integer[] ga aylantiradi (bu ibtidoiy tur emas ). To'g'ri yo'l quyidagi variant bo'ladi: 4. Int[] massivini Ro'yxatga qanday aylantirish mumkin? Eng oson yo'li ArrayUtils- dan yuqoridagi kabi Apache Commons Lang kutubxonasida foydalanishdir . Bundan tashqari, JDK da bu ifoda uchun yorliq yo'q. 5. To'plamni filtrlashning eng yaxshi usuli qanday? Funktsionallikni oshirish uchun Guava yoki Apache Commons Lang kabi uchinchi tomon paketlaridan foydalanishingiz mumkin . Ushbu paketlarning ikkalasida filter() usuli mavjud ( Guava'dan Collections2 sinfida va Apache'dan CollectionUtils ). filter() usuli berilgan Predikatga mos keladigan elementlarni qaytaradi. JDK da hamma narsa murakkabroq. Yaxshi xabar shundaki, predikatlar Java 8 da qo'shiladi , ammo hozircha butun to'plamni takrorlash uchun Iterator dan foydalanishingiz kerak. Albatta, siz yangi Predicate interfeysi bilan tanishib, Guava va Apache-ning yo'liga taqlid qilishingiz mumkin. Endi biz to'plamni filtrlash uchun quyidagi koddan foydalanishimiz mumkin: 6. Ro'yxatni qanday qilib osongina to'plamga aylantirish mumkin? Tenglikni qanday belgilashni xohlayotganingizga qarab, buni qilishning ikki yo'li mavjud. Kodning birinchi qismi ro'yxatni HashSet-ga qo'yadi. Bu holda dublikat asosan hashCode() tomonidan aniqlanadi. Odatda bu ishlaydi. Ammo agar siz taqqoslash yo'lini hisobga olishingiz kerak bo'lsa, kodning ikkinchi qismidan foydalanish yaxshi bo'ladi, bu erda siz o'zingizning taqqoslashingizni belgilashingiz mumkin. 7. ArrayList dan takroriy elementlarni qanday olib tashlash mumkin? Bu savol yuqoridagi savolga ma'lum darajada bog'liq. Agar ArrayList-dagi elementlarning tartibi siz uchun muhim bo'lmasa, dublikatlarni olib tashlash uchun varaqni to'plamga joylashtirish va keyin uni yana Ro'yxatga qaytarish oqilona harakat bo'ladi. Quyida bir misol keltirilgan. Agar elementlarning tartibi siz uchun muhim bo'lsa, ro'yxatni standart JDKda joylashgan LinkedHashSet ga joylashtirish orqali tartibni ta'minlash mumkin. 8. Saralangan to'plam int[] 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 tartiblangan to'plamni qo'llab-quvvatlashning bir necha yo'li mavjud. Ularning barchasi tabiiy tartibda yoki ma'lum bir taqqoslash vositasida to'plamni taqdim etadi. Tabiiy tartib bo'lsa, siz elementda taqqoslanadigan interfeysni ham amalga oshirishingiz kerak.
  1. Collections.sort() Ro'yxatni saralashi mumkin. Java hujjatlarida aytilganidek, bu tur barqaror va n log(n) ishlashini kafolatlaydi.
  2. PriorityQueue tartibli navbat beradi. PriorityQueue va Collections.sort() o'rtasidagi farq shundaki, PriorityQueue har doim navbat tartibini saqlab turadi, lekin siz faqat navbatning birinchi elementini olishingiz mumkin. PriorityQueue.get(4) kabi elementga tasodifiy kira olmaysiz.
  3. To'plamda dublikatlar bo'lmasa, TreeSet ni tanlashingiz mumkin . PriorityQueue singari, TreeSet ham har doim tartiblangan to'plamni saqlaydi. Siz TreeSet-dan eng kichik yoki eng katta elementni olishingiz mumkin, lekin siz hali ham elementlarga tasodifiy kira olmaysiz.
Oddiy qilib aytganda, Collections.sort() bir martalik buyurtma qilingan ro'yxatni taqdim etadi. PriorityQueue va TreeSet elementlarga indekslangan kirish imkoni yo'qligi hisobiga har doim tartiblangan to'plamni saqlab turadi. 9. Collections.emptyList() yoki yangi namuna Xuddi shu savol emptyMap() va emptySet() ga tegishli. Ikkala usul ham bo'sh ro'yxatni qaytaradi, lekin Collections.emptyList() o'zgarmas ro'yxatdir. Bu siz "bo'sh" ro'yxatga yangi elementlar qo'sha olmaysiz degan ma'noni anglatadi. Orqa fonda Collections.emptyList() usuliga har bir qo'ng'iroq aslida bo'sh ro'yxatning yangi nusxasini yaratmaydi. Buning o'rniga, u allaqachon mavjud bo'sh misolni qayta ishlatadi. Agar siz Singleton bilan dizayn namunasi sifatida tanish bo'lsangiz , nimani anglatishini tushunishingiz kerak. Agar tez-tez qo'ng'iroq qilsangiz, bu sizga yaxshi ishlash imkonini beradi . 10 To‘plamdan nusxa olish, Collections.copy() Manba ro‘yxatini maqsadli ro‘yxatga ko‘chirishning ikki yo‘li mavjud. Buning bir usuli ArrayList konstruktoridan foydalanishdir. Yana bir usul Collections.copy() usulidan foydalanishdir . Birinchi qatorga e'tibor bering: biz hech bo'lmaganda asl ro'yxat uzunligi bilan bir xil uzunlikdagi ro'yxatni ajratmoqdamiz, chunki to'plamlar haqidagi Java hujjatlarida shunday deyilgan: ArrayList dstList = new ArrayList (srcList);
Mo'ljal ro'yxati kamida manba ro'yxati kabi uzun bo'lishi kerak.
Bu shuni anglatadiki, yakuniy ro'yxat asl ro'yxatidan qisqa bo'lmasligi kerak. Ikkala usul ham sayoz nusxa ko'chirishdir. Xo'sh, bu ikki usul o'rtasidagi farq nima? Birinchidan, Collections.copy() dstList to'plam hajmini qayta taqsimlamaydi, hatto dstListda srcListdagi barcha elementlarni o'z ichiga olish uchun etarli joy bo'lmasa ham. Buning o'rniga, u IndexOutOfBoundsException ni chiqaradi . Buning foydasi bormi, degan savol tug'ilishi mumkin. Sababi, bu usulning vaqtida chiziqli ishlashini ta'minlaydi. Bu ArrayList konstruktorida xotirani qayta taqsimlash o'rniga massivlarni qayta ishlatmoqchi bo'lganingizda ham mos keladi. Xulosa o'rniga, agar maqolani o'qib chiqqandan keyin sizda hali ham savollaringiz bo'lsa, ularni sharhlarda so'rashingiz mumkin. Shuningdek, agar tarjimada noaniqlik yoki boshqa xato topsangiz, PMga yozing, u tuzatiladi va sizga minnatdorchilik bildiriladi. Asl. ArrayList dstList = new ArrayList (srcList.size()); Collections.copy(dstList, srcList);
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION