Предполагая, что у меня есть ArrayList
ArrayList<MyClass> myList;
И я хочу вызвать toArray, есть ли причина для использования производительности
MyClass[] arr = myList.toArray(new MyClass[myList.size()]);
над
MyClass[] arr = myList.toArray(new MyClass[0]);
?
Я предпочитаю второй стиль, так как он менее многословен, и я предполагал, что компилятор позаботится о том, чтобы пустой массив на самом деле не создавался, но мне было интересно, правда ли это.
Конечно, в 99% случаев это не имеет значения, так или иначе, но я хотел бы сохранить согласованный стиль между моим нормальным кодом и оптимизированными внутренними циклами ...
java
performance
coding-style
itsadok
источник
источник
Ответы:
Как ни странно, самая быстрая версия на Hotspot 8:
Я запустил микро-бенчмарк, используя jmh, результаты и код приведены ниже, показывая, что версия с пустым массивом стабильно превосходит версию с предварительно определенным массивом. Обратите внимание, что если вы можете повторно использовать существующий массив правильного размера, результат может быть другим.
Результаты тестов (оценка в микросекундах, меньше = лучше):
Для справки, код:
Вы можете найти похожие результаты, полный анализ и обсуждение в блоге Arrays of Wisdom of the Ancients . Подводя итог: компилятор JVM и JIT содержит несколько оптимизаций, которые позволяют ему дешево создавать и инициализировать новый массив правильного размера, и эти оптимизации нельзя использовать, если вы создаете массив самостоятельно.
источник
MyClass[] arr = myList.stream().toArray(MyClass[]::new);
.., который, я думаю, будет медленнее. Кроме того, я хотел бы видеть тесты различий с объявлением массива. Как в разнице между:MyClass[] arr = new MyClass[myList.size()]; arr = myList.toArray(arr);
иMyClass[] arr = myList.toArray(new MyClass[myList.size()]);
... или не должно быть никакой разницы? Я полагаю, что эти два вопроса находятся за пределамиtoArray
функций. Но эй! Я не думал, что узнаю о других запутанных различиях.toArray
прямом вызове (чем меньше размер, тем больше относительнаяЧто касается ArrayList в Java 5 , массив будет заполнен уже, если он имеет правильный размер (или больше). следовательно
создаст один объект массива, заполнит его и вернет его в «arr». С другой стороны
создаст два массива. Второй - это массив MyClass с длиной 0. Таким образом, существует объект для объекта, который будет немедленно отброшен. Поскольку исходный код предполагает, что компилятор / JIT не может оптимизировать этот, чтобы он не был создан. Кроме того, использование объекта нулевой длины приводит к приведению типов в методе toArray ().
Смотрите источник ArrayList.toArray ():
Используйте первый метод, чтобы создать только один объект, и избегайте (неявных, но, тем не менее, дорогих) приведений.
источник
new Myclass[0]
это быстрее: shipilev.net/blog/2016/arrays-wisdom-ancientsИз JetBrains Intellij Идея осмотра:
источник
Современные JVM оптимизируют конструкцию отражательного массива в этом случае, поэтому разница в производительности незначительна. Называть коллекцию дважды в таком стандартном коде не очень хорошая идея, поэтому я бы избегал первого метода. Еще одним преимуществом второго является то, что он работает с синхронизированными и одновременными коллекциями. Если вы хотите провести оптимизацию, повторно используйте пустой массив (пустые массивы являются неизменяемыми и могут использоваться совместно) или используйте профилировщик (!).
источник
private static final MyClass[] EMPTY_MY_CLASS_ARRAY = new MyClass[0]
не мешает возвращаемый массив из строится путем отражения, но это предотвратить дополнительный массив строится каждый каждый раз.MyClass[] arr = myList.stream().toArray(MyClass[]::new);
это помогло бы или повредило бы с синхронизированными и параллельными коллекциями. И почему? Пожалуйста.toArray проверяет, что переданный массив имеет правильный размер (то есть достаточно большой, чтобы вместить элементы из вашего списка) и, если это так, использует это. Следовательно, если размер массива будет меньше требуемого, будет создан рефлексивно новый массив.
В вашем случае массив нулевого размера является неизменным, поэтому его можно безопасно преобразовать в статическую конечную переменную, что может сделать ваш код немного чище, что позволяет избежать создания массива при каждом вызове. В любом случае внутри метода будет создан новый массив, так что это удобочитаемость.
Возможно, более быстрая версия - передать массив правильного размера, но если вы не можете доказать, что этот код является узким местом в производительности, предпочтите удобочитаемость производительности во время выполнения, пока не доказано обратное.
источник
Первый случай более эффективен.
Это потому, что во втором случае:
среда выполнения фактически создает пустой массив (с нулевым размером), а затем внутри метода toArray создает другой массив для соответствия фактическим данным. Это создание выполняется с использованием отражения с использованием следующего кода (взятого из jdk1.5.0_10):
Используя первую форму, вы избегаете создания второго массива, а также избегаете кода отражения.
источник
Второй вариант немного читабелен, но улучшений так мало, что оно того не стоит. Первый способ быстрее, без недостатков во время выполнения, поэтому я использую его. Но я пишу это вторым способом, потому что это быстрее печатать. Тогда моя IDE помечает это как предупреждение и предлагает исправить это. Одним нажатием клавиши он преобразует код из второго типа в первый.
источник
Использование 'toArray' с массивом правильного размера будет работать лучше, так как альтернатива создаст сначала массив нулевого размера, а затем массив правильного размера. Однако, как вы говорите, разница, вероятно, будет незначительной.
Также обратите внимание, что компилятор javac не выполняет никакой оптимизации. В настоящее время все оптимизации выполняются компиляторами JIT / HotSpot во время выполнения. Я не знаю каких-либо оптимизаций вокруг 'toArray' в каких-либо JVM.
Таким образом, ответ на ваш вопрос в значительной степени зависит от стиля, но ради согласованности должен являться частью любых стандартов кодирования, которых вы придерживаетесь (документированных или иных).
источник
Пример кода для целого числа:
источник