2017-01-29 19 views
18

Java 9 поставляется с convenience factory methods для создания неизменяемых списков. Наконец, создание списка так же просто, как:Что такое перегруженный метод удобства для коллекций в Java 9

List<String> list = List.of("foo", "bar"); 

Но есть 12 перегруженные версии этого метода, 11 с 0 до 10 элементов, и один с вар арг.

static <E> List<E> of(E... elements) 

То же самое и в случае с Set и Map.

Поскольку существует метод var args, в чем смысл дополнительных 11 методов?

Я думаю, что var-args создает массив, поэтому другие 11 методов могут пропустить создание дополнительного объекта, и в большинстве случаев будут выполняться 0 - 10 элементов. Есть ли другая причина для этого?

+8

Вы только что ответили на свой собственный вопрос - перегрузка его аргументами 0-10 пропускает ненужные создания массивов. – luk2302

+0

@ luk2302: Да, это я выяснил, но я хотел знать, есть ли другая причина. Наверное, нет. – ares

+0

Хорошо, тогда ответ «нет». – luk2302

ответ

23

С самого JEP docs -

Описания -

Они будут включать в себя переменную длину перегрузок, так что не существует никакого фиксированного предел от размера коллекции. Однако созданные экземпляры коллекции могут быть настроены для меньших размеров. Будут предоставлены специальные API-интерфейсы (фиксированные аргументы ) для до десяти элементов. Хотя этот вводит некоторый беспорядок в API, он избегает выделения массива, инициализации и накладных расходов на сбор мусора, которые возникают в результате вызовов varargs. Существенно, что исходный код сайта вызова одинаковый независимо от того, вызвана ли перегрузка fixed-arg или varargs.


Редактировать - добавить мотивации и, как уже упоминалось в комментариях по @CKing тоже:

Ненаркотические Цели -

Это не цель поддержка высокопроизводительных масштабируемых коллекций с произвольным количеством элементов. Основное внимание уделяется небольшим коллекциям.

Мотивация -

Создание небольшой, неизменяемый набор (скажем, набор) включает в себя построение его, хранить его в локальной переменной, и вызовом добавить() на нем несколько раз, а затем обертывание Это.

Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a", "b", "c"))); 

Java 8 Stream API может использоваться для создания небольших коллекций путем объединения методов фабрики потоков и коллекционеров.

// Java 8 
Set<String> set1 = Collections.unmodifiableSet(Stream.of("a", "b", "c").collect(Collectors.toSet())); 

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

// Java 9 
Set set2 = Set.of("a", "b", "c"); 
+1

Разве это не микро-оптимизация в эпоху обширного оборудования в вашем распоряжении на языке высокого уровня, например Java? Я так хочу, чтобы была другая причина для этого, но не может думать о одном – CKing

+0

В дополнение к тому, что вы цитировали, в документах также говорится: * Не стоит поддерживать высокопроизводительные масштабируемые коллекции с произвольным количеством элементов. Основное внимание уделяется ** небольшим коллекциям *** – CKing

+15

@CKing Да, это микро-оптимизация. Критерии производительности для библиотек JDK гораздо более строгие, чем для большинства приложений. Эти API-интерфейсы используются в самом JDK, и они влияют на время запуска, поэтому даже кажущиеся крошечными оптимизациями стоит того. –

8

Как вы подозревали, это повышение производительности. Методы Vararg создают массив «под капотом», а метод, принимающий 1-10 аргументов, позволяет избежать этого избыточного создания массива.

+1

Разве это не микро-оптимизация в эпоху обширного оборудования в вашем распоряжении на языке высокого уровня, например Java? Мне жаль, что для этого не было другой причины, но я не могу думать об этом. – CKing

+2

@CKing Разработчики языка/библиотеки должны учитывать производительность своего кода не только в коде, который выполняется нечасто; но также и то, что происходит, когда кто-то использует его в горячем цикле приложения с интенсивным вычислением. В тех случаях вещи, которые в противном случае могут быть отклонены как «бессмысленные микрооптимизации», имеют значительное влияние на производительность. –

+2

@DanNeely Этот аргумент справедлив в этом случае? Насколько дорого стоит создать массив из 10 элементов? – CKing

3

Вы также можете посмотреть на него наоборот. Начиная с varargs методы могут принимать массивы, такой метод будет служить альтернативным способом преобразования массива в List.

String []strArr = new String[]{"1","2"}; 
List<String> list = List.of(strArr); 

Альтернатива этого подхода является использование Arrays.asList, но любых изменений, сделанных в List в этом случае будет отражать в массиве, который не в случае с List.of. Поэтому вы можете использовать List.of, если вы не хотите, чтобы List и массив были в синхронизации.

Примечание Обоснование, данное в спецификации, похоже на микрооптимизацию для меня. (Это теперь подтверждено владельцем самого API в комментариях к another ответа)

+0

Это как вместо компилятора, создающего массив для меня, я сам создаю его. – ares

+0

@ares Подумайте об этом так. Иногда вы говорите с кодом, который возвращает массив. Если вы хотите преобразовать этот массив в список, вы можете напрямую передать его методу «List.of».Кроме того, 'List' и массив не будут синхронизироваться по сравнению с методом' Arrays.asList', так что это другой вариант использования этого метода. – CKing

6

Вы можете найти следующий отрывок из пункта 42 Josh Блоха Эффективное Java поучительный (2-е изд.):

Каждый вызов метода varargs вызывает распределение и инициализацию массива. Если вы определили эмпирически, что вы не можете позволить себе эту стоимость, но вам нужна гибкость varargs, есть образец, который позволяет вам иметь ваш торт и есть его тоже. Предположим, вы определили, что 95 процентов вызовов метода имеют три или меньше параметров. Затем объявить пять перегрузок методы, по одному с нулем через три обычных параметров, а также один метод переменной длиной для использования, когда количество аргументов превышает три [...]

+0

Итак, реализация была скопирована прямо из текста Джоша Больча. – ares

+0

Самые важные два слова, чтобы принять к сведению: * определено emprically *. Микро-оптимизации наиболее определенно требуют эмпирического доказательства. – CKing

-1

В соответствии с Java doc: наборов, возвращенных методы удобной фабрики более эффективны по площади, чем их изменяемые эквиваленты.

Перед Java 9: ​​

Set<String> set = new HashSet<>(3); // 3 buckets 

set.add("Hello"); 
set.add("World"); 
set = Collections.unmodifiableSet(set); 

В выше реализациях Set, есть 6 объектов создаются: в неизменяемую обертке; HashSet, который содержит HashMap; таблица ведер (массив); и два экземпляра узла (по одному для каждого элемента). Если VM занимает 12 байтов на объект, тогда 72 байта потребляют как служебные, плюс 28 * 2 = 56 байтов для 2 элементов. Здесь большая сумма потребляется накладными расходами по сравнению с данными, хранящимися в коллекции. Но в Java 9 эти накладные расходы очень малы.

После Java 9: ​​

Set<String> set = Set.of("Hello", "World"); 

В выше реализации Set, только один объект является создание и это займет очень меньше места для хранения данных из-за минимальных затратах.

+3

Хотя этот ответ может быть правильным, это не относится к заданному вопросу. – ares

 Смежные вопросы

  • Нет связанных вопросов^_^