Кто-то нарушает мою сортировку списка - теперь какой подход выбрать: вернуть немодифицируемый список или новый список вообще?
Я использую списки на веб-сервере jsf, например, для доступа к модели данных с веб-страниц. Доступ к этим спискам также осуществляется из других мест (веб-сервисы, инструменты).
Есть фрагмент кода, который нарушается кем-то, прибегающим к списку, который я возвращаю. С кем-то я говорю о ком-то из моей команды разработчиков - мы единственные, кто использует этот код. У меня есть около 300 ссылок на эту функцию, и это может быть связано с производительностью, чтобы сделать исправление красиво:
Список может быть где-то от 1 до 10000 записей, и обычно у меня может быть 10-100 таких списков. В действительности у меня, вероятно, будет очень часто около 20 списков, в каждом из которых будет по 8 записей, так что это не такая уж большая проблема. Но я могу иметь больше иногда
Я, кстати, говорю о функции что-то вроде этого:
public List<MyObject> getMyObjectList() {
if (this.myObjects== null) {
myObjects = new ArrayList<MyObject>(myObjectsMap.values());
}
return myObjects;
}
Теперь я могу, конечно, сделать возврат так:
public List<MyObject> getMyObjectList() {
if (this.myObjects== null) {
myObjects = new ArrayList<MyObject>(myObjectsMap.values());
}
return Collections.unmodifiableList(myObjects );
}
Но это сломается, в конце концов, в нескольких местах в разных проектах / приложениях. Имхо было бы самым чистым вернуть немодифицируемое, добавить javadoc - и исправить все, что сломалось. Но:-D это работа. Вероятно, мне придется протестировать примерно 10 приложений.
С другой стороны, я мог бы просто вернуть новый список, например
public List<MyObject> getMyObjectList() {
return new ArrayList<MyObject>(myObjectsMap.values());
}
Что не мало для работы - но как насчет проблем с производительностью с этим? Кроме этого - если кто-то удаляет материал из списка, который я вернул, он молча сломает приложение.
Итак: в чем проблема производительности? Это проблема?
Чтобы ты делал?
2 ответа
Чтобы ты делал?
Если я вас правильно понимаю, это производственная библиотека, используемая в нескольких приложениях. И, как ни крути, де-факто контракт на getMyObjectList()
является то, что пользователь может сортировать список без получения ошибки или исключения.
Я немедленно изменил бы этот метод и возвратил бы защитную копию:
// good idea
public List<MyObject> getMyObjectList() {
return new ArrayList<MyObject>(myObjectsMap.values());
}
Теперь вы устранили проблему, когда кто-то сортирует вашу внутреннюю коллекцию, а вы не нарушили свой контракт. На самом деле вы даже можете обновить Javadoc и сказать пользователю, что он может делать с копией все, что хочет.
Это может или не может вызвать проблемы с производительностью. Помните, что объекты в коллекции не копируются - они все еще используются совместно. Вы просто создаете новый список массивов и любые внутренние объекты, необходимые для отслеживания объектов.
Если окажется, что эти копии вызывают проблемы с производительностью, вы можете рассмотреть возможность расширения вашего класса для включения кэша только для чтения вашей внутренней коллекции. Чтобы получить доступ к этому, вы должны дать методу новое имя - ex getMySharedObjectList
и вы можете постепенно обновлять клиентский код, чтобы использовать этот новый метод, как того требует производительность.
Но не делай так. Я думаю, что этот метод особенно плох:
// bad idea
public List<MyObject> getMyObjectList() {
if (this.myObjects== null) {
myObjects = new ArrayList<MyObject>(myObjectsMap.values());
}
return Collections.unmodifiableList(myObjects );
}
Вы создали ситуацию, когда myObjects очень легко не синхронизироваться с myObjectsMap. (Что происходит, когда элемент добавляется в myObjectsMap после того, как кто-то вызвал getMyObjectList?) В то же время вы создаете копию списка каждый раз, когда кто-то вызывает метод. Таким образом, вы просто отказались от теоретического прироста производительности, который у вас был.
В любом случае, удачи. Надеюсь это поможет.
Если вы можете позволить себе тестировать приложения, я бы пошел с unmodifiableList. Это избавит вас от других связанных с этим вопросов в будущем.