В процессе разработки часто возникает задача проверить, содержит ли коллекция данных какие-либо элементы перед выполнением дальнейших действий. В данном случае разберем, как наиболее грамотно и эффективно проверить на пустоту один из самых полезных объектов в 1С — Соответствие. Рассмотрим стандартный метод, его преимущества в производительности и проанализируем, почему у разработчиков, перешедших с платформы 7.7, могут возникать сомнения.
Основной и самый правильный способ проверить, пустое ли соответствие — это использовать его встроенный метод Количество(). Этот метод возвращает число элементов (пар "Ключ-Значение"), содержащихся в коллекции. Сравнив это число с нулем, мы однозначно определяем, есть ли в соответствии данные.
Давайте посмотрим на простой пример. Допустим, у нас есть соответствие, в котором хранятся активные рабочие сессии пользователей (рабочие столы), и нам нужно перед закрытием программы убедиться, что все сессии завершены.
// Предположим, это наше соответствие с рабочими столами
АктивныеСтолы = Новый Соответствие;
// ... в процессе работы программы оно как-то заполняется ...
// АктивныеСтолы.Вставить(Пользователь1, ДанныеСтола1);
// Проверка перед закрытием программы
Если АктивныеСтолы.Количество() = 0 Тогда
Сообщить("Все рабочие столы закрыты. Программу можно закрывать.");
// Здесь может быть код для закрытия программы
Иначе
Сообщить("Обнаружены незакрытые рабочие столы! Количество: " + АктивныеСтолы.Количество());
// Здесь может быть код, прерывающий закрытие и выводящий предупреждение
КонецЕсли;
Этот подход является идеальным по нескольким причинам:
Если МоеСоответствие.Количество() > 0 недвусмысленно говорит о намерении программиста — "если в соответствии есть хотя бы один элемент".Иногда может возникнуть предположение, что для очень больших коллекций (например, с миллионами элементов) вызов метода Количество() может быть ресурсоемкой операцией, и что быстрее было бы запустить цикл и прервать его на первом же элементе. Для платформы 1С:Предприятие 8 это утверждение неверно.
Давайте разберемся, как это работает "под капотом":
Метод Количество() не перебирает все элементы, чтобы их посчитать. Любая коллекция в 1С, будь то Соответствие, Массив или ТаблицаЗначений, хранит текущее число своих элементов в специальном внутреннем поле (счетчике). Когда вы вызываете МоеСоответствие.Количество(), платформа просто возвращает значение из этого поля. Это операция с так называемой сложностью O(1), то есть ее скорость не зависит от размера коллекции. Она будет практически мгновенной как для пустого соответствия, так и для соответствия с миллионом элементов.
А вот организация цикла, даже с немедленным выходом, — более сложный процесс:
// Неэффективный способ проверки на пустоту
СоответствиеНеПустое = Ложь;
Для Каждого Элемент Из ОгромноеСоответствие Цикл
СоответствиеНеПустое = Истина;
Прервать; // Выходим на первом же элементе
КонецЦикла;
Если СоответствиеНеПустое Тогда
// ...
КонецЕсли;
Что здесь происходит с точки зрения системы:
Прервать).Все это требует больше системных ресурсов, чем простое чтение одного числового поля. Поэтому вывод однозначен: всегда используйте Количество() для проверки коллекции на пустоту.
В обсуждении на форуме была упомянута "боязнь этих объектов" после работы с 1С 7.7. Это очень характерное ощущение для многих разработчиков того времени, и оно имеет под собой веские основания.
В платформе 1С 7.7 не было прямого и настолько гибкого аналога объекта Соответствие, где в качестве ключа мог выступать любой тип данных (например, ссылка на документ или элемент справочника). Задачи, которые сегодня элегантно решаются с помощью Соответствие, тогда требовали "обходных путей":
Найти(). Это было значительно медленнее, чем доступ по ключу в Соответствие.АссоциативныйМассив. Однако, как верно подмечено в теме, он имел ограничение: ключом могла быть только строка. Это не позволяло, например, напрямую сопоставить ссылку на номенклатуру со ссылкой на контрагента.Поэтому переход на платформу 8.х с ее богатой и унифицированной объектной моделью требовал привыкания и изучения новых подходов, что и вызывало начальные трудности.
Следует четко различать два понятия:
Количество() = 0.В 1С существует несколько видов "пустых" значений:
Неопределено — специальное значение для неинициализированных переменных.NULL — результат запроса к БД, когда в поле нет значения.Справочники.Номенклатура.ПустаяСсылка).Если ваша задача — не просто проверить наличие элементов, а убедиться, что среди них нет "пустых" значений, то здесь уже не обойтись без цикла.
Посмотрим на пример, где нужно обработать только те элементы соответствия, у которых значение является заполненной ссылкой на контрагента.
// Соответствие может содержать разные значения
МоиДанные = Новый Соответствие;
МоиДанные.Вставить("Заказ1", Справочники.Контрагенты.НайтиПоКоду("001"));
МоиДанные.Вставить("Заказ2", Неопределено); // Значение не было установлено
МоиДанные.Вставить("Заказ3", Справочники.Контрагенты.ПустаяСсылка()); // Значение - пустая ссылка
Если МоиДанные.Количество() > 0 Тогда
Сообщить("В соответствии есть данные, начинаем обработку...");
Для Каждого КлючЗначение Из МоиДанные Цикл
ТекущийКонтрагент = КлючЗначение.Значение;
// Проверяем, что значение - это ссылка на контрагента и она не пустая
Если ТипЗнч(ТекущийКонтрагент) = Тип("СправочникСсылка.Контрагенты") И НЕ ТекущийКонтрагент.Пустая() Тогда
Сообщить("Обрабатываем заказ '" + КлючЗначение.Ключ + "' для контрагента: " + ТекущийКонтрагент);
// ... здесь основная логика работы ...
Иначе
Сообщить("Пропускаем заказ '" + КлючЗначение.Ключ + "', так как контрагент не указан или указан некорректно.");
КонецЕсли;
КонецЦикла;
Иначе
Сообщить("Нет данных для обработки.");
КонецЕсли;
Таким образом, проверка на пустоту с помощью Количество() и проверка содержимого на "пустоту" — это две разные логические задачи, и для каждой из них есть свой правильный инструмент.