#java
#java
Вопрос:
У меня есть Java-код, который содержит класс TRADE_HISTORY, который хранит историю сделок.
Класс TRADE_HISTORY имеет конечное поле с именем fMapDateOutputPriceRatios, которое задается в конструкторе . fMapDateOutputPriceRatios — это сопоставление дат и двойного массива (TreeMap). В конструкторе поле сравнивается с аргументом с помощью
fMapDateOutputPriceRatios = new TreeMap<Date, double[]>(aOutputPriceRatioData);
Количество дат получается с использованием
Set<Date> dates = fMapDateOutputPriceRatios.keySet();
Размер дат распечатывается в конструкторе. Класс имеет только один конструктор.
При добавлении новой сделки возникает проблема. При добавлении новой даты используется двойной вектор, полученный из
double[] outputPriceRatios = fMapDateOutputPriceRatios.get( aDate );
Ошибка возникает из-за того, что дата недоступна.
При попытке отладки ошибки печатается размер дат.
Во время построения размер составляет 1973 элемента.
При возникновении ошибки размер составляет 1964 элемента.
В частности, дата 11 апреля 2011 недоступна на момент возникновения ошибки.
Я использую eclipse и установил разрыв в переменной fMapDateOutputPriceRatios на разрыв при изменении поля. Она прерывается только во время конструктора.
Есть предложения о том, как определить, почему изменяется размер fMapDateOutputPriceRatios?
Единственными строками, которые обращаются к fMapDateOutputPriceRatios, являются
TRADE_HISTORY::TRADE_HISTORY(Map<Date, double[]> aOutputPriceRatioData )
fMapDateOutputPriceRatios = new TreeMap<Date, double[]>(aOutputPriceRatioData);
Set<Date> dates = fMapDateOutputPriceRatios.keySet(); // Used to debug error
TRADE_HISTORY::public void addTradeDistribution_0_to_100(Date aDate, ...)
outputPriceRatios = fMapDateOutputPriceRatios.get( aDate ) // Causes error
Set<Date> dates = fMapDateOutputPriceRatios.keySet(); // Used to debug error
Комментарии:
1. Было бы полезно видеть соответствующий код в одном связном блоке вместо неформатированного и перемежающегося описательным текстом.
2. Код довольно длинный, но я согласен, что дополнительная информация была бы полезной.
Ответ №1:
Окончательная ссылка на экземпляр объекта не делает этот экземпляр неизменяемым!Это только блокирует изменение ссылки, указывающей на другой экземпляр объекта. Ссылка является окончательной — не состоянием экземпляра объекта, на который она ссылается.
Обратите внимание, что набор ключей, возвращаемый keySet()
, поддерживается картой. Если вы удалите из нее ключи, соответствующие сопоставления будут удалены из fMapDateOutputPriceRatios
. Вы модифицируете dates
или используете ее для чего-либо другого, кроме отладки?
Комментарии:
1. Изменение
dates
набора тоже было моей первой мыслью. Судя по тому, как представлен код, я чувствую кого-то, кто обычно пишет C , а не Java.final
в Java ЭТО НЕ ТО ЖЕ самое, чтоconst
в C .2. В карте ключей изменений не было.
3. Передача
Map
в конструктор копирует сопоставления, поэтому оригинал не повлияет на него после построения. Единственными другими способами удаления элементов являютсяremove()
операции and над коллекциями, возвращаемымиkeySet()
,entrySet()
иvalues()
. Вы должны где-то это делать.
Ответ №2:
Во-первых, важный вопрос: вы уверены, что даты, используемые в качестве ключей, нигде не изменены? Предполагается, что Date является неизменяемым объектом, но он по-прежнему содержит устаревшие методы, позволяющие изменять содержимое ключа. Это привело бы к непредсказуемым последствиям для TreeMap, включая те, которые вы описали.
Кроме того, убедитесь, что все даты имеют часы / минуты / секунды / миллисекунды, очищенные до 0.
Теперь предположим, что даты неизменяемы:
Вы действительно наблюдали уменьшение размера набора ключей, что означает, что происходит физическая модификация содержимого. Единственный известный мне способ, как это может произойти, — это одновременный доступ к карте двумя или более потоками.
TreeMap приходится перестраивать дерево при добавлении нового ключа. То есть отсоедините часть дерева и повторно свяжите его где-нибудь в другом месте дерева. В течение этого времени, если другой поток обращается к той же структуре и делает то же самое, это поддерево может быть потеряно, что приведет к уменьшению количества ключей.
Поэтому в качестве первого шага попробуйте получить доступ к этому полю в синхронизированном блоке:
synchronized(fMapDateOutputPriceRatios) {
outputPriceRatios = fMapDateOutputPriceRatios.get( aDate )
}
P.S. На самом деле я нигде не вижу put() в вашем коде, но он должен быть там, чудес не бывает.
Комментарии:
1. Операционная система передает существующий файл
Map
вTreeMap
конструктор.put()
нет необходимости заполнять карту.2. В какой-то момент я планирую использовать несколько потоков, но сейчас должен быть запущен один поток. Вот код из более высокого класса.
code
логическое значение useThreads = false; логическое значение useThreadService = true; if (useThreads) { Runnable worker = новый fooWorker(текущая конфигурация, fPortfolio, fFileDirectory); if (useThreadService) { executor.execute(рабочий); } else { worker.run(); } } else { fooWorker worker = новый fooWorker (текущая конфигурация, fPortfolio, fFileDirectory); worker.run(); }code
3. В классе driver конструктору передаются соотношения даты и цены для ввода и вывода и устанавливается общая дата, если она создана. В функции обработки класса driver создается экземпляр TRADE_HISTORY и передается карта выходных данных / цен. Затем в функции обработки выполняется цикл по общим датам и создается новая сделка.
4. В подпрограмме драйвера выполняется цикл по датам, которые являются общими для входных и выходных карт даты / цены. В момент возникновения ошибки в TRADE_HISTORY добавляется дата, и эта дата не существует в поле отображения даты / цены в TRADE_HISTORY. Поле map было инициализировано во время построения TRADE_HISTORY. Однако дата должна быть там, и дата действительно существует на карте, которая присутствует в классе драйвера, поэтому код был изменен, чтобы удалить карту даты / цены из класса TRADE_HISTORY и использовать карту, которая есть в коде драйвера, программа запускается.
5. Если я изменю код обратно, на отображение даты / цены в TRADE_HISTORY, и помещу доступ к карте в синхронизированный блок, как предложено, тогда программа завершится, но ошибки или сообщения не будет, только два оператора null. В этом случае я не знаю, как определить причину. Я запускаю debug в eclipse, и обычно это останавливается на причине ошибки во время выполнения.
Ответ №3:
Спасибо за отзыв.
Перемещение карты даты / выходных цен в управляющую функцию устраняет возможность проблемы с картами даты / выходных цен. Тем не менее, по-прежнему возникают непредвиденные ошибки.
В конструктор TRADE_HISTORY был добавлен статический счетчик для отслеживания количества созданных TRADE_HISTORY. Кроме того, в конструктор был добавлен целочисленный идентификатор, равный счетчику, поэтому идентификаторы должны быть 1, 2, 3….
При возникновении текущей ошибки идентификатор TRADE_HISTORY печатается и равен нулю, чего не должно происходить. Требуется дополнительная отладка в конструкторе экземпляров TRADE_HISTORY. Похоже, что используется TRADE_HISTORY, которая не была сконструирована должным образом.
Если потребуется дополнительная помощь, будет запущен другой вопрос.