Set.clear(): примеры (JAVA)
Set.clear(): voidОписание метода
В Java метод clear присутствует в интерфейсе java.util.Collection и, следовательно, реализуется большинством реализаций Set (например, HashSet, TreeSet, LinkedHashSet). Сигнатура метода:
void clear()
Краткое поведение:
- Удаляет все элементы из множества. После вызова
size()возвращает 0,isEmpty()возвращаетtrue. - Аргументы отсутствуют. Возвращаемое значение отсутствует (тип
void). - Реализация зависит от конкретного класса: операция может быть оптимизирована для определённых структур данных, но семантика - удалить все элементы - сохраняется.
- Если сет является представлением (view) другой коллекции, например
map.keySet(), очистка представления влияет на исходную коллекцию (удаляются соответствующие элементы в исходном контейнере).
Возможные исключения и особенности:
- UnsupportedOperationException - если конкретная реализация не поддерживает модификацию (например, неизменяемые множества, создаваемые через
Set.of(...)илиCollections.unmodifiableSet(...)). - ConcurrentModificationException - может возникнуть при обнаружении модификации коллекции во время итерации с помощью несинхронизированного итератора у реализаций, отслеживающих изменения модификаций. Сам по себе
clear()не гарантирует атомарность для всех реализаций и может быть видим по-разному в многопоточной среде. - Для конкурентных реализаций (например,
ConcurrentSkipListSetили наборов на основеConcurrentHashMap) поведение более подходящее для многопоточных сценариев, но точная семантика удаления и видимость зависят от конкретной реализации.
Типичное применение: быстро удалить все элементы, чтобы переиспользовать экземпляр множества без выделения новой структуры или чтобы очистить представление коллекции, связанной с другой структурой (например, удалить все записи из карты через map.keySet().clear()).
Короткие примеры использования
Пример 1. Обычное очищение HashSet:
import java.util.*;
class Example1 {
public static void main(String[] args) {
Set set = new HashSet<>(Arrays.asList("a", "b", "c"));
set.clear();
System.out.println(set.size());
System.out.println(set.isEmpty());
}
}
0 true
Пример 2. Попытка очистить неизменяемое множество:
import java.util.*;
class Example2 {
public static void main(String[] args) {
Set immutable = Set.of("x", "y");
immutable.clear(); // UnsupportedOperationException
}
}
Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.clear(ImmutableCollections.java:148)
...
Пример 3. Очистка представления ключей карты влияет на карту:
import java.util.*;
class Example3 {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.keySet().clear();
System.out.println(map.size());
}
}
0
Пример 4. Модификация во время итерации вызывает исключение у большинства реализаций:
import java.util.*;
class Example4 {
public static void main(String[] args) {
Set set = new HashSet<>(Arrays.asList("a","b","c"));
for (String s : set) {
if (s.equals("b")) {
set.clear(); // ConcurrentModificationException
}
}
}
}
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1577)
at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1600)
at java.base/java.util.HashSet$Itr.next(HashSet.java:157)
...
Пример 5. Очистка конкурентного множества безопасна для параллельного использования в большинстве случаев:
import java.util.*;
import java.util.concurrent.*;
class Example5 {
public static void main(String[] args) {
Set cs = new ConcurrentSkipListSet<>(Arrays.asList("a","b","c"));
cs.clear();
System.out.println(cs.isEmpty());
}
}
true
Похожие методы в Java и критерии выбора
- removeAll(Collection c) - удаляет все элементы, содержащиеся в переданной коллекции. Используется для удаления определённого поднабора, а не всех элементов.
- removeIf(Predicate) - удаляет элементы по условию; полезно, когда нужно удалить часть элементов без полного очищения.
- iterator().remove() - удаление текущего элемента во время итерации; безопасно для последовательной модификации по одному элементу.
- retainAll(Collection c) - оставляет только элементы, присутствующие в переданной коллекции; применяется для пересечения множеств.
- Присваивание новой коллекции (например,
set = new HashSet<>()) - альтернатива, когда нет ссылок, которые требуется очистить, и приемлемо переназначение переменной. При наличии других ссылок на исходный объект это не приведёт к их очистке.
Выбор метода зависит от задачи: полная очистка - clear(), фильтрация - removeIf или removeAll, аккуратное удаление во время итерации - через итератор.
Аналоги в других языках и отличия
- JavaScript:
Set.prototype.clear()- удаляет все элементы, возвращаетundefined. Пример:const s = new Set(['a','b']); s.clear(); console.log(s.size);0
- Python:
set.clear()- удаляет все элементы, возвращаетNone. Пример:s = {1,2,3} s.clear() print(len(s), s)0 set()
- C#:
HashSet<T>.Clear()- удаляет все элементы, возвращаетvoid. Пример:var s = new HashSet{"a","b"}; s.Clear(); Console.WriteLine(s.Count); 0
- Kotlin:
MutableSet.clear()- поведение аналогично Java. Пример:val s = mutableSetOf("a","b") s.clear() println(s.size)0
- Go: в языке нет встроенного множества, обычно используется
map[T]struct{}. Очистка выполняется переназначением или итерацией с удалением. Пример:m := map[string]struct{}{"a":{},"b":{}} // очистка m = make(map[string]struct{}) fmt.Println(len(m))0
- Lua: таблица как множество, очистка - установка nil для ключей или новая таблица. Пример:
s = {a=true, b=true} for k in pairs(s) do s[k] = nil end print(next(s)) -- nil when emptynil
- PHP: нет прямого аналога Set в стандартных массивах; очистка массива -
$arr = [];илиunset. Для SplObjectStorage есть методremoveAllи другие средства. - SQL: для удаления всех строк из таблицы используются
DELETE FROM tableилиTRUNCATE TABLE; отличие - операции на уровне БД, не памяти приложения.
Отличия от Java: в большинстве языков метод очистки доступен и семантически схож; различия касаются возврата значения, потокобезопасности и того, является ли структура изменяемой по умолчанию. В Go и Lua очистка чаще осуществляется переназначением контейнера, поскольку структуры реализации отличаются.
Типичные ошибки при использовании
- UnsupportedOperationException: попытка вызвать
clear()у неизменяемого множества. Пример:Sets = Collections.unmodifiableSet(new HashSet<>(List.of("a"))); s.clear(); Exception in thread "main" java.lang.UnsupportedOperationException at java.base/java.util.Collections$UnmodifiableCollection.clear(Collections.java:XXXX) ... - ConcurrentModificationException: модификация коллекции во время итерации стандартными итераторами. Пример:
Sets = new HashSet<>(Arrays.asList(1,2,3)); for (Integer i : s) { s.clear(); } Exception in thread "main" java.util.ConcurrentModificationException at ... - Неправильное ожидание о ссылках: присвоение новой коллекции переменной (например,
set = new HashSet<>()) не очистит другие ссылки на прежний объект. В таких случаяхclear()корректно очищает сам объект и все ссылки на него увидят изменения. - Проблемы многопоточности: вызов
clear()без внешней синхронизации на несинхронизированных реализациях может привести к неконсистентному состоянию в параллельном окружении. Для общегоHashSetтребуется внешняя синхронизация или использование Concurrent-реализаций.
Изменения и совместимость
Метод clear() присутствует в интерфейсе Collection с ранних версий Java (начиная с версии коллекций, Java 1.2). За последние релизы языка сама сигнатура и базовая семантика не менялись. Новые релизы добавляли неизменяемые фабрики коллекций (Set.of(...) в Java 9), которые делают вызов clear() неприемлемым и приводят к UnsupportedOperationException. Также появились удобные методы для пакетной модификации, например removeIf, предоставляющие альтернативы частичным очисткам.
Расширенные и малоизвестные сценарии
1) Очистка диапазона в TreeSet через view (subSet):
import java.util.*;
class Adv1 {
public static void main(String[] args) {
TreeSet t = new TreeSet<>(Arrays.asList(1,2,3,4,5));
t.subSet(2, 5).clear(); // удалит 2,3,4
System.out.println(t);
}
}
[1, 5]
Пояснение: subSet возвращает представление части множества. Очистка представления удаляет соответствующие элементы во всём наборе.
2) Удаление по условию, эквивалентное частичной очистке:
import java.util.*;
class Adv2 {
public static void main(String[] args) {
Set s = new HashSet<>(Arrays.asList("apple","banana","cherry"));
s.removeIf(str -> str.startsWith("b"));
System.out.println(s);
}
}
[apple, cherry]
Пояснение: вместо полного clear() применяется фильтрация с помощью предиката.
3) Очистка карты через ключи с условием:
import java.util.*;
class Adv3 {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("a",1); map.put("b",2); map.put("c",3);
// удалить все записи, где значение меньше 3
map.keySet().removeIf(k -> map.get(k) < 3);
System.out.println(map);
}
}
{c=3}
Пояснение: применение removeIf к keySet() позволяет удалять записи карты по условию без явного перебора entrySet().
4) Корректная очистка при итерации: использование итератора для безопасного удаления по одному элементу:
import java.util.*;
class Adv4 {
public static void main(String[] args) {
Set s = new HashSet<>(Arrays.asList(1,2,3,4));
Iterator it = s.iterator();
while (it.hasNext()) {
Integer v = it.next();
if (v % 2 == 0) {
it.remove(); // безопасно
}
}
System.out.println(s);
}
}
[1, 3]
5) Переиспользование экземпляра и управление памятью: при очень больших множествах вызов clear() удаляет элементы, но внутренние структуры (например, массив бакетов в HashSet) могут остаться прежнего размера. Для снижения занимаемой памяти предпочтительнее создать новый объект, если требуется уменьшить внутреннюю ёмкость.
6) Поведение в многопоточном окружении: у ConcurrentSkipListSet и у наборов, созданных через ConcurrentHashMap.newKeySet(), вызов clear() работает для параллельного использования, но не обеспечивает глобальной атомарности для внешних операций. В сценариях, где требуется полная атомарность видимости, может потребоваться внешняя синхронизация или блокировка вышеуровневой логики.
7) Очистка и мониторинг: при реализации кэшей или структур с наблюдателями (listeners) важно учитывать, вызываются ли подписчики при массовых операциях clear() - у некоторых обёрток и реализаций коллбэки могут быть вызваны для каждого удаления.