Java Academy · Lekcja

Podmapy i widoki zakresów

Wyodrębniaj widoki subMap, headMap i tailMap do wyszukiwania zakresowego w posortowanych mapach.

Lekcja 2 z 413 kroki

Podmapy i widoki zakresów to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

Widoki zakresów w TreeMap

subMap, headMap i tailMap w TreeMap zwracają widoki powiązane z mapą — odzwierciedlają zmiany w mapie bazowej i odwrotnie. Zmiany wprowadzone przez widok są odzwierciedlane w oryginalnej mapie.

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 1; i <= 10; i++) map.put(i * 10, "item" + i);

var view = map.subMap(30, 70); // [30, 70)
System.out.println(view); // {30=item3, 40=item4, 50=item5, 60=item6}

map.put(45, "new"); // also visible through view!
System.out.println(view.containsKey(45)); // true

headMap: klucze poniżej granicy

headMap(toKey) zwraca wszystkie wpisy, których klucze są ściśle mniejsze niż toKey. Użyj wariantu włączającego granicę — headMap(toKey, true) — aby uwzględnić tę granicę.

TreeMap<String, Integer> words = new TreeMap<>();
"banana cherry apple date elderberry".chars()
    .mapToObj(c -> String.valueOf((char)c)).distinct()
    .forEach(w -> words.put(w, w.length()));
// Actually let's use real words:
TreeMap<String, Integer> wc = new TreeMap<>();
wc.put("apple",5); wc.put("banana",6); wc.put("cherry",6); wc.put("date",4);

System.out.println(wc.headMap("cherry")); // {apple=5, banana=6}

tailMap: klucze od granicy

tailMap(fromKey) zwraca wszystkie wpisy, których klucze są ≥ fromKey.

TreeMap<Integer, String> grades = new TreeMap<>();
grades.put(50,"F"); grades.put(60,"D"); grades.put(70,"C"); grades.put(80,"B"); grades.put(90,"A");

// All passing grades (>= 60)
var passing = grades.tailMap(60);
System.out.println(passing); // {60=D, 70=C, 80=B, 90=A}

subMap z włączającymi granicami

Wersja subMap(from, fromInclusive, to, toInclusive) z 4 argumentami zapewnia pełną kontrolę nad włączaniem granic:

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 10; i <= 100; i += 10) map.put(i, "v"+i);

// [30, 60] — both inclusive
System.out.println(map.subMap(30, true, 60, true));
// {30=v30, 40=v40, 50=v50, 60=v60}

// (30, 60) — both exclusive
System.out.println(map.subMap(30, false, 60, false));
// {40=v40, 50=v50}

Modyfikowanie za pośrednictwem widoku

Operacje put/remove na widoku subMap są odzwierciedlane w oryginalnej mapie (i odwrotnie). Próba wstawienia klucza spoza zakresu widoku powoduje zgłoszenie wyjątku.

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 1; i <= 5; i++) map.put(i * 10, "v" + i);

var view = map.subMap(20, 40); // [20, 40)
view.remove(20); // removes from both view and original map
System.out.println(map.containsKey(20)); // false

// This would throw IllegalArgumentException:
// view.put(50, "out of range");

Przypadek użycia: zapytanie o zakres logów

Pobierz wszystkie wpisy dziennika między dwoma znacznikami czasu, używając widoku zakresu TreeMap:

import java.time.*;
TreeMap<LocalDateTime, String> logs = new TreeMap<>();
logs.put(LocalDateTime.of(2024,1,1,8,0), "Server start");
logs.put(LocalDateTime.of(2024,1,1,10,0), "Request spike");
logs.put(LocalDateTime.of(2024,1,1,14,0), "Maintenance");
logs.put(LocalDateTime.of(2024,1,1,18,0), "Server stop");

