2008-10-22 4 views
27

В духе Best Practices: Always return a ____, never a ____, я сталкиваюсь с похожим вопросом в своем предстоящем migration from JDK1.4.2 to JDK5 and more. (Да, I знаю, JDK1.4.2 is EOL! ;-)).API java 5 и более: следует ли возвращать массив или коллекцию?

Для функций, возвращающих коллекции (которые не являются простыми property collections), я всегда предпочитаю (в jdk1.4.2) возвращение массива вместо общего списка, потому что:

  • он навязывает возвращающегося типа (MyObject[] вместо списка объектов, гораздо более типобезопасного на статическом - как в «компиляции» - уровень)
  • это наводит на мысль а «только для чтения» символа возвращенной коллекции (это сложнее добавить элемент в коллекции, хотя это не так строго, как ключевое слово «только для чтения» в C#). Это не то же самое, как говорят, что это «неизменное», поскольку ссылки внутри массива по-прежнему могут быть изменены ...

Конечно, я всегда создать Возвращаемый массив (я не подвергать какой-либо " внутренняя ')

Теперь, в JDK5 и более, я мог бы использовать List<MyObject>, если захочу.

Каковы веские причины для выбора MyObject[] вместо списка или Collection<MyObject> при кодировании в java5?

Bonus, если Collection<MyObject> используется, это возможно:

  • применять для чтения атрибут только на возвращаемой коллекции? (нет add() или remove() возможно)
  • обеспечить неизменный аспект возвращенной коллекции? (даже ссылки этой коллекции не могут быть изменены)

PS: У JavaGenericFAQ не было этого.

ответ

34

Предпочитайте набор (или список или задайте в зависимости от ситуации) массив. С generics вы получаете проверку типов, которой не хватало pre-Java 5. Кроме того, выставляя только интерфейс, вы можете впоследствии изменить реализацию (например, переключить ArrayList для LinkedList).

Массивы и дженерики не очень хорошо смешиваются. Итак, если вы хотите воспользоваться дженериками, вы должны обычно избегать массивов.
I.e: Вы не можете создать массив в общем виде. Например, если T - общий тип, то «новый T [0]» не компилируется. Вам нужно будет сделать что-то вроде «(T []) нового объекта [0]», который генерирует предупреждение без предупреждения. По той же причине вы не можете использовать общие типы с varargs без предупреждений.

Используя Collections.unmodifiableCollection (и аналогичные методы), вы получаете ограничение только для чтения (чего вы не можете достичь с помощью массива - вам нужно будет вернуть клон массива).

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

+0

Спасибо! +1 на данный момент (я буду ждать немного для других ответов). Вы можете сказать, что я еще не всерьез прочитал JDK6 javadoc ...;) – VonC 2008-10-22 12:54:38

+0

«Массивы и дженерики не очень хорошо смешиваются. Поэтому, если вы хотите использовать дженерики, вы обычно должны избегать массивов». -> Urg? можете ли вы объяснить эту часть? Мои массивы хорошо сочетаются с моими дженериками ... – Nicolas 2008-10-22 15:05:46

+0

Вы не можете создать массив. Например, если T - общий тип, то «новый T [0]» не компилируется. Вам нужно будет сделать что-то вроде «(T []) нового объекта [0]», который генерирует предупреждение без предупреждения. По той же причине вы не можете использовать общие типы с varargs без предупреждений. – 2008-10-22 15:38:50

3

Ознакомьтесь с немодифицируемыми * методами в классе Collections, чтобы сделать возвращенные коллекции доступными только для чтения/неизменяемыми. Это обернет исходную коллекцию в список, который предотвратит доступ к самому изменению самого списка (сами элементы не являются неизменными).

unmodifiableList например.

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

Массив, вероятно, будет работать быстрее, если вы делаете что-то критическое.

2

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

Усовершенствователь проекта cglib.sourceforge.net, он позволяет создавать прокси для классов (JDK поддерживает только прокси для интерфейсов). Прокси позволяет управлять методами в объекте, однако вы не можете использовать поля доступа с помощью отражений. если у вас есть вопросы.

10

На самом деле массивы все еще имеют одно преимущество перед Коллекциями/списками. Из-за того, что Java реализует Generics посредством стирания типа, у вас не может быть двух методов, которые принимают Collections в качестве аргументов, но только отличаются общим типом коллекции.

Пример:

public void doSomething(Collection<String> strs) { ... } 
public void doSomething(Collection<Integer> ints) { ... } 

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

В приведенных выше случаях наилучшим обходным способом является то, чтобы методы принимали массивы в качестве их аргументов и использовали метод Collection/List toArray() при передаче им аргументов. Если вы все еще хотите использовать Collection/List внутри указанных выше методов, просто используйте метод java.util.Arrays.asList(), чтобы вернуть свой список.

Ex:

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()); 
}