API Java 5 и более: я должен вернуть массив или коллекцию? - PullRequest
31 голосов
/ 22 октября 2008

В духе Наилучшие практики: Всегда возвращайте ____, а не ____ , я сталкиваюсь с подобным вопросом в моей предстоящей миграции с JDK1.4.2 на JDK5 и более . (Да, я знаю , JDK1.4.2 - это EOL! ;-)).

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

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

Конечно, я всегда создаю этот возвращенный массив (я не предоставляю никакого 'внутреннего' массива)

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

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

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

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

PS: JavaGenericFAQ не совсем такой.

Ответы [ 4 ]

37 голосов
/ 22 октября 2008

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

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

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

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

11 голосов
/ 10 ноября 2008

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

Ex:

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

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

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

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());
}
4 голосов
/ 22 октября 2008

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

unmodifiableList например.

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

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

3 голосов
/ 23 октября 2008

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

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

...