Kezdő Olvasási idő: ~8 perc

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 Collection az Iterable-ből ágazik tovább.
  • List — rendezett ág, duplikátumokat megenged.
  • Set — duplikátummentes ág, ezen belül SortedSet és NavigableSet változatokkal.
  • Queue — FIFO vagy prioritásos elérés, ezen belül a kétvégű Deque.
  • A Map külön kulcs-érték hierarchia, amelynek rendezett változatai a SortedMap és NavigableMap.

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.concurrent tí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 dob
  • List.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, gyors containsHashSet (alapértelmezett)
  • 🗺️ Map — kulcs-érték, gyors get kulcs alapján → HashMap (alapértelmezett)
  • 📬 Queue — FIFO feladatfeldolgozás → ArrayDeque (ajánlott a LinkedList helyett)
  • ↔️ Deque — mindkét vég elérhető, stack is → ArrayDeque
  • ⚠️ Stack osztály legacy — használj ArrayDeque-t helyette
  • Interfész ellen programozzList<E>, ne ArrayList<E> a szignatúrákban
  • 🔒 Immutable gyűjteményekList.of(), Set.of(), Map.of() (Java 9+)
  • 🚫 TreeSet/TreeMap visszautasítja a null kulcsokat/elemeket
  • 🔄 Módosítás iterálás közbeniterator.remove() vagy removeIf()

🎮 Játékok

10 kérdés