📚 Ce este Map în Java?
Map este o interfață fundamentală în Java Collections Framework care stochează date sub formă de perechi cheie-valoare (key-value pairs). Spre deosebire de List sau Set, Map nu extinde interfața Collection, având propria ierarhie.
🔑 Chei Unice
Fiecare cheie poate apărea o singură dată în Map
🎯 Acces Rapid
Permite accesarea rapidă a valorilor folosind cheia
🔄 Valori Duplicate
Valorile pot fi duplicate, doar cheile sunt unice
📊 Structură Flexibilă
Ideal pentru mapări, dicționare și cache-uri
Declararea Interfeței Map
public interface Map<K, V> { // K - tipul cheilor // V - tipul valorilor V put(K key, V value); V get(Object key); V remove(Object key); boolean containsKey(Object key); boolean containsValue(Object value); int size(); boolean isEmpty(); void clear(); }
🔧 Tipuri de Map în Java
1. HashMap
HashMap este cea mai folosită implementare a interfeței Map. Folosește hash table pentru stocare.
- ✅ Permite null pentru cheie și valori
- ✅ Nu garantează ordinea elementelor
- ✅ Performanță O(1) pentru operații de bază
- ❌ Nu este sincronizat (not thread-safe)
import java.util.HashMap; // Crearea unui HashMap HashMap<String, Integer> varste = new HashMap<>(); // Adăugarea elementelor varste.put("Ion", 25); varste.put("Maria", 30); varste.put("Andrei", 28); varste.put(null, 35); // Cheie null permisă // Accesarea valorilor Integer varstaIon = varste.get("Ion"); // 25 // Verificarea existenței if (varste.containsKey("Maria")) { System.out.println("Maria are " + varste.get("Maria") + " ani"); }
2. LinkedHashMap
LinkedHashMap extinde HashMap și menține ordinea de inserție folosind o listă dublu înlănțuită.
- ✅ Păstrează ordinea de inserție
- ✅ Permite configurarea pentru access-order
- ✅ Ideal pentru implementarea LRU cache
- ❌ Overhead de memorie mai mare decât HashMap
import java.util.LinkedHashMap; // LinkedHashMap cu ordine de inserție LinkedHashMap<String, String> tari = new LinkedHashMap<>(); tari.put("RO", "România"); tari.put("FR", "Franța"); tari.put("DE", "Germania"); tari.put("IT", "Italia"); // Elementele vor fi iterate în ordinea inserării tari.forEach((cod, nume) -> System.out.println(cod + " -> " + nume) ); // LRU Cache folosind LinkedHashMap LinkedHashMap<Integer, String> lruCache = new LinkedHashMap<>(16, 0.75f, true) { protected boolean removeEldestEntry(Map.Entry eldest) { return size() > 100; // Maxim 100 elemente } };
3. TreeMap
TreeMap implementează interfețele NavigableMap și SortedMap, stochând elementele sortate.
- ✅ Chei sortate automat
- ✅ Implementare Red-Black Tree
- ✅ Operații O(log n)
- ❌ Nu permite chei null
import java.util.TreeMap; // TreeMap cu sortare naturală TreeMap<Integer, String> note = new TreeMap<>(); note.put(95, "Excelent"); note.put(75, "Bine"); note.put(85, "Foarte bine"); note.put(60, "Satisfăcător"); // Elementele sunt sortate după cheie System.out.println(note); // {60=Satisfăcător, 75=Bine, 85=Foarte bine, 95=Excelent} // Operații NavigableMap System.out.println(note.firstKey()); // 60 System.out.println(note.lastKey()); // 95 System.out.println(note.ceilingKey(80)); // 85 (cea mai mică cheie >= 80) System.out.println(note.floorKey(80)); // 75 (cea mai mare cheie <= 80) // SubMap SortedMap<Integer, String> noteIntre = note.subMap(70, 90); System.out.println(noteIntre); // {75=Bine, 85=Foarte bine}
4. Hashtable
Hashtable este o clasă legacy, sincronizată și thread-safe.
- ✅ Thread-safe (sincronizat)
- ❌ Nu permite null pentru chei sau valori
- ❌ Mai lent decât HashMap
- ⚠️ Considerat legacy, folosiți ConcurrentHashMap
import java.util.Hashtable; Hashtable<String, Double> preturi = new Hashtable<>(); preturi.put("Pâine", 5.50); preturi.put("Lapte", 8.20); preturi.put("Ouă", 15.00); // preturi.put(null, 10.0); // Aruncă NullPointerException // preturi.put("Unt", null); // Aruncă NullPointerException
5. ConcurrentHashMap
ConcurrentHashMap este alternativa modernă pentru Hashtable, optimizată pentru concurență.
- ✅ Thread-safe cu performanță superioară
- ✅ Permite operații concurente
- ✅ Segment-based locking
- ❌ Nu permite null pentru chei sau valori
import java.util.concurrent.ConcurrentHashMap; ConcurrentHashMap<String, Integer> contor = new ConcurrentHashMap<>(); // Thread-safe operations contor.put("vizitatori", 0); // Atomic operations contor.compute("vizitatori", (k, v) -> v + 1); contor.computeIfAbsent("utilizatori", k -> 0); contor.merge("total", 1, Integer::sum);
⚙️ Operații de Bază cu Map
Operații CRUD Complete
import java.util.*; public class MapOperations { public static void main(String[] args) { Map<String, Integer> stoc = new HashMap<>(); // CREATE - Adăugare elemente stoc.put("Laptop", 15); stoc.put("Mouse", 50); stoc.put("Tastatură", 30); // putIfAbsent - adaugă doar dacă cheia nu există stoc.putIfAbsent("Monitor", 20); stoc.putIfAbsent("Mouse", 100); // Nu va modifica valoarea existentă // READ - Citire valori Integer cantitate = stoc.get("Laptop"); Integer defaultVal = stoc.getOrDefault("Telefon", 0); // UPDATE - Actualizare valori stoc.put("Laptop", 20); // Suprascrie valoarea stoc.replace("Mouse", 45); stoc.replace("Tastatură", 30, 35); // Replace doar dacă valoarea e 30 // Compute methods stoc.compute("Monitor", (k, v) -> v + 5); stoc.computeIfPresent("Laptop", (k, v) -> v * 2); stoc.computeIfAbsent("Cablu", k -> 100); // DELETE - Ștergere elemente stoc.remove("Cablu"); stoc.remove("Mouse", 45); // Șterge doar dacă valoarea e 45 // Verificări boolean areLaptop = stoc.containsKey("Laptop"); boolean areValoare20 = stoc.containsValue(20); boolean esteGol = stoc.isEmpty(); int dimensiune = stoc.size(); } }
Iterarea prin Map
Map<String, Integer> puncte = new HashMap<>(); puncte.put("Echipa A", 45); puncte.put("Echipa B", 38); puncte.put("Echipa C", 52); // 1. Iterare prin entrySet() - Cel mai eficient for (Map.Entry<String, Integer> entry : puncte.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } // 2. Iterare prin keySet() for (String echipa : puncte.keySet()) { System.out.println(echipa + ": " + puncte.get(echipa)); } // 3. Iterare prin values() for (Integer punctaj : puncte.values()) { System.out.println("Punctaj: " + punctaj); } // 4. Java 8+ forEach cu lambda puncte.forEach((echipa, punctaj) -> System.out.println(echipa + " are " + punctaj + " puncte") ); // 5. Java 8+ Stream API puncte.entrySet().stream() .filter(e -> e.getValue() > 40) .forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));
put(K key, V value)
Adaugă sau actualizează o pereche cheie-valoare
get(Object key)
Returnează valoarea asociată cheii
remove(Object key)
Șterge perechea cheie-valoare
containsKey(Object key)
Verifică dacă cheia există
containsValue(Object value)
Verifică dacă valoarea există
size()
Returnează numărul de elemente
isEmpty()
Verifică dacă Map-ul este gol
clear()
Șterge toate elementele
keySet()
Returnează Set-ul de chei
values()
Returnează Collection de valori
entrySet()
Returnează Set de Entry-uri
putAll(Map m)
Adaugă toate elementele din alt Map
💻 Exemple Practice
Exemplu 1: Numărarea Frecvenței Cuvintelor
import java.util.*; public class FrecventaCuvinte { public static void main(String[] args) { String text = "java este un limbaj de programare java este popular"; String[] cuvinte = text.split(" "); Map<String, Integer> frecventa = new HashMap<>(); // Metoda clasică for (String cuvant : cuvinte) { if (frecventa.containsKey(cuvant)) { frecventa.put(cuvant, frecventa.get(cuvant) + 1); } else { frecventa.put(cuvant, 1); } } // Metoda Java 8+ Map<String, Integer> frecventa2 = new HashMap<>(); for (String cuvant : cuvinte) { frecventa2.merge(cuvant, 1, Integer::sum); } // Afișare sortată după frecvență frecventa.entrySet().stream() .sorted(Map.Entry.<String, Integer>comparingByValue().reversed()) .forEach(e -> System.out.println(e.getKey() + ": " + e.getValue())); } }
Exemplu 2: Gruparea Datelor
class Student { String nume; String facultate; int varsta; public Student(String nume, String facultate, int varsta) { this.nume = nume; this.facultate = facultate; this.varsta = varsta; } } public class GrupareStudenti { public static void main(String[] args) { List<Student> studenti = Arrays.asList( new Student("Ana", "Informatică", 20), new Student("Ion", "Matematică", 21), new Student("Maria", "Informatică", 22), new Student("Dan", "Fizică", 20), new Student("Elena", "Informatică", 21) ); // Grupare după facultate Map<String, List<Student>> grupeDupăFacultate = new HashMap<>(); for (Student student : studenti) { grupeDupăFacultate .computeIfAbsent(student.facultate, k -> new ArrayList<>()) .add(student); } // Java 8+ Stream API Map<String, List<Student>> grupe = studenti.stream() .collect(Collectors.groupingBy(s -> s.facultate)); // Afișare grupe.forEach((facultate, lista) -> { System.out.println(facultate + ": " + lista.size() + " studenți"); }); } }
Exemplu 3: Cache Implementation
import java.util.*; class SimpleCache<K, V> { private final int maxSize; private final LinkedHashMap<K, V> cache; public SimpleCache(int maxSize) { this.maxSize = maxSize; this.cache = new LinkedHashMap<K, V>(16, 0.75f, true) { protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > SimpleCache.this.maxSize; } }; } public synchronized V get(K key) { return cache.get(key); } public synchronized void put(K key, V value) { cache.put(key, value); } public synchronized void clear() { cache.clear(); } public synchronized int size() { return cache.size(); } } public class TestCache { public static void main(String[] args) { SimpleCache<String, String> cache = new SimpleCache<>(3); cache.put("user1", "Ion Popescu"); cache.put("user2", "Maria Ionescu"); cache.put("user3", "Ana Popa"); cache.put("user4", "Dan Mihai"); // user1 va fi eliminat System.out.println(cache.get("user1")); // null System.out.println(cache.get("user2")); // Maria Ionescu } }
Exemplu 4: Map de Map-uri (Structuri Complexe)
// Exemplu: Stocarea notelor studenților pe materii și semestre Map<String, Map<String, Double>> catalog = new HashMap<>(); // Adăugare note pentru studenți catalog.computeIfAbsent("Ion Popescu", k -> new HashMap<>()) .put("Matematică", 9.5); catalog.computeIfAbsent("Ion Popescu", k -> new HashMap<>()) .put("Informatică", 10.0); catalog.computeIfAbsent("Maria Ionescu", k -> new HashMap<>()) .put("Matematică", 8.5); // Calcularea mediei pentru fiecare student catalog.forEach((student, note) -> { double medie = note.values().stream() .mapToDouble(Double::doubleValue) .average() .orElse(0.0); System.out.println(student + ": Media = " + medie); });
🧩 Probleme Practice cu Map
Consolidează-ți cunoștințele rezolvând aceste probleme clasice care apar frecvent în interviuri și aplicații reale.
🟢 Probleme Ușoare
1. Two Sum (LeetCode #1)
Problemă: Găsește două numere într-un array care adunate dau o sumă țintă.
public int[] twoSum(int[] nums, int target) { // Folosim HashMap pentru a stoca valoarea și indexul Map<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { int complement = target - nums[i]; // Verificăm dacă complementul există în map if (map.containsKey(complement)) { return new int[] {map.get(complement), i}; } // Adăugăm numărul curent în map map.put(nums[i], i); } return new int[] {}; // Nu s-a găsit soluție } // Exemplu de utilizare: int[] nums = {2, 7, 11, 15}; int target = 9; int[] result = twoSum(nums, target); System.out.println(Arrays.toString(result)); // [0, 1]
2. Primul Caracter Unic
Problemă: Găsește primul caracter care apare o singură dată într-un string.
public char firstUniqueChar(String s) { // Numărăm frecvența fiecărui caracter Map<Character, Integer> frecventa = new LinkedHashMap<>(); for (char c : s.toCharArray()) { frecventa.put(c, frecventa.getOrDefault(c, 0) + 1); } // Găsim primul caracter cu frecvența 1 for (Map.Entry<Character, Integer> entry : frecventa.entrySet()) { if (entry.getValue() == 1) { return entry.getKey(); } } return '\0'; // Nu există caracter unic } // Test: System.out.println(firstUniqueChar("leetcode")); // 'l' System.out.println(firstUniqueChar("loveleetcode")); // 'v'
3. Verificare Anagramă
Problemă: Verifică dacă două string-uri sunt anagrame (conțin aceleași caractere în aceeași frecvență).
public boolean isAnagram(String s1, String s2) { if (s1.length() != s2.length()) { return false; } Map<Character, Integer> map = new HashMap<>(); // Adăugăm caracterele din primul string for (char c : s1.toCharArray()) { map.put(c, map.getOrDefault(c, 0) + 1); } // Scădem caracterele din al doilea string for (char c : s2.toCharArray()) { if (!map.containsKey(c)) { return false; } map.put(c, map.get(c) - 1); if (map.get(c) < 0) { return false; } } // Verificăm dacă toate valorile sunt 0 return map.values().stream().allMatch(count -> count == 0); } // Test: System.out.println(isAnagram("anagram", "nagaram")); // true System.out.println(isAnagram("rat", "car")); // false
🟡 Probleme Medii
4. Group Anagrams (LeetCode #49)
Problemă: Grupează string-urile care sunt anagrame între ele.
public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> map = new HashMap<>(); for (String str : strs) { // Sortăm caracterele pentru a obține cheia char[] chars = str.toCharArray(); Arrays.sort(chars); String key = String.valueOf(chars); // Adăugăm string-ul la grupul corespunzător map.computeIfAbsent(key, k -> new ArrayList<>()).add(str); } return new ArrayList<>(map.values()); } // Alternativă optimizată cu frecvență caractere: public List<List<String>> groupAnagramsOptimized(String[] strs) { Map<String, List<String>> map = new HashMap<>(); for (String str : strs) { // Creăm o cheie bazată pe frecvența caracterelor int[] count = new int[26]; for (char c : str.toCharArray()) { count[c - 'a']++; } StringBuilder key = new StringBuilder(); for (int i = 0; i < 26; i++) { key.append('#').append(count[i]); } map.computeIfAbsent(key.toString(), k -> new ArrayList<>()).add(str); } return new ArrayList<>(map.values()); } // Test: String[] input = {"eat", "tea", "tan", "ate", "nat", "bat"}; System.out.println(groupAnagrams(input)); // Output: [["eat","tea","ate"], ["tan","nat"], ["bat"]]
5. Subarray Sum Equals K (LeetCode #560)
Problemă: Găsește numărul de subarray-uri continue care au suma egală cu K.
public int subarraySum(int[] nums, int k) { Map<Integer, Integer> sumFreq = new HashMap<>(); sumFreq.put(0, 1); // Suma 0 apare o dată (array gol) int currentSum = 0; int count = 0; for (int num : nums) { currentSum += num; // Verificăm dacă există o sumă prefix care, // scăzută din suma curentă, dă k if (sumFreq.containsKey(currentSum - k)) { count += sumFreq.get(currentSum - k); } // Adăugăm suma curentă în map sumFreq.put(currentSum, sumFreq.getOrDefault(currentSum, 0) + 1); } return count; } // Test: int[] nums = {1, 1, 1}; System.out.println(subarraySum(nums, 2)); // 2 (subarray-urile [1,1] de 2 ori)
6. Longest Substring Without Repeating Characters (LeetCode #3)
Problemă: Găsește lungimea celui mai lung substring fără caractere repetate.
public int lengthOfLongestSubstring(String s) { Map<Character, Integer> lastIndex = new HashMap<>(); int maxLength = 0; int start = 0; for (int end = 0; end < s.length(); end++) { char c = s.charAt(end); // Dacă caracterul a mai apărut și e în fereastra curentă if (lastIndex.containsKey(c) && lastIndex.get(c) >= start) { start = lastIndex.get(c) + 1; } lastIndex.put(c, end); maxLength = Math.max(maxLength, end - start + 1); } return maxLength; } // Varianta cu Set pentru vizualizare mai clară: public int lengthOfLongestSubstringSet(String s) { Set<Character> window = new HashSet<>(); int maxLength = 0; int left = 0, right = 0; while (right < s.length()) { if (!window.contains(s.charAt(right))) { window.add(s.charAt(right)); maxLength = Math.max(maxLength, right - left + 1); right++; } else { window.remove(s.charAt(left)); left++; } } return maxLength; } // Test: System.out.println(lengthOfLongestSubstring("abcabcbb")); // 3 ("abc") System.out.println(lengthOfLongestSubstring("bbbbb")); // 1 ("b")
🔴 Probleme Avansate
7. LRU Cache (LeetCode #146)
Problemă: Implementează un Least Recently Used (LRU) cache cu complexitate O(1) pentru get și put.
class LRUCache { class Node { int key, value; Node prev, next; Node(int key, int value) { this.key = key; this.value = value; } } private final int capacity; private final Map<Integer, Node> cache; private final Node head, tail; public LRUCache(int capacity) { this.capacity = capacity; this.cache = new HashMap<>(); // Noduri santinelă pentru lista dublu înlănțuită this.head = new Node(0, 0); this.tail = new Node(0, 0); head.next = tail; tail.prev = head; } public int get(int key) { if (!cache.containsKey(key)) { return -1; } Node node = cache.get(key); removeNode(node); addToHead(node); return node.value; } public void put(int key, int value) { if (cache.containsKey(key)) { Node node = cache.get(key); node.value = value; removeNode(node); addToHead(node); } else { if (cache.size() == capacity) { Node lru = tail.prev; removeNode(lru); cache.remove(lru.key); } Node newNode = new Node(key, value); cache.put(key, newNode); addToHead(newNode); } } private void removeNode(Node node) { node.prev.next = node.next; node.next.prev = node.prev; } private void addToHead(Node node) { node.next = head.next; node.prev = head; head.next.prev = node; head.next = node; } }
8. Word Pattern (LeetCode #290)
Problemă: Verifică dacă un string urmează un anumit pattern.
public boolean wordPattern(String pattern, String s) { String[] words = s.split(" "); if (pattern.length() != words.length) { return false; } Map<Character, String> charToWord = new HashMap<>(); Map<String, Character> wordToChar = new HashMap<>(); for (int i = 0; i < pattern.length(); i++) { char c = pattern.charAt(i); String word = words[i]; // Verificăm maparea bidirecțională if (charToWord.containsKey(c)) { if (!charToWord.get(c).equals(word)) { return false; } } else { charToWord.put(c, word); } if (wordToChar.containsKey(word)) { if (!wordToChar.get(word).equals(c)) { return false; } } else { wordToChar.put(word, c); } } return true; } // Test: System.out.println(wordPattern("abba", "dog cat cat dog")); // true System.out.println(wordPattern("abba", "dog cat cat fish")); // false
9. Top K Frequent Elements (LeetCode #347)
Problemă: Găsește cele mai frecvente K elemente dintr-un array.
public int[] topKFrequent(int[] nums, int k) { // Pasul 1: Calculăm frecvența Map<Integer, Integer> freq = new HashMap<>(); for (int num : nums) { freq.put(num, freq.getOrDefault(num, 0) + 1); } // Pasul 2: Bucket sort - grupăm după frecvență List<Integer>[] buckets = new List[nums.length + 1]; for (Map.Entry<Integer, Integer> entry : freq.entrySet()) { int frequency = entry.getValue(); if (buckets[frequency] == null) { buckets[frequency] = new ArrayList<>(); } buckets[frequency].add(entry.getKey()); } // Pasul 3: Colectăm top K elemente List<Integer> result = new ArrayList<>(); for (int i = buckets.length - 1; i >= 0 && result.size() < k; i--) { if (buckets[i] != null) { result.addAll(buckets[i]); } } return result.stream().mapToInt(i -> i).toArray(); } // Alternativă cu PriorityQueue: public int[] topKFrequentHeap(int[] nums, int k) { Map<Integer, Integer> freq = new HashMap<>(); for (int num : nums) { freq.put(num, freq.getOrDefault(num, 0) + 1); } PriorityQueue<Integer> heap = new PriorityQueue<>( (a, b) -> freq.get(b) - freq.get(a) ); heap.addAll(freq.keySet()); int[] result = new int[k]; for (int i = 0; i < k; i++) { result[i] = heap.poll(); } return result; }
- 🎯 Identifică pattern-ul: frecvență, grupare, mapare bidirecțională
- 🔑 Alege cheia potrivită: ce informație trebuie accesată rapid?
- ⚡ Optimizează cu compute methods: computeIfAbsent, merge
- 🔄 Pentru sliding window: folosește Map pentru a urmări elementele din fereastră
- 📊 Pentru counting: Map<Element, Integer> sau Map<Element, Long>
- 🎨 Pentru grupare: Map<Key, List<Value>>
- HashMap: O(1) amortizat pentru operații de bază
- TreeMap: O(log n) pentru operații de bază
- Spațiu: O(n) unde n este numărul de perechi cheie-valoare
- Atenție la collision handling în HashMap - worst case O(n)
📊 Comparație între Implementări
| Caracteristică | HashMap | LinkedHashMap | TreeMap | Hashtable | ConcurrentHashMap |
|---|---|---|---|---|---|
| Ordine | Fără ordine | Ordine inserție | Sortată | Fără ordine | Fără ordine |
| Null Keys | ✅ Da (unul) | ✅ Da (unul) | ❌ Nu | ❌ Nu | ❌ Nu |
| Null Values | ✅ Da | ✅ Da | ✅ Da | ❌ Nu | ❌ Nu |
| Thread-Safe | ❌ Nu | ❌ Nu | ❌ Nu | ✅ Da | ✅ Da |
| Performanță | O(1) | O(1) | O(log n) | O(1) | O(1) |
| Overhead Memorie | Mic | Mediu | Mare | Mediu | Mare |
| Când să folosești | Uz general | Ordine necesară | Sortare necesară | Legacy code | Concurență |
✨ Best Practices și Sfaturi
1. Alegeți Implementarea Corectă
HashMap pentru performanță, LinkedHashMap pentru ordine, TreeMap pentru sortare, ConcurrentHashMap pentru thread-safety.
2. Inițializați cu Capacitate
Pentru Map-uri mari, specificați capacitatea inițială pentru a evita redimensionările: new HashMap<>(1000)
3. Implementați equals() și hashCode()
Pentru chei custom, implementați corect metodele equals() și hashCode() pentru funcționare corectă.
4. Folosiți Immutable Keys
Cheile ar trebui să fie immutable pentru a evita comportamente neprevăzute.
5. Null Safety
Folosiți getOrDefault() și computeIfAbsent() pentru a evita NullPointerException.
6. Java 8+ Features
Utilizați metodele compute(), merge(), și forEach() pentru cod mai curat și expresiv.
Exemple de Anti-Pattern-uri de Evitat
- Nu modificați obiectele folosite ca chei după inserare
- Nu iterați și modificați simultan Map-ul (folosiți Iterator)
- Nu presupuneți ordinea în HashMap
- Nu folosiți Hashtable în cod nou (preferați ConcurrentHashMap)
Cod pentru Evitarea ConcurrentModificationException
Map<String, Integer> map = new HashMap<>(); map.put("A", 1); map.put("B", 2); map.put("C", 3); // GREȘIT - va arunca ConcurrentModificationException // for (String key : map.keySet()) { // if (map.get(key) == 2) { // map.remove(key); // } // } // CORECT - Folosind Iterator Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> entry = iterator.next(); if (entry.getValue() == 2) { iterator.remove(); } } // CORECT - Java 8+ removeIf map.entrySet().removeIf(entry -> entry.getValue() == 2);
🎮 Demo Interactiv - Rezolvă o Problemă
Apasă butoanele pentru a vedea diferite exemple de Map în acțiune: