Зачем вам использовать MyObject [] для внутреннего использования, но выставить список <MyObject>? - PullRequest
4 голосов
/ 08 апреля 2010

Я столкнулся с классом, который имеет неизменное свойство:

MyObject[] allObjs

Свойство инициализируется так:

List<MyObject> objs = createAllMyObjects();
allObjs = objs.toArray(new MyObject[objs.size()]);

Когда он выставляется через средство доступа, это делается в виде списка:

public List<MyObject> getAllMyObjects() {
    return Collections.unmodifiableList(Arrays.asList(allObjs));
}

Зачем программисту это делать? Есть ли польза, о которой я не знаю?

Производительность не имеет значения, так как массив objs будет когда-либо перечисляться только в нескольких десятках элементов.

Кажется, что мы кружимся по кругу.

Класс является своего рода фабрикой, поэтому он имеет закрытый конструктор и предоставляет только статические методы (не уверен, может ли это быть причиной безумия).

редактировать

Я предполагаю, что мой вопрос действительно таков: "Почему бы просто не использовать внутренний List<MyObject> allObjs вместо MyObject[] allObjs и вернуть Collections.unmodifiableList (allObjs)?" как это сделало бы то же самое.

Ответы [ 9 ]

6 голосов
/ 08 апреля 2010

Единственная причина, которую я вижу, - это «неудача на раннем этапе в случае неправильного использования» (если этот выбор дизайна не был случайным и имел значение, то это означает, что он очень мало доверяет своим конкретным клиентам).

MyObject[] - это reified , и проверяется во время выполнения , а List<MyObject> - нет. В последнем можно скрыть ссылки не-MyObject (он, конечно, получит непроверенные предупреждения при компиляции), которые потерпят неудачу в какой-то неопределенной точке будущего с ClassCastException, но он не может сделать то же самое с MyObject[] - это приведет к сразу же в случае неправильного использования.

Обратите внимание, что если клиенты представляют собой предварительно собранные двоичные файлы, которые использовали этот API до того, как он был сгенерирован, то никто не получал непроверенные предупреждения, поэтому, если этот код пытается выполнить миграцию кода, используемого клиентами перед обобщением, это имеет смысл.

(Другим способом достижения того же результата будет использование List<T>, а также требование Class<T>, чтобы последний мог предлагать проверки типов во время выполнения. Но для этого потребуется, например, другой параметр конструктора - существующие клиенты не будут автоматически воспользуйтесь этим. ** Обновление: ** Это в основном описывает вызов API, упомянутый в первом комментарии Sauer, поэтому не нужно изобретать это заново, просто используйте его :)).

2 голосов
/ 08 апреля 2010

Для этого может быть несколько причин:

  • Они не знали, что делают.Сейчас я работаю в коде, который, кажется, был написан кем-то новым для Java и новичком в программировании.К сожалению, слишком часто можно встретить плохо спроектированный код, чем найти хороший, чистый, ухоженный код, написанный кем-то с глубоким пониманием платформы.Отчасти это связано со следующим пунктом.
  • Изменения List были исправлены без необходимости внесения оптовых изменений.Если в остальной части кода используется массив, возможно, кто-то не захотел бы вносить все остальные изменения.
  • В то время как коллекции являются более подходящим способом OO / Java, если список статичен,с массивом на самом деле «проще» работать, так как они все еще могут повторяться с for(:), как Collection, но доступ к ним осуществляется с помощью [] вместо get().Лично это не достаточно веская причина для использования массивов, но, возможно, это только я.
  • Может быть, они хотели, чтобы было ясно, что длина данных равна final .Если бы они только что использовали немодифицируемый список, то List все равно был бы средством для ссылки на данные, и любой, кто не обращал бы внимания на остальную часть (надеюсь, прокомментированного) кода, мог бы попытаться добавить к List, что привело бы кво время выполнения UnsupportedOperationException.Создание массива делает его использование понятным.
1 голос
/ 09 апреля 2010

Позвольте мне ответить шуткой:

Новая еврейская невеста готовит свой первый большой ужин для своего мужа и пробует руку на рецепте грудинки своей матери, отсекая концы с жареным способомее мать всегда так делала.Хабби думает, что мясо вкусное, но говорит: «Почему ты отрезаешь концы - это лучшая часть!» Она отвечает: «Так всегда делала моя мама.

На следующей неделе они идут вдом старой бабби, и она готовит знаменитый рецепт грудинки, снова обрезая концы.Молодая невеста уверена, что ей не хватает какой-то важной информации, поэтому она спрашивает бабушку, почему она обрезала концы.Бабушка говорит: «Далинк, это единственный способ, которым она уместится на сковороде!»

Хотя мы, безусловно, можем найти некоторые аргументы для обоснования конкретного решения, на практике это редко имеет какое-либо значение, и частонет намерений, стоящих за такими решениями.

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

1 голос
/ 08 апреля 2010

Есть веская причина не возвращать ссылку на внутренний атрибут MyObject[].Посредством ссылки вызывающий может внести изменения в массив.

Если нет причины, по которой результат должен быть List, вы также можете вернуть копию массива:

public MyObject[] getAllMyObjects() {
    MyObject[] result = new MyObject[allObjs.length];
    system.ArrayCopy(allObjs, 0, result, 0, result.length);
    return result;
}

Обновление , после добавления к вопросу: вы правы, если внутренний атрибут изменен на Список, его проще не изменять.

Причина, по которойкласс использует массив вместо списка может быть производительность.Если массив не изменяется (сильно) в течение жизни объекта и многократно повторяется, массив имеет меньше накладных расходов, чем List.

Если производительность является причиной использования массива, вы можете предотвратитьсоздание дополнительного объекта в получателе, сохраняя список с единственной целью его возврата, то есть:

allObjsList = Collections.unmodifiableList(createAllMyObjects());
allObjs = allObjsList.toArray(new MyObject[allObjsList.size()]);

используйте массив allObjs, как и раньше, и возвращайте сохраненный список в получателе:

public List<MyObject> getAllMyObjects() {
    return allObjsList ;
}
1 голос
/ 08 апреля 2010

Кажется, что автор намеревался вернуть неизменную копию и сделал это излишне.Я предполагаю, что List был выбран в качестве возвращаемого типа, чтобы можно было легко создать клон с типом MyObject.

0 голосов
/ 08 апреля 2010

В книге Java Generics автор фактически говорит, что, поскольку у нас есть Generics, мы должны использовать исключительно коллекцию и больше не должны использовать массив. Лично я теперь стараюсь держаться подальше от массивов, потому что коллекции помогают мне вспомнить мое намерение использовать коллекцию вещей, например. устанавливает vs list вместо массива, который ничего не говорит мне о данных.

Также нет ничего такого, что я не могу сделать с коллекциями, что я не могу сделать с массивом, за исключением, возможно, быстрого копирования (System.arraycopy ())

0 голосов
/ 08 апреля 2010

Таким образом, коллекция не может быть изменена, т. Е. Вызывающая сторона не может изменить массив-член.Это невозможно сделать с помощью массива, поэтому кодер копирует его в список.

0 голосов
/ 08 апреля 2010

Я думаю, что причиной этого может быть то, что массив не может быть изменен. Однако вы можете сохранить внутренний список в виде списка и просто вернуть его копию в получателе, чтобы внутренний список по-прежнему нельзя было изменять извне.

Или используйте «неизменяемый» список, возвращаемый Collections.unmodifiableList () ...

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

0 голосов
/ 08 апреля 2010

Я не вижу никаких преимуществ в использовании массивов вместо списков.Списки гораздо удобнее.Может, парню просто нравится работать с массивами:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...