Ключ = Новый Структура("Поле1, Поле2", "123", "456");
Карта.Вставить(Ключ, 1);
Ключ2 = Новый Структура("Поле1, Поле2", "789", "987");
Карта.Вставить(Ключ2, 2);
Значение = Карта.Получить(Ключ2);
Вроде ничего сложного, да? Сделали два ключа, положили по ним значение в Пример утрированный, эти операции размазаны по коду, но смысл такой.
Так вот. Как думаете, что будет в переменной Значение? По идее двойка, да?
По идее да. Двойка. И так и было примерно в 99.9% случаев. А в 0.01% в Значении было... Неопределено.
НедоумевающийДжекиЧан.джпг
Что, почему, как? Херня эта ваша джава, да?
Как и в большинстве случаев в программировании проблема оказалась в программисте.
Интерфейсы часто помимо, собственно, сигнатуры метода, содержат еще некоторую договоренность или контракт, описанный в документации к интерфейсу. Например, в случае Comparable есть требование возвращать -1, 0 или 1 в качестве результата метода compareTo для значений "меньше", "равно" или "больше" в плане сравнения порядка/сортировки двух объектов. Или рекомендация возвращать 0, если объекты равны между собой по equals, что действительно звучит логично - равные объекты и упорядочиваться должны одинаково.
Но есть и еще одно требование - если А > Б, то обязательно должно выполняться Б < А. От перемены мест слагаемых и все такое прочее.
Т.к. метод сортировки применяется в ConcurrentSkipListMap для построения индекса, два объекта, которые при сравнении друг с другом с разных сторон давали разные ответы, приводили к ошибкам позиционирования в индексе. И вместо нахождения в индексе адреса нужного значения в дереве из двусвязных списков, индекс врезался в null.
Проблема решилась путем выкидывания наколеночной реализации compareTo и обычного сравнения по всем полям.
Можно было бы подумать, что это все жабо-проблемы, и в этом нашем 1С такого не может быть. Какие у нас интерфейсы, какие контракты?
А вот и нет. Есть у нас интерфейсы, и есть контракты. Не важно, какую библиотеку вы используете: Библиотеку стандартных подсистем с ее миллионом общих модулей и вязанкой "переопределяемых" методов, или, к примеру клевую библиотеку для сериализации SerLib1C от Артема Кузнецова (не реклама, честно, просто вспомнилось :) ) - автор может закладываться на какое-то ваше адекватное поведение в коде переопределяемых обработчиков. Хороший автор еще напишет об этом в документации.
Вот такое вам длиииииииинное субботнее чтиво.
Всем добра и RTFM!