Przejdź do treści

Najczęstsze operacje na List, Map i Set

  • Kolekcje i strumienie
  • poziom: początkujący
  • aktualizacja: 16 sierpnia 2026

Wybór między List, Set i Map rozstrzyga jedno pytanie: co ma się dziać z powtórzeniami i kolejnością. Lista zachowuje jedno i drugie, zbiór wycina duplikaty, a mapa łączy klucz z wartością. Ten przykład pokazuje operacje, po które sięgasz najczęściej, na modyfikowalnych ArrayList, LinkedHashSet i LinkedHashMap. Warianty LinkedHash* trzymają kolejność dodawania, więc wydruk wygląda tak samo przy każdym uruchomieniu — na zwykłym HashSet takiej gwarancji nie masz.

JAVA KolekcjeWPraktyce.java 100 linii Pobierz .java
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Najczęstsze operacje na List, Map i Set — skryptyJAVA.pl
 * Zapisz jako: KolekcjeWPraktyce.java
 */
public class KolekcjeWPraktyce {

    /** Zwraca sumę zbiorów, nie zmieniając żadnego z argumentów. */
    public static <T> Set<T> suma(Set<T> pierwszy, Set<T> drugi) {
        Set<T> wynik = new LinkedHashSet<>(pierwszy);
        wynik.addAll(drugi);
        return wynik;
    }

    /** Zwraca część wspólną dwóch zbiorów. */
    public static <T> Set<T> czescWspolna(Set<T> pierwszy, Set<T> drugi) {
        Set<T> wynik = new LinkedHashSet<>(pierwszy);
        wynik.retainAll(drugi);
        return wynik;
    }

    /** Zwraca elementy pierwszego zbioru, których nie ma w drugim. */
    public static <T> Set<T> roznica(Set<T> pierwszy, Set<T> drugi) {
        Set<T> wynik = new LinkedHashSet<>(pierwszy);
        wynik.removeAll(drugi);
        return wynik;
    }

    /** Wypisuje tytuł kolejnej części przykładu. */
    private static void sekcja(String tytul) {
        System.out.println("\n--- " + tytul + " ---");
    }

    // ── PRZYKŁADY ───────────────────────────────────────────
    public static void main(String[] args) {
        sekcja("List — dodawanie, zmiana i usuwanie");
        List<String> zadania = new ArrayList<>(List.of("mail", "raport", "telefon"));
        zadania.add("spotkanie");
        zadania.add(1, "faktura");
        zadania.set(0, "pilny mail");
        zadania.remove("telefon");
        System.out.println("Po zmianach: " + zadania);

        // removeIf kasuje wszystko, co pasuje do warunku — także wpisane wyżej "pilny mail".
        zadania.removeIf(zadanie -> zadanie.startsWith("pilny"));
        System.out.println("Lista: " + zadania);
        System.out.println("Ma raport: " + zadania.contains("raport"));

        // subList zwraca WIDOK, a nie kopię: zmiana widoku zmienia listę źródłową,
        // a dodanie elementu do listy unieważnia widok.
        System.out.println("Pierwsze dwa: " + zadania.subList(0, 2));

        // Kopia może być zmieniana niezależnie od listy źródłowej.
        List<String> kopia = new ArrayList<>(zadania);
        kopia.addAll(List.of("archiwizacja", "kopia zapasowa"));
        System.out.println("Oryginał: " + zadania.size() + ", kopia: " + kopia.size());

        sekcja("Set — unikalność i działania na zbiorach");
        List<String> zDuplikatami = List.of("Java", "SQL", "Java", "Git", "SQL");
        Set<String> unikalne = new LinkedHashSet<>(zDuplikatami);
        System.out.println("Bez duplikatów: " + unikalne);

        Set<String> zespolA = new LinkedHashSet<>(List.of("Anna", "Jan", "Ola"));
        Set<String> zespolB = new LinkedHashSet<>(List.of("Ola", "Piotr", "Jan"));
        System.out.println("Suma:          " + suma(zespolA, zespolB));
        System.out.println("Część wspólna: " + czescWspolna(zespolA, zespolB));
        System.out.println("Różnica A-B:   " + roznica(zespolA, zespolB));

        sekcja("Map — wartości domyślne, zliczanie i grupowanie");
        Map<String, Integer> magazyn = new LinkedHashMap<>();
        magazyn.put("kawa", 12);
        magazyn.putIfAbsent("herbata", 8);
        magazyn.merge("kawa", 5, Integer::sum);
        magazyn.merge("cukier", 3, Integer::sum);
        System.out.println("Stan kawy: " + magazyn.getOrDefault("kawa", 0));
        System.out.println("Stan mleka: " + magazyn.getOrDefault("mleko", 0));
        magazyn.forEach((produkt, sztuk) ->
                System.out.println("  " + produkt + ": " + sztuk));

        List<String> slowa = List.of("kot", "pies", "koń", "papuga", "kret");
        Map<Character, List<String>> wedlugLitery = new LinkedHashMap<>();
        for (String slowo : slowa) {
            wedlugLitery.computeIfAbsent(slowo.charAt(0), klucz -> new ArrayList<>())
                    .add(slowo);
        }
        System.out.println("Grupy: " + wedlugLitery);

        Map<String, Integer> licznik = new LinkedHashMap<>();
        for (String slowo : List.of("java", "git", "java", "sql", "java", "git")) {
            licznik.merge(slowo, 1, Integer::sum);
        }
        System.out.println("Wystąpienia: " + licznik);
    }
}

