Map.entrySet: примеры (JAVA)
Map.entrySet: Set> Описание Map.entrySet
Метод Map.entrySet() возвращает представление набором элементов пары ключ-значение в карте в виде Set<Map.Entry<K,V>>. Это не копия, а представление, связанное с исходной картой: изменения в наборе отражаются в карте и обратно при условии, что реализация карты поддерживает модификации. Набор используется для итерации по элементам, массовых операций удаления и для прямой модификации значений через Map.Entry.setValue.
Аргументы: метод без аргументов.
Возвращаемое значение: Set<Map.Entry<K,V>>. Особенности возвращаемого набора:
- Это представление (view) данных карты, а не глубокая копия.
- Итератор набора поддерживает
remove(), который удаляет соответствующую запись из карты. - Записи реализованы как
Map.Entry<K,V>с методамиgetKey(),getValue(),setValue(V). Для некоторых реализацийsetValueможет выбрасыватьUnsupportedOperationException(например, для неизменяемых карт). - Семантика
equals()иhashCode()для записей соответствует контрактуMap.Entry, что позволяет сравнивать наборы записей между картами. - Поведение при параллельном доступе зависит от реализации карты (например,
HashMapне потокобезопасен,ConcurrentHashMapимеет свои ограничения).
Типичные сценарии использования: перебор пар ключ-значение с доступом к ключу и значению без дополнительного поиска, удаление элементов во время итерации, массовые операции через removeIf или работа со стримами через map.entrySet().stream().
Примеры использования
Примеры показывают базовые варианты получения и использования entrySet(), с кодом и результатом.
Итерация for-each и вывод
import java.util.*;
public class Example1 {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
for (Map.Entry e : map.entrySet()) {
System.out.println(e.getKey() + " -> " + e.getValue());
}
}
}
a -> 1 b -> 2 c -> 3
Изменение значения через Map.Entry.setValue
import java.util.*;
class Example2 {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("x", 10);
for (Map.Entry e : map.entrySet()) {
e.setValue(e.getValue() + 5);
}
System.out.println(map);
}
}
{x=15}
Удаление во время итерации через Iterator.remove
import java.util.*;
class Example3 {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("a", 1); map.put("b", 2); map.put("c", 3);
Iterator> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry e = it.next();
if (e.getValue() % 2 == 0) it.remove();
}
System.out.println(map);
}
}
{a=1, c=3}
Использование с потоками
import java.util.*;
import java.util.stream.*;
class Example4 {
public static void main(String[] args) {
Map map = Map.of("a",1,"b",2,"c",3);
List keysWithOdd = map.entrySet().stream()
.filter(e -> e.getValue() % 2 == 1)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
System.out.println(keysWithOdd);
}
}
[a, c]
Похожие методы в Java
В Java доступны другие представления и методы, близкие по назначению к entrySet():
Map.keySet()- возвращаетSetключей. Предпочтителен, когда нужна только информация о ключах, без значений.Map.values()- возвращает коллекцию значений. Удобен для операций только со значениями, но не сохраняет соответствие с ключами.Map.forEach(BiConsumer)- выполняет действие для каждой пары, не возвращая представление. Удобен для побочных эффектов без модификации структуры коллекции.Map.ofEntries(...)иMap.entry(K,V)(Java 9+) - средства для создания небольших неизменяемых карт; возвращаемые карты обычно не поддерживаютsetValueи бросаютUnsupportedOperationException.
Выбор: если требуется итерироваться и изменять значения без дополнительных обращений по ключу, entrySet() предпочтительнее. Для простых списков ключей или значений лучше применять keySet() или values().
Аналоги в других языках
Краткие сравнения и примеры эквивалентов Map.entrySet() в популярных языках.
JavaScript
// Для объекта
const obj = {a:1, b:2};
console.log(Object.entries(obj));
// Для Map
const m = new Map([["a",1],["b",2]]);
console.log(Array.from(m.entries()));
[['a',1],['b',2]] [['a',1],['b',2]]
Python
d = {'a':1, 'b':2}
print(list(d.items()))
# Итерация дает кортежи (key, value)
[('a', 1), ('b', 2)]
PHP
$arr = ['a'=>1, 'b'=>2];
foreach ($arr as $k => $v) { echo "$k -> $v\n"; }
a -> 1 b -> 2
C#
using System; using System.Collections.Generic;
class P { static void Main(){
var d = new Dictionary{{"a",1},{"b",2}};
foreach(var kv in d) Console.WriteLine(kv.Key + " -> " + kv.Value);
}}
a -> 1 b -> 2
Go
m := map[string]int{"a":1, "b":2}
for k,v := range m {
fmt.Println(k, v)
}
a 1 b 2
Отличия от Java: в большинстве языков представление пар возвращается в виде массивов/кортежей или итераторов. В Java важна семантика view: изменения через запись в наборе отражаются в исходной карте при поддержке операции, а в многих других языках копирование является обычным поведением, либо нет аналога setValue как метода записи в паре.
Типичные ошибки и исключения
Частые проблемы при работе с entrySet() и примеры:
ConcurrentModificationException при модификации карты
import java.util.*;
class Err1 {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("a",1); map.put("b",2);
for (Map.Entry e : map.entrySet()) {
if (e.getKey().equals("a")) map.remove("a"); // некорректно
}
}
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
...
Правильно: использовать Iterator.remove() или collect to remove потом или removeIf.
UnsupportedOperationException для неизменяемых карт
import java.util.*;
class Err2 {
public static void main(String[] args) {
Map map = Map.of("a",1);
Map.Entry e = map.entrySet().iterator().next();
e.setValue(2); // вызовет исключение
}
}
Exception in thread "main" java.lang.UnsupportedOperationException
at ...
ClassCastException или Comparator mismatch для TreeMap
import java.util.*;
class Err3 {
public static void main(String[] args) {
Map map = new TreeMap();
map.put(1, "one");
map.put("two", 2); // разные типы ключей приведут к ошибке при сравнениях
}
}
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer
at ...
Ещё один нюанс: у ConcurrentHashMap вызов entry.setValue может быть не поддержан и бросать UnsupportedOperationException в зависимости от реализации.
Изменения в последних версиях Java
Сам метод entrySet() существует давно и существенно не менялся, но в последних релизах появились сопутствующие возможности:
- Java 8: появление Stream API. Часто применяется
map.entrySet().stream()для преобразований и фильтрации. - Java 9: добавлены
Map.entry(K,V)и фабричные методыMap.of,Map.ofEntries. Возвращаемые карты могут быть неизменяемыми, что влияет на поведениеentry.setValueи операций удаления. - Java 10/11:
Map.copyOfдля создания неизменяемых копий; у неизменяемых карт набор записей будет бросатьUnsupportedOperationExceptionпри попытке модификации.
Итог: сам контракт entrySet() не изменился, но окружение и дополнительные API сделали использование более гибким и добавили факторы, которые влияют на возможность модификации возвращаемого представления.
Расширенные и редкие примеры
Несколько продвинутых сценариев с пояснениями и результатами.
Удаление по условию через removeIf
import java.util.*;
class Adv1 {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("a",1); map.put("b",2); map.put("c",3);
map.entrySet().removeIf(e -> e.getValue() < 3);
System.out.println(map);
}
}
{c=3}
Атомарное обновление значений без дополнительного поиска
import java.util.*;
class Adv2 {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("k", 1);
for (Map.Entry e : map.entrySet()) {
e.setValue(e.getValue() * 2); // обновление in-place
}
System.out.println(map);
}
}
{k=2}
Сборка новой карты из entrySet с преобразованием ключей и значений
import java.util.*;
import java.util.stream.*;
class Adv3 {
public static void main(String[] args) {
Map map = Map.of("a",1,"b",2);
Map transformed = map.entrySet().stream()
.collect(Collectors.toMap(
e -> e.getKey().toUpperCase(),
e -> "val:" + e.getValue()
));
System.out.println(transformed);
}
}
{A=val:1, B=val:2}
Использование entrySet с ConcurrentHashMap для безопасных операций чтения/записи
import java.util.concurrent.*;
class Adv4 {
public static void main(String[] args) {
ConcurrentHashMap chm = new ConcurrentHashMap<>();
chm.put("a",1); chm.put("b",2);
chm.forEach(1, (k,v) -> System.out.println(k+":"+v));
// Прямая модификация через entry.setValue может быть неопределенной, рекомендуется compute/replace
chm.computeIfPresent("a", (k,v) -> v + 10);
System.out.println(chm);
}
}
a:1
b:2
{a=11, b=2}
Использование entrySet для поиска пары с минимальным значением
import java.util.*;
class Adv5 {
public static void main(String[] args) {
Map map = Map.of("x",10,"y",5,"z",7);
Map.Entry min = map.entrySet().stream()
.min(Map.Entry.comparingByValue())
.orElse(null);
System.out.println(min.getKey()+" -> "+min.getValue());
}
}
y -> 5
Комментарий: entrySet дает доступ к ключу и значению одновременно, что позволяет избегать двух обращений к карте (get по ключу) и повышает производительность в коде с интенсивной обработкой пар.