#java #arrays #collections
#java #массивы #Коллекции
Вопрос:
Нет ли какого-либо короткого пути, чтобы сделать это красиво?
Эти уродливые два цикла (один цикл для чтения списка pmList и второй цикл для добавления в markupArray) — единственный вариант (вместо ArrayUtils).
ArrayList<Double> pmList = new ArrayList<Double>();
pmList.add(0.1); // adding through a loop in real time.
pmList.add(0.1);
pmList.add(0.1);
pmList.add(0.1);
double[] markupArray = new double[pmList.size()];
arkupArray = pmList.toArray(markupArray); // This says The method toArray(T[]) in the type ArrayList<Double> is not applicable for the arguments (double[])
Ответ №1:
Просто используйте Double[]
массив, вместо double[]
этого все работает нормально. Если вы заранее знаете размер списка, вы также можете пропустить список и вставить его непосредственно в массив. Возможно, даже стоит пройти ввод два раза: один раз для получения его размера и один раз для вставки.
Автоматическая упаковка работает только для примитивных типов, а не для массивов примитивных типов. double[]
Массив не T[]
является массивом, поскольку параметром типа T
всегда должен быть an Object
. Хотя a double
может быть автоматически вставлен в T
(с T=Double
), a double[]
не может быть автоматически вставлен в T[]
.
Причина, по которой массивы не блокируются автоматически, вероятно, заключается в том, что эта операция была бы очень дорогостоящей: объединение массива означает создание нового массива и объединение каждого элемента. Для больших массивов это имеет огромное снижение производительности. Вы не хотите, чтобы такая дорогостоящая операция выполнялась неявно, следовательно, нет автобоксинга для массивов. Кроме того, упаковка полного массива приведет к созданию нового массива. Таким образом, при записи в новый массив изменения не будут записываться в старый массив. Итак, вы видите, есть некоторые проблемы с семантикой с упаковкой массивов, поэтому она не поддерживается.
Если вы должны вернуть double[]
массив, то вы должны либо написать свою собственную функцию, либо использовать стороннюю библиотеку, такую как Guava (см. Ответ msandiford). В Java Collections framework нет методов для (не) упаковки массивов.
Комментарии:
1. @Jayaprasad: Да, смотрите Мой отредактированный ответ. Упаковка просто не работает с массивами.
2. @ gexicide : я не могу из-за зависимостей. Этот markupArray должен быть double[] .
3. @Namalak: Вы заранее знаете размер списка? Если это так, вы можете просто пропустить список и вставить непосредственно в массив.
4. @ gexicide: НЕТ. (к сожалению)
5. @Namalak: Ну, тогда напишите свой собственный метод. Четыре строки вас не убьют :). Другим решением было бы дважды выполнить цикл над вашим вводом, в первый раз подсчитывая только количество удвоений. Возможно ли это?
Ответ №2:
Вы могли бы использовать TDoubleArraList или коллекцию примитивных списков guava.
Вы также можете заранее определить размер в одном цикле и добавить значения в другом.
Ответ №3:
Почему бы не создать свой собственный ярлык?
static double[] doubleListToArray(List<Double> list) {
int k = 0;
double[] result = new double[list.size()];
for(double value : list)
result[k ] = value;
return resu<
}
Комментарии:
1. Это всего лишь смещение кода. Вы собираетесь сказать, что если мы используем короткий путь, который должен выполнять эти два цикла внутри?
2. Любой другой ярлык будет делать это внутренне, да.
Ответ №4:
Google guava имеет Doubles#asList(...)
и Doubles#toArray(...)
которые обеспечивают преобразования из double[]
в List<Double>
и из Collection<? extends Number>
в double[]
соответственно.
Ответ №5:
Вы правы, что на первый взгляд это не очень интуитивно понятно. Однако это ограничение связано с тем, как язык Java реализует универсальные типы и автоматическую упаковку:
-
Общие типы удаляются во время выполнения. Это означает, что any
ArrayList<Double>
представлен одним скомпилированным классом JavaArrayList
, который совместно используется с другими общими представлениямиArrayList
, такими как, напримерArrayList<String>
. Как следствие, скомпилированный методArrayList::toArray
не знает (и не должен), какой универсальный тип представляет экземпляр, поскольку единственный скомпилированный метод должен быть применим для любого универсального типа. Поэтому, поскольку элементы могут быть чем-то вродеString
orDouble
, вам необходимо предоставить методу массив. Затем метод может проверить тип целевого массива во время выполнения и проверить, что элементы, которые заполняются в массив во время выполнения, могут быть назначены типу компонента массива. Вся эта логика может быть реализована одним скомпилированным методом. -
Во-вторых, автоматическая упаковка и распаковка — это то, что существует только во время компиляции. Это означает, что операторы
Integer i = 42; int j = i;
компилируются так, как если бы вы написали
Integer i = new Integer(42); int j = i.intValue();
Это компилятор Java, который добавляет инструкции по упаковке для вас. Среда выполнения Java применяет несколько иную систему типов, где упаковка не рассматривается. Как следствие, единственный скомпилированный метод
ArrayList::toArray
, который мы упомянули в (1), не может знать, что этот блок должен быть применен, поскольку мы утверждали, что метод должен быть применим для любого типаT
, который не всегда может представлять aDouble
.
Теоретически, вы могли бы изменить реализацию ArrayList::toArray
, чтобы явно проверять, применимы ли тип компонента массива и тип элемента lists для распаковки, но этот подход приведет к нескольким ветвям, которые добавят к методу довольно много времени выполнения. Скорее напишите небольшой служебный метод, который специализируется на Double
типе и применяет неявную распаковку из-за специализации. Для этой цели достаточно итерации по всем элементам списка, именно так ArrayList::toArray
это и реализовано. Если ваш массив невелик, рассмотрите возможность использования массива значений в штучной Double[]
упаковке вместо double[]
. Если ваш массив сколь угодно велик, живет долго или вы ограничены примитивными типами, чтобы соответствовать стороннему API, используйте утилиту. Кроме того, обратите внимание на реализации примитивных коллекций, если вы хотите отменить общий пакет. В Java 8 используйте a Stream
для встроенного преобразования массива.