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.
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
- Skopiuj kod do pliku
KolekcjeWPraktyce.java— Java wymaga, żeby plik nazywał się tak jak klasa publiczna — i uruchom poleceniemjava KolekcjeWPraktyce.java. Wynik jest podzielony na osobne sekcje dla listy, zbioru i mapy. - Wybierz implementację według potrzeb:
ArrayListdo uporządkowanej listy,LinkedHashSetdo unikalnych elementów w kolejności dodania iLinkedHashMapdo par klucz–wartość o przewidywalnej kolejności. - Do usuwania duplikatów przekaż listę do konstruktora
LinkedHashSet. Jeśli wynikiem znów ma być lista, użyj potemnew ArrayList<>(unikalne). - Skopiuj metody
suma,czescWspolnairoznicado 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 imTreeSet, wynik nie będzie się już sam sortował przy kolejnych dodaniach.
Warto wiedzieć
- Kolekcje utworzone przez
List.of,Set.ofiMap.ofsą niemodyfikowalne — dlatego listazadaniapowstaje jakonew ArrayList<>(List.of(...)); bez tej kopii pierwszeaddzgłosiłobyUnsupportedOperationException. Te fabryki nie znoszą teżnull:List.of("a", null)rzucaNullPointerException, aSet.ofiMap.ofodrzucają duplikaty wyjątkiemIllegalArgumentException. Jeśli Twoje dane mogą mieć dziury albo powtórzenia, buduj kolekcję przeznew ArrayList<>(...)lubnew LinkedHashSet<>(...). HashSetiHashMapnie gwarantują kolejności iteracji — to, że raz wypisały się „po kolei", niczego nie obiecuje. Jeśli kolejność dodawania ma znaczenie, użyjLinkedHashSetlubLinkedHashMap; jeśli potrzebujesz sortowania po kluczu, wybierzTreeSetalboTreeMap.- Nie usuwaj elementów z listy, po której właśnie iterujesz pętlą
for-each— dostanieszConcurrentModificationException, i to nie zawsze od razu, więc błąd potrafi się ujawnić dopiero na produkcyjnych danych. Do warunkowego usuwania jestremoveIf, a przy bardziej złożonej logice — jawnyIteratori jegoremove(). - Klucze mapy i elementy zbioru muszą mieć poprawne
equalsihashCode. Bez nich dwa identyczne obiekty wylądują w zbiorze jako osobne wpisy, agetna mapie zwrócinull, choć klucz „przecież tam jest". Rekordy dostają obie metody za darmo; w zwykłej klasie pisz je zawsze parami.
Podobne skrypty
Stream API w praktyce: filtrowanie, grupowanie i podsumowania
Dziewięć gotowych sekcji Stream API na liście pracowników: filter i map, sortowanie z thenComparing, groupingBy z counting i summingDouble, statystyki, Optional, joining i partitioningBy.
średni Zobacz kod → Kolekcje i strumienieSortowanie obiektów przez Comparator i Collator
Sortowanie rekordów po wielu polach naraz: rosnąco i malejąco, z bezpieczną obsługą wartości null i polskim porządkiem liter — Comparator, thenComparing i Collator w praktyce.
średni Zobacz kod → Kolekcje i strumienieRecord, equals/hashCode i niemodyfikowalne kolekcje
Rekordy z walidacją w konstruktorze kompaktowym, automatyczne equals i hashCode w roli elementu zbioru i klucza mapy, obronna kopia List.copyOf oraz różnica między migawką a widokiem Collections.unmodifiableList.
średni Zobacz kod →