Alap interfészek
List, Set, Map, Queue és Deque interfészek
Collections Framework — Alap interfészek
A Java Collections Framework interfész-hierarchiája — List, Set, Map, Queue, Deque — mindegyik egy jól meghatározott szerződést definiál az adatok tárolására és elérésére.
1. Definíció
Mi ez?
A Java Collections Framework (JCF) egy egységes architektúra objektumcsoportok reprezentálására és manipulálására. A középpontjában interfészek állnak, amelyek a szerződéseket definiálják — a mit, nem a hogyan — a különböző gyűjteménytípusokhoz.
Miért létezik?
A JCF előtt (Java 1.2 előtt) csak Vector, Stack, Hashtable és tömbök léteztek — következetlen API-kkal. A JCF egy koherens hierarchiát hozott létre, hogy:
- Az algoritmusok interfészek ellen legyenek írva, nem konkrét osztályok ellen
- Az implementációk felcserélhetők legyenek a hívók módosítása nélkül
- A közös műveletek (iteráció, rendezés, szűrés) egységesen működjenek
Hol helyezkedik el?
A fő interfész-hierarchia röviden:
- Az
Iterableáll a legfelső szinten. - A
CollectionazIterable-ből ágazik tovább. List— rendezett ág, duplikátumokat megenged.Set— duplikátummentes ág, ezen belülSortedSetésNavigableSetváltozatokkal.Queue— FIFO vagy prioritásos elérés, ezen belül a kétvégűDeque.- A
Mapkülön kulcs-érték hierarchia, amelynek rendezett változatai aSortedMapésNavigableMap.
2. Alapfogalmak
2.1 `Collection` — az gyökér interfész
A gyűjtemény-hierarchia gyökere (a Map kivételével). Biztosítja:
add(E e),remove(Object o),contains(Object o)size(),isEmpty(),clear()iterator(),forEach(),stream()- Tömeges műveletek:
addAll,removeAll,retainAll,containsAll
2.2 `List` — rendezett, index-alapú elérés
| Tulajdonság | Részletek |
|---|---|
| Sorrend | Beszúrási sorrend megőrzött |
| Duplikátumok | ✅ Megengedett |
| Index elérés | ✅ get(int index) |
| Null elemek | ✅ Általában megengedett |
| Fő implementációk | ArrayList, LinkedList, CopyOnWriteArrayList |
Plusz metódusok: get(int), set(int, E), add(int, E), remove(int), indexOf(Object), subList(from, to), sort(Comparator).
2.3 `Set` — nincs duplikátum
| Tulajdonság | Részletek |
|---|---|
| Sorrend | Implementációfüggő (nincs / beszúrási / rendezett) |
| Duplikátumok | ❌ Nem megengedett (equals/hashCode alapján) |
| Index elérés | ❌ Nincs get(int) |
| Null elemek | ✅ Legfeljebb egy null |
| Fő implementációk | HashSet, LinkedHashSet, TreeSet |
SortedSet plusz: first(), last(), headSet(to), tailSet(from), subSet(from, to).
NavigableSet plusz: floor(e), ceiling(e), lower(e), higher(e), descendingSet().
2.4 `Queue` — FIFO elérés
| Művelet | Kivételt dob | Speciális értéket ad |
|---|---|---|
| Beszúrás | add(e) |
offer(e) → false |
| Fejelem törlés | remove() |
poll() → null |
| Fejelem megnézés | element() |
peek() → null |
Fő implementációk: LinkedList, ArrayDeque, PriorityQueue.
2.5 `Deque` — kétoldalú sor (Queue kiterjesztése)
Mindkét végén enged beszúrást és törlést. Stack (LIFO) gyanánt is használható.
| Művelet | Eleje | Vége |
|---|---|---|
| Beszúrás | addFirst(e) / offerFirst(e) |
addLast(e) / offerLast(e) |
| Törlés | removeFirst() / pollFirst() |
removeLast() / pollLast() |
| Megnézés | peekFirst() |
peekLast() |
| Stack használat | push(e) = addFirst |
pop() = removeFirst |
Fő implementációk: ArrayDeque (ajánlott), LinkedList.
2.6 `Map` — kulcs-érték párok
A Map nem terjeszti ki a Collection-t. Legfontosabb műveletek:
put(K, V),get(K),remove(K),containsKey(K),containsValue(V)keySet()→Set<K>,values()→Collection<V>,entrySet()→Set<Map.Entry<K,V>>- Java 8+:
getOrDefault,putIfAbsent,computeIfAbsent,merge,forEach
SortedMap plusz: firstKey(), lastKey(), headMap(to), tailMap(from), subMap(from, to).
3. Gyakorlati használat
Mikor melyik interfészt?
| Forgatókönyv | Interfész | Miért |
|---|---|---|
| Rendezett elemek, index-elérés szükséges | List |
O(1) pozicionális elérés |
| Egyedi elemek, gyors tagság-ellenőrzés | Set |
contains O(1)-ben (HashSet) |
| Kulcs → érték keresés | Map |
O(1) keresés kulcs alapján |
| Feladatsor / eseményfeldolgozás | Queue |
FIFO szemantika |
| Undo/redo stack, böngésző history | Deque |
Mindkét vége elérhető |
| Rendezett elemek, tartomány-lekérdezések | SortedSet / SortedMap |
Természetes vagy egyedi sorrend |
Interfészek ellen programozz, ne implementáció ellen
// ✅ Interfész ellen programozz
List<String> nevek = new ArrayList<>();
Map<String, Integer> pontszamok = new HashMap<>();
// ❌ Túl specifikus implementáció
ArrayList<String> nevek = new ArrayList<>(); // elveszíti a rugalmasságot
Mikor NE használj Collection-t?
- Fix méretű numerikus adatok → primitív tömbök
- Magas konkurenciájú frissítések →
java.util.concurrenttípusok - Stream pipeline közbülső eredmények → ne gyűjtsd be korán
4. Kód példák
Alappélda — Interfész-szerződések működés közben
import java.util.*;
public class InterfaceSzerzodések {
public static void main(String[] args) {
// List — sorrend megőrzött, duplikátumok engedélyezve
List<String> lista = new ArrayList<>(List.of("banán", "alma", "alma", "cseresznye"));
System.out.println(lista); // [banán, alma, alma, cseresznye]
System.out.println(lista.get(1)); // alma
// Set — nincs duplikátum, iterálási sorrend nem garantált (HashSet)
Set<String> halmaz = new HashSet<>(lista);
System.out.println(halmaz.size()); // 3 (alma deduplication)
// Queue — FIFO
Queue<String> sor = new LinkedList<>(List.of("első", "második", "harmadik"));
System.out.println(sor.poll()); // első
System.out.println(sor.peek()); // második
// Deque mint stack — LIFO
Deque<String> verem = new ArrayDeque<>();
verem.push("a"); verem.push("b"); verem.push("c");
System.out.println(verem.pop()); // c (LIFO)
// Map — kulcs-érték
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 90); map.put("Bob", 85);
System.out.println(map.get("Alice")); // 90
System.out.println(map.getOrDefault("Charlie", 0)); // 0
}
}
Haladó példa — Generikus algoritmus interfészek ellen
public class GyujtemenySegéd {
// Bármely List implementációval működik
public static <T extends Comparable<T>> T maximumot(List<T> lista) {
if (lista.isEmpty()) throw new NoSuchElementException();
T max = lista.get(0);
for (T elem : lista) {
if (elem.compareTo(max) > 0) max = elem;
}
return max;
}
// Bármely Collection-nel működik
public static <T> void mindenKiírása(Collection<T> gyujtemeny) {
gyujtemeny.forEach(System.out::println);
}
// Nem módosítható nézetet ad vissza — csak List szerződést kap a hívó
public static List<String> getNames() {
List<String> nevek = new ArrayList<>(List.of("Alice", "Bob", "Charlie"));
return Collections.unmodifiableList(nevek);
}
}
Gyakori hiba — Módosítás iterálás közben
List<String> elemek = new ArrayList<>(List.of("a", "b", "c", "b"));
// ❌ ConcurrentModificationException!
for (String s : elemek) {
if (s.equals("b")) elemek.remove(s);
}
// ✅ Iterator remove() metódusa
Iterator<String> it = elemek.iterator();
while (it.hasNext()) {
if (it.next().equals("b")) it.remove();
}
// ✅ Vagy removeIf (Java 8+)
elemek.removeIf(s -> s.equals("b"));
5. Trade-offok
| Interfész | ⚡ Elérési sebesség | 💾 Memória | 🔧 Funkciók | Felhasználási eset |
|---|---|---|---|---|
List |
O(1) index (tömb), O(n) keresés | Közepes | Index, rendezés, subList | Rendezett sorozatok |
Set |
O(1) contains (hash), O(log n) (fa) | Alacsony–Közepes | Egyediség | Tagság ellenőrzés, deduplication |
Queue |
O(1) fejelem műveletek | Alacsony | FIFO szemantika | Feladat ütemezés |
Deque |
O(1) mindkét vég | Alacsony | Stack + Queue | Undo, sliding window |
Map |
O(1) kulcs alapján (hash), O(log n) (fa) | Közepes–Magas | Kulcs-érték, merge | Cache, indexelés |
6. Gyakori hibák
1. `List` használata, ha egyediség szükséges
// ❌ Duplikátumokat enged — hiba, ha egyedi elemek kellenek
List<String> cimkek = new ArrayList<>();
cimkek.add("java"); cimkek.add("java"); // csendes duplikátum
// ✅ Set használata
Set<String> cimkek = new HashSet<>();
cimkek.add("java"); cimkek.add("java"); // méret marad 1
2. Régi `Stack` osztály használata
// ❌ A Stack kiterjeszti a Vector-t — szinkronizált, legacy, kerülendő!
Stack<Integer> verem = new Stack<>();
// ✅ Deque használata
Deque<Integer> verem = new ArrayDeque<>();
verem.push(1); verem.pop();
3. Null kezelési különbségek figyelmen kívül hagyása
// TreeSet/TreeMap: null NullPointerException-t dob
TreeSet<String> rendezett = new TreeSet<>();
rendezett.add(null); // ❌ NullPointerException — null-t nem lehet összehasonlítani
// HashSet: egy null megengedett
HashSet<String> hashelve = new HashSet<>();
hashelve.add(null); // ✅ OK
4. `remove(Object)` vs `remove(int)` keveredés List-en
List<Integer> szamok = new ArrayList<>(List.of(1, 2, 3, 4));
szamok.remove(1); // INDEX alapján töröl → [1, 3, 4]
szamok.remove(Integer.valueOf(3)); // ÉRTÉK alapján töröl → [1, 4]
7. Senior-szintű meglátások
Interfész szegregáció API tervezésben
Mindig a legszűkebb hasznos típust add vissza a metódusodból. Ha a hívóknak csak iterálni kell, visszaadhatsz Iterable<T>-t. Ha tagság-ellenőrzés kell, Collection<T> elegendő. Csak akkor adj vissza List-et, ha az index-elérés valóban szükséges.
`Iterable` vs `Collection` vs `List`
Iterable → iterálható (for-each)
Collection → + size, contains, add, remove
List → + index elérés, rendezés
Minden szint overhead-et ad (memória, komplexitás) — válaszd a minimális szerződést.
`Collections.unmodifiableXxx` vs `List.of` / `Set.of`
Collections.unmodifiableList(lista)— egy mutable lista nézete; az alap változásai láthatóak!List.of(...)(Java 9+) — valóban immutable; minden mutáló hívásra kivételt dobList.copyOf(collection)(Java 10+) — immutable másolat, pillanatkép szemantika
A teljesítmény és az interfész-választás kapcsolata
Egy LinkedList átadása olyan metódusnak, amely ismételten hívja a get(int)-et, O(n²) komplexitást eredményez. A List<T> elfogadása az API-ban nem garantálja a véletlenszerű elérést — fontolja meg a RandomAccess marker interfészt vagy dokumentálja a követelményeket.
`SortedSet` és `SortedMap` konzisztencia
A comparator legyen konzisztens az equals-szal: ha comparator.compare(a, b) == 0, akkor a.equals(b) is true kell legyen. Különben a Set szerződés (nincs duplikátum) csendesen megsérül.
8. Szószedet
| Fogalom | Definíció |
|---|---|
| JCF | Java Collections Framework — a gyűjtemény interfészek és implementációk egységes hierarchiája |
| Szerződés | Az a viselkedési garancia, amelyet egy interfész biztosít a hívóinak |
| RandomAccess | Marker interfész ArrayList-en stb., jelzi az O(1) index-elérést |
| FIFO | First-In-First-Out — a beszúrás sorrendje határozza meg a törlés sorrendjét (Queue) |
| LIFO | Last-In-First-Out — a legutóbb hozzáadott elem kerül először törlésre (Stack/Deque) |
| NavigableSet | SortedSet kiterjesztése floor/ceiling/lower/higher lekérdezésekkel |
| Fail-fast iterator | Iterator, amely ConcurrentModificationException-t dob, ha a gyűjtemény módosul iterálás közben |
| Strukturális módosítás | Bármely változás a gyűjtemény méretén (add/remove), szemben a set-tel |
9. Cheatsheet
- 📋
List— rendezett, index-elérés, duplikátumok OK →ArrayList(alapértelmezett) - 🔑
Set— nincs duplikátum, gyorscontains→HashSet(alapértelmezett) - 🗺️
Map— kulcs-érték, gyorsgetkulcs alapján →HashMap(alapértelmezett) - 📬
Queue— FIFO feladatfeldolgozás →ArrayDeque(ajánlott aLinkedListhelyett) - ↔️
Deque— mindkét vég elérhető, stack is →ArrayDeque - ⚠️
Stackosztály legacy — használjArrayDeque-t helyette - ✅ Interfész ellen programozz —
List<E>, neArrayList<E>a szignatúrákban - 🔒 Immutable gyűjtemények →
List.of(),Set.of(),Map.of()(Java 9+) - 🚫
TreeSet/TreeMapvisszautasítja anullkulcsokat/elemeket - 🔄 Módosítás iterálás közben →
iterator.remove()vagyremoveIf()
🎮 Játékok
10 kérdés