Статический доступ к HashMap/массиву?

Вот пример статического метода, который используется в веб-приложении. Как видите, String[] allergensArr создается каждый раз, когда вызывается этот метод. Он потокобезопасен, так как находится в статическом методе, но это дорогостоящий вызов.

Каковы другие способы использования allergensArr[] , чтобы он не создавался каждый раз при вызове метода.

Я рассматривал следующие варианты.

  • Иметь статический конструктор, который инициализирует статическую конечную строку []
  • Используйте синглтон (хотя это заблокирует многих людей)

Это будет постоянный массив, который не изменится в течение времени существования экземпляра сервера.

public class UserHealthConcernsManager {
    public static String[] getAllergensFlag () {

        String[] allergensArr = new String[12];

        allergensArr[0] = "x";
        allergensArr[1] = "y";
        allergensArr[2] = "w";
                 _SNIP_
                return allergensArr;
     }
}

person Shaun F    schedule 22.10.2009    source источник
comment
Вы профилировали приложение во время выполнения и обнаружили, что вызов для создания массива был проблемой производительности? Может и не стоит заморачиваться с оптимизацией...   -  person serg10    schedule 22.10.2009
comment
Что заставляет вас думать, что создание массива и 12 строк — это дорого? (Ребята, это 2009 год! Стоимость создания объекта почти равна нулю!)   -  person Bombe    schedule 22.10.2009
comment
Мне нравится, как 'UserHealthConcernsManager.getAllergensFlag() == UserHealthConvernsManager.getAllergensFlag()' оценивается как false;)   -  person Juliet    schedule 22.10.2009
comment
Бомбе прав, и на самом деле вы каждый раз создаете не строки, а только массив.   -  person Keith Randall    schedule 22.10.2009
comment
Я думаю, что меня это беспокоит, потому что вариант этого метода вызывается много раз снова и снова. Для меня очевидно, что есть более эффективные способы справиться с этим, чем каждый раз воссоздавать объект/массив.   -  person Shaun F    schedule 23.10.2009


Ответы (5)


Рассматривали ли вы возможность использования Lists вместо массивов ссылок?

Код можно сократить до:

public static final List<String> allergensFlag =
    Collections.unmodifiableList(Arrays.asList(
        "x",
        "y",
        "w",
        ...
    ));

Если вам очень-очень нужны старомодные массивы, тогда стоимость клонирования будет мизерной.

private static final String[] allergensFlag = {
    "x",
    "y",
    "w",
    ...
};

public static String[] getAllergensFlag () {
    return allergensFlag.clone();
}
person Tom Hawtin - tackline    schedule 22.10.2009
comment
Это похоже на подход, который я хочу. - person Shaun F; 23.10.2009

  1. Статический не означает потокобезопасный. Если «пользователь» (HashMapSupport) используется несколькими потоками...
  2. Выглядит не очень дорого.
  3. Вы можете хранить такого рода информацию в объекте Session, если вам это действительно необходимо.
  4. Если вам нужно гарантировать, что массив строк не может быть изменен, вам нужно обернуть массив строк в какой-либо другой объект, чтобы гарантировать, что сохраненный объект неизменен (например, только методы получения).

Редактировать: Ярг. Как отмечали другие, вы значительно изменили проблему. Если вы хотите гарантировать неизменность массива, см. пункт № 4.

person hythlodayr    schedule 22.10.2009

Статический конструктор кажется очевидным решением.

static String[] allergensArr = {"x", "y", "w", ...9 more...}

Вам нужно убедиться, что никто не переназначает статическое поле или не изменяет массив в течение всего времени существования вашего приложения.

Обновление: если вы действительно заботитесь о том, чтобы клиенты не вмешивались в него, вы можете сделать:

final static List<String> x = Collections.unmodifiableList(Arrays.asList("x", "y", "z", ...));
person Keith Randall    schedule 22.10.2009
comment
Обратите внимание, что статический метод, который возвращает ссылку на массив таким образом, открывает его для других классов/потоков для изменения содержимого этого массива. - person matt b; 22.10.2009
comment
@james, Кит имел в виду, убедитесь, что клиенты не изменяют значения в массиве, добавление ключевого слова final не помешает клиентам выполнять код, например getAllergensFlag()[0] = "haha"; - person rsp; 22.10.2009

Иногда определенная область проблемы может быть слишком узкой, чтобы придумать хорошую оптимизацию.

Если ваша проблема заключается в том, что вам НЕОБХОДИМО переместить эти элементы из переданной хеш-карты в массив, это не станет слишком эффективным (хотя вы, вероятно, захотите начать с такого массива: new String[] {"ADDED_SUGARS_FREE_FLAG ", "EGG_FREE_FLAG", ...} и переберите его, чтобы у вас не было всех этих повторяющихся строк.

Таким образом, чтобы получить лучшую оптимизацию, вам, возможно, придется уменьшить масштаб на один или два уровня. Почему вы храните их в массиве, нельзя ли просто скопировать хеш-карту пользователя частично или полностью? Можно ли сделать пользовательскую хэш-карту неизменной, чтобы вы могли просто сделать ее копию указателя и даже не беспокоиться об извлечении значения?

Или, что еще лучше, вы можете обернуть HashMapSupport более интеллектуальной коллекцией, которая решает проблемы всех использующих ее классов.

Я не могу ответить ни на один из них, не зная намного больше о вашем коде, но это то, на что я бы обратил внимание.

После вашего редактирования: вы уже немного изменили задачу. То, что у вас сейчас есть, эквивалентно:

return new String[]{"w", "x", "y", ...}

Вы уверены, что не упростили часть проблемы?

person Bill K    schedule 22.10.2009

Просто инициализируйте массив при запуске веб-приложения и поместите его в контекст сервлета. См. ServletContextListener и ServletContext.

person alphazero    schedule 22.10.2009