Jak użyć tego skryptu

  1. Skopiuj kod do pliku KolekcjeWPraktyce.java — Java wymaga, żeby plik nazywał się tak jak klasa publiczna — i uruchom poleceniem java KolekcjeWPraktyce.java. Wynik jest podzielony na osobne sekcje dla listy, zbioru i mapy.
  2. Wybierz implementację według potrzeb: ArrayList do uporządkowanej listy, LinkedHashSet do unikalnych elementów w kolejności dodania i LinkedHashMap do par klucz–wartość o przewidywalnej kolejności.
  3. Do usuwania duplikatów przekaż listę do konstruktora LinkedHashSet. Jeśli wynikiem znów ma być lista, użyj potem new ArrayList<>(unikalne).
  4. Skopiuj metody suma, czescWspolna i roznica do własnej klasy narzędziowej. Są generyczne, więc obsłużą zbiory napisów, liczb i własnych obiektów. Pamiętaj tylko, że zawsze zwracają LinkedHashSet: jeśli podasz im TreeSet, wynik nie będzie się już sam sortował przy kolejnych dodaniach.

Warto wiedzieć

  • Kolekcje utworzone przez List.of, Set.of i Map.of są niemodyfikowalne — dlatego lista zadania powstaje jako new ArrayList<>(List.of(...)); bez tej kopii pierwsze add zgłosiłoby UnsupportedOperationException. Te fabryki nie znoszą też null: List.of("a", null) rzuca NullPointerException, a Set.of i Map.of odrzucają duplikaty wyjątkiem IllegalArgumentException. Jeśli Twoje dane mogą mieć dziury albo powtórzenia, buduj kolekcję przez new ArrayList<>(...) lub new LinkedHashSet<>(...).
  • HashSet i HashMap nie gwarantują kolejności iteracji — to, że raz wypisały się „po kolei", niczego nie obiecuje. Jeśli kolejność dodawania ma znaczenie, użyj LinkedHashSet lub LinkedHashMap; jeśli potrzebujesz sortowania po kluczu, wybierz TreeSet albo TreeMap.
  • Nie usuwaj elementów z listy, po której właśnie iterujesz pętlą for-each — dostaniesz ConcurrentModificationException, i to nie zawsze od razu, więc błąd potrafi się ujawnić dopiero na produkcyjnych danych. Do warunkowego usuwania jest removeIf, a przy bardziej złożonej logice — jawny Iterator i jego remove().
  • Klucze mapy i elementy zbioru muszą mieć poprawne equals i hashCode. Bez nich dwa identyczne obiekty wylądują w zbiorze jako osobne wpisy, a get na mapie zwróci null, choć klucz „przecież tam jest". Rekordy dostają obie metody za darmo; w zwykłej klasie pisz je zawsze parami.
#kolekcje #list #map #set #grupowanie #wydajność

Podobne skrypty