API java 5 и более: следует ли возвращать массив или коллекцию?
В духе Лучшие практики: всегда возвращайте ____, никогда не ____, я сталкиваюсь с аналогичным вопросом в своем предстоящем переход от JDK1.4.2 к JDK5 и более. (Да, я знаю, JDK1.4.2 - EOL!;-)).
Для функций, возвращающих коллекцию (которые не просто коллекции свойств), я всегда предпочитаю (в JDK1.4.2) возвращать Array вместо общего списка, потому что
- он применяет возвращаемый тип (
MyObject[]
вместо List of Objects, гораздо более тип-безопасный) на статическом уровне, как на уровне 'compilation')
- он предлагает символ "только для чтения" возвращенной коллекции (сложнее добавить элемент в коллекцию, хотя это не так строго, как ключевое слово "только для чтения" в С#). Это не то же самое, что сказать, что это "неизменный", поскольку ссылки внутри массива все еще могут быть изменены...
Конечно, я всегда создаю этот возвращенный массив (я не выставляю никакого "внутреннего" массива)
Теперь, в JDK5 и более, я мог бы использовать List<MyObject>
, если захочу.
Каковы веские причины для возврата MyObject[]
вместо List или Collection<MyObject>
при кодировании в java5?
Бонус, если используется Collection<MyObject>
, возможно ли:
- применять атрибут "только для чтения" для возвращаемой коллекции? (нет
add()
или remove()
)
- обеспечить неизменный аспект возвращенной коллекции? (даже ссылки этой коллекции не могут быть изменены)
PS: JavaGenericFAQ не имел этого.
Ответы
Ответ 1
Предпочитайте сборку (или список или установите соответственно) массиву. С generics вы получаете проверку типов, которой не хватало pre-Java 5. Кроме того, выставляя только интерфейс, вы можете позже изменить реализацию (например, переключить ArrayList для LinkedList).
Массивы и дженерики не очень хорошо смешиваются. Итак, если вы хотите воспользоваться дженериками, вы обычно должны избегать массивов.
I.e: Вы не можете создать массив. Например, если T - общий тип, то "новый T [0]" не компилируется. Вам нужно будет сделать что-то вроде "(T []) нового объекта [0]", который генерирует предупреждение без предупреждения. По той же причине вы не можете использовать общие типы с varargs без предупреждений.
Используя Collections.unmodifiableCollection (и аналогичные методы), вы получаете ограничение только для чтения (чего вы не можете достичь с помощью массива - вам нужно будет вернуть клон массива).
Вы не можете обеспечить неизменность членов, но тогда вы не можете сделать это с массивом.
Ответ 2
На самом деле массивы все еще имеют одно преимущество перед Коллекциями/списками. Из-за того, что Java реализует Generics посредством стирания типа, у вас не может быть двух методов, которые принимают Collections в качестве аргументов, но отличаются только общим типом Collection.
Пример:
public void doSomething(Collection<String> strs) { ... }
public void doSomething(Collection<Integer> ints) { ... }
Два вышеуказанных метода не будут компилироваться, потому что компилятор javac использует стирание типа и, следовательно, не может передавать информацию типа в JVM. JVM будет видеть только два метода, которые принимают коллекцию в качестве аргумента.
В вышеприведенных случаях наилучшим решением является то, чтобы методы принимали массивы в качестве их аргументов и использовали метод Collection/List toArray() при передаче им аргументов. Если вы все еще хотите использовать Collection/List внутри указанных выше методов, просто используйте метод java.util.Arrays.asList(), чтобы вернуть свой список.
Пример:
public void doSomething(String[] strs) {
List<String> strList = Arrays.asList(strs);
...
}
public void doSomething(Integer[] ints) {
List<Integer> intList = Arrays.asList(ints);
...
}
public static void main(String[] args) {
List<String> strs = new ArrayList<String>();
List<Integer> ints = new ArrayList<Integer>();
obj.doSomething(strs.toArray());
obj.doSomething(ints.toArray());
}
Ответ 3
Ознакомьтесь с немодифицируемыми * методами в классе Collections
, чтобы сделать возвращенные коллекции доступными только для чтения/неизменяемыми. Это обернет исходную коллекцию в список, который запрещает доступ к изменению самого списка (сами элементы не являются неизменяемыми).
unmodifiableList, например.
Для меня это зависит от того, как будет использоваться возвращенный список. Какие другие методы передаются и как они будут использоваться? В общем, я бы предпочел общую коллекцию над массивом, но изменил бы ее в каждом конкретном случае.
Массив, вероятно, будет работать быстрее, если вы делаете что-то критическое.
Ответ 4
Мой ответ был приостановлен, потому что я использую прокси для класса и использую такие вещи (прокси и отражение), потому что это влияет на производительность некоторых людей (многие люди даже не используют рефлексию, однако они используют спящий режим и spring которые используют relfection, прокси класса и xml).
Enhancer из проекта cglib.sourceforge.net, он позволяет создавать прокси для классов (JDK поддерживает только прокси для интерфейсов). Прокси позволяет управлять методами в объекте, однако вы не можете использовать поля доступа с помощью отражений. если у вас есть вопросы, задайте вопросы.