var morning = logs.subMap(
    LocalDateTime.of(2024,1,1,8,0), true,
    LocalDateTime.of(2024,1,1,12,0), false
);
morning.forEach((t,m) -> System.out.println(t+" : "+m));

Przypadek użycia: wyszukiwanie zakresu cen

Znajdź wszystkie produkty w zakresie cen, używając cen jako kluczy TreeMap:

TreeMap<Double, String> products = new TreeMap<>();
products.put(9.99, "Pen");
products.put(24.99, "Book");
products.put(49.99, "Headphones");
products.put(299.99, "Tablet");

double min = 10.0, max = 100.0;
var affordable = products.subMap(min, true, max, true);
affordable.forEach((p,n) -> System.out.println(n+" $"+p));
// Book $24.99, Headphones $49.99

descending SubMap

Połącz descendingMap() z widokiem, aby nawigować w odwrotnej kolejności:

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 10; i <= 100; i += 10) map.put(i, "v"+i);

// Get [40, 80] in descending order
map.subMap(40, true, 80, true)
   .descendingMap()
   .forEach((k,v) -> System.out.println(k + "=" + v));
// 80=v80, 70=v70, 60=v60, 50=v50, 40=v40

Interfejs NavigableMap

NavigableMap rozszerza SortedMap i dodaje nawigację po kluczach ceiling/floor/higher/lower oraz widoki malejące. TreeMap to najczęściej używana implementacja; ConcurrentSkipListMap jest bezpieczną wątkowo alternatywą.

Wydajność widoków

Operacje na widoku podmapy (get, put, containsKey) mają taką samą złożoność O(log n) jak bazowa TreeMap. Utworzenie widoku ma złożoność O(1) — nie jest wykonywane kopiowanie. Skanowanie zakresu obejmującego n kluczy w widoku ma złożoność O(log N + n), gdzie N oznacza pełny rozmiar mapy.

Pułapka: nieaktualne widoki

Ponieważ widoki są powiązane z oryginalną mapą, widok może stać się pusty lub zgłosić wyjątek, jeśli oryginalna mapa zostanie wyczyszczona. Należy zawsze zaznaczyć, że widoki są żywe, i nie przechowywać ich dłużej niż przez zamierzony cykl życia.

TreeMap<Integer, String> map = new TreeMap<>();
map.put(10, "a"); map.put(20, "b"); map.put(30, "c");

var view = map.subMap(10, 30);
map.clear(); // view becomes empty
System.out.println(view.size()); // 0 — but no exception

Szybkie sprawdzenie

Wywołujesz map.subMap(30, false, 70, true) na obiekcie TreeMap z kluczami {10,20,30,40,50,60,70,80}. Które klucze zostaną uwzględnione w wyniku?

Podsumowanie: podmapy i widoki zakresów

Najważniejsze informacje:

  • subMap, headMap i tailMap zwracają żywe widoki powiązane z mapą — bez kopiowania
  • Zmiany w widoku są odzwierciedlane w oryginalnej mapie i odwrotnie
  • 4-argumentowa wersja subMap(from, fromInclusive, to, toInclusive) zapewnia pełną kontrolę nad granicami
  • Wstawienie wartości spoza zakresu za pośrednictwem widoku powoduje zgłoszenie IllegalArgumentException
  • Złożoność skanowania zakresu: O(log N + n)
Bezpłatny start

Ucz się Java dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
104
Lekcje
374

Często zadawane pytania

Czy lekcja „Podmapy i widoki zakresów” jest bezpłatna?

Tak — pełny tekst „Podmapy i widoki zakresów” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Podmapy i widoki zakresów”?

Wyodrębniaj widoki subMap, headMap i tailMap do wyszukiwania zakresowego w posortowanych mapach. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Podmapy i widoki zakresów”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. TreeMap: posortowane pary klucz-wartość
  2. Podmapy i widoki zakresów
  3. TreeSet i NavigableSet
  4. Własny porządek w kolekcjach typu Tree
← Powrót do Java Academy