Макала " Java Collections жөнүндө эң мыкты 10 суроо " макаласынын котормосу . Төмөндө Stackowerflow'та берилген жана талкууланган Java коллекциялары жөнүндө эң популярдуу суроолор. Бул суроолорду кароодон мурун класстын иерархиясынын диаграммасын карап чыксаңыз жакшы болмок.
1. ArrayListтин ордуна LinkedListти качан колдонуу керек?
ArrayList чындыгында массив; анын элементтерине түздөн-түз индекс аркылуу кирүүгө болот. Эгерде массив толуп кетсе, анда көбүрөөк орун менен жаңысы зарыл болуп калат. Бардык элементтерди жайгаштыруу жана жылдыруу O(n) убакытты талап кылат. Ошондой эле, элементтерди кошуу жана алып салуу массивдеги бар элементтерди жылдыруу үчүн зарыл. Бул, балким, ArrayListти колдонуудагы эң чоң ыңгайсыздык. LinkedList - бул элемент шилтемелеринин кош тизмеси. Ошентип, борбордогу элементке жетүү үчүн, барактын башынан аягына чейин издөө керек. Экинчи жагынан, LinkedListке элементти кошуу жана алып салуу тезирээк, анткени бул операциялар тизменин өзүн гана өзгөртөт. Эң начар мезгилдер төмөндө салыштырылат:
Метод |
Arraylist |
LinkedList |
алуу (индекс) |
O(1) |
O(n) |
кошуу(E) |
O(n) |
O(1) |
кошуу(E, индекс) |
O(n) |
O(n) |
алып салуу(индекс) |
O(n) |
O(n) |
Iterator.remove() |
O(n) |
O(1) |
Iterator.add(E) |
O(n) |
O(1) |
Иштөө убактысына карабастан, эстутумдун колдонулушу чоң тизмелер үчүн өзүнчө каралышы керек. LinkedListте ар бир түйүндө мурунку жана кийинки түйүндөрдү байланыштыруу үчүн кеминде эки кошумча көрсөткүч болушу керек, ал эми ArrayListте элементтердин массивдери гана керектелет.
ArrayList, LinkedList жана Vector тизмелерин көбүрөөк салыштыруу .
2. Коллекцияны итерациялоо учурунда элементтерди алып салуу үчүн эффективдүү эквивалент. Итерация учурунда коллекцияны өзгөртүүнүн (элементтерди алып салуу) жалгыз туура жолу
Iterator.remove() колдонуу болуп саналат . Мисалы: Эң кеңири тараган ката: Сиз жогорудагы codeду иштетип жатканда
ConcurrentModificationException аласыз . Бул итератор бүт тизме боюнча жылдыруу үчүн түзүлгөндүктөн болот, бирок ошол эле учурда барак Iterator.remove() чалуу менен өзгөртүлөт. Бул өзгөчөлүк үчүн documentтерде жазылгандай,
Iterator
itr = list.iterator(); while(itr.hasNext()) { // do something itr.remove(); }
for(Integer i: list) { list.remove(i); }
"бир жип коллекцияны өзгөртүүгө, ал эми экинчи жип анын үстүнөн итерацияланууга жалпысынан жол берилбейт."
Жалпысынан алганда, бир жип коллекцияны башка жиптен өтүп жатканда өзгөртүүгө жол берилбейт.
3. Тизмени int[] массивине кантип айландыруу керек? Муну жасоонун эң оңой жолу -
Apache Commons Lang китепканасында жайгашкан
ArrayUtils колдонуу . JDKда бул туюнтма үчүн кыска жол жок. List.toArray() функциясын колдоно албасыңызды унутпаңыз, анткени бул туюнтма Тизмени бүтүн санга[] айлантат (ал примитивдүү түр
эмес ). Төмөнкү вариант туура жол болмок:
4. int[] массивин Тизмеге кантип айландыруу керек? Эң оңой жолу - жогорудагыдай
Apache Commons Lang китепканасында
ArrayUtils колдонуу . Ошондой эле, JDKда бул туюнтма үчүн кыска жол жок.
5. Коллекцияны чыпкалоонун эң жакшы жолу кайсы? Функционалдуулукту жогорулатуу үчүн
Guava же
Apache Commons Lang сыяктуу үчүнчү тараптын пакеттерин колдоно аласыз . Бул эки пакетте тең filter() ыкмасы бар ( Guavaдан
Collections2 классында жана Apacheден
CollectionUtils ). filter() методу берилген Предикатка дал келген элементтерди кайтарат. JDKда баары татаалыраак. Жакшы жаңылык, предикаттар Java 8ге кошулат
, бирок азыр сиз бүт коллекцияны кайталоо үчүн Iterator колдонушуңуз керек. Албетте, сиз жаңы Predicate интерфейси менен таанышып, Guava жана Apache басып өткөн жолду туурай аласыз. Эми коллекцияны чыпкалоо үчүн төмөнкү codeду колдонсок болот:
6. Тизмени Set'ке кантип оңой айландырса болот? Теңдикти кантип аныктагыңыз келгенине жараша муну жасоонун эки жолу бар. Коддун биринчи бөлүгү тизмени HashSetке салат. Бул учурда дубликат негизинен hashCode() менен аныкталат. Эреже катары, бул иштейт. Бирок салыштыруу жолун эске алуу керек болсо, анда codeдун экинчи бөлүгүн колдонсоңуз жакшы болмок, анда сиз өзүңүздүн компараторуңузду аныктай аласыз.
7. ArrayListтен кайталанган элементтерди кантип алып салсам болот? Бул суроо жогорудагы суроого кандайдыр бир деңгээлде байланыштуу. Эгерде ArrayListтеги элементтердин тартиби сиз үчүн маанилүү болбосо, дубликаттарды алып салуу үчүн баракты топтомго жайгаштыруу, андан кийин аны кайра Тизмеге кайтаруу акылдуу кадам болот. Төмөндө бир мисал келтирилген. Эгер элементтердин тартиби сиз үчүн маанилүү болсо, анда тизмени стандарттык JDKдагы
LinkedHashSetке жайгаштыруу менен тартипти камсыз кылууга болот.
8. Сорттолгон коллекция
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'да сорттолгон коллекцияны колдоонун бир нече жолу бар. Алардын баары табигый тартипте же көрсөтүлгөн компаратор менен чогултууну камсыз кылат. Табигый тартип болгон учурда, сиз элементте
Салыштырылуучу интерфейсти ишке ашырууңуз керек.
- Collections.sort() Тизмени иреттей алат. Java documentациясында айтылгандай, бул сорт туруктуу жана n log(n) иштешине кепилдик берет.
- PriorityQueue иреттүү кезекти камсыз кылат. PriorityQueue менен Collections.sort() ортосундагы айырма PriorityQueue ар дайым кезек тартибин сактап турат, бирок сиз кезектин биринчи элементин гана ала аласыз. PriorityQueue.get(4) сыяктуу элементке туш келди кире албайсыз.
- Коллекцияда эч кандай дубликаттар жок болсо, TreeSet тандай аласыз . PriorityQueue сыяктуу эле, TreeSet ар дайым иреттелген топтомду сактап турат. Сиз TreeSetтен эң кичине же эң чоң элементти ала аласыз, бирок сиз дагы эле элементтерге туш келди кире албайсыз.
Жөнөкөй сөз менен айтканда, Collections.sort() бир жолку иреттелген тизмени берет. PriorityQueue жана TreeSet элементтерге индекстелген жеткorктүүлүктүн жоктугунан улам ар дайым иреттелген коллекцияны сактап турушат.
9. Collections.emptyList() же жаңы инстанция Ушул эле суроо emptyMap() жана emptySet() үчүн колдонулат. Эки ыкма тең бош тизмени кайтарат, бирок Collections.emptyList() өзгөрүлгүс тизме. Бул "бош" тизмеге жаңы элементтерди кошууга
болбойт дегенди билдирет. Фондо Collections.emptyList() ыкмасына ар бир чалуу иш жүзүндө бош тизменин жаңы инстанциясын түзбөйт. Анын ордуна, ал буга чейин болгон бош инстанцияны кайра колдонот.
Эгер сиз Singleton менен дизайн үлгүсү катары тааныш болсоңуз , анда эмнени билдирерин түшүнүшүңүз керек. Бул тез-тез чалса
жакшыраак иштеши керек .
10 Коллекцияны көчүрүү, Collections.copy() Булак тизмесин көздөгөн тизмеге көчүрүүнүн эки жолу бар. Бир жолу - ArrayList конструкторун колдонуу.
Дагы бир жолу Collections.copy() ыкмасын колдонуу . Биринчи сапта эскертүү: биз эң аз дегенде баштапкы тизменин узундугуна барабар болгон тизмени бөлүп жатабыз, анткени коллекциялар жөнүндө Java documentациясында мындай дейт:
ArrayList
dstList = new ArrayList
(srcList);
Бара турган жерлердин тизмеси булак тизмесинен кем эмес болушу керек.
Бул акыркы тизме түп нускасынан кыска болбошу керек дегенди билдирет. Эки ыкма тең тайыз көчүрүү болуп саналат. Ошентип, бул эки ыкманын ортосунда кандай айырма бар? Биринчиден, Collections.copy() dstListтин коллекция сыйымдуулугун кайра бөлүштүрбөйт, ал тургай, dstListте srcListтин бардык элементтерин камтуу үчүн жетиштүү орун жок.
Анын ордуна, ал IndexOutOfBoundsException ыргытат . Мунун кандайдыр бир пайдасы барбы деп сурашы мүмкүн. Себеби, бул ыкма өз убагында сызыктуу иштешин камсыз кылат. Бул ArrayList конструкторунда эстутумду кайра бөлүштүрүүнүн ордуна массивдерди кайра колдонгуңуз келгенде да ылайыктуу.
Корутундунун ордуна, макаланы окугандан кийин дагы суроолоруңуз болсо, аларды комментарийлерде берүүдөн тартынбаңыз. Ошондой эле котормодо так эмес же башка ката тапсаңыз, анда ПМге жазыңыз, ал оңдолот, сизге ыраазычылык билдирилет.
Original.
ArrayList
dstList = new ArrayList
(srcList.size()); Collections.copy(dstList, srcList);
GO TO FULL VERSION