Я хочу создать новый массив объектов, объединив два меньших массива.
Они не могут быть нулевыми, но размер может быть равен 0.
Я не могу выбрать между этими двумя способами: эквивалентны они или более эффективны (например, system.arraycopy () копирует целые куски)?
MyObject[] things = new MyObject[publicThings.length+privateThings.length];
System.arraycopy(publicThings, 0, things, 0, publicThings.length);
System.arraycopy(privateThings, 0, things, publicThings.length, privateThings.length);
или же
MyObject[] things = new MyObject[publicThings.length+privateThings.length];
for (int i = 0; i < things.length; i++) {
if (i<publicThings.length){
things[i] = publicThings[i]
} else {
things[i] = privateThings[i-publicThings.length]
}
}
Единственная разница во внешнем виде кода?
EDIT: спасибо за связанный вопрос, но, похоже, у них есть нерешенное обсуждение:
Действительно ли это быстрее, если it is not for native types
: byte [], Object [], char []? во всех остальных случаях выполняется проверка типа, что было бы в моем случае и было бы эквивалентно ... нет?
По другому связанному вопросу они говорят, что the size matters a lot
для размера> 24 побеждает system.arraycopy (), для менее 10 лучше использовать ручной цикл ...
Теперь я очень запутался.
arraycopy()
это родной вызов, который, безусловно, быстрее.Ответы:
public void testHardCopyBytes() { byte[] bytes = new byte[0x5000000]; /*~83mb buffer*/ byte[] out = new byte[bytes.length]; for(int i = 0; i < out.length; i++) { out[i] = bytes[i]; } } public void testArrayCopyBytes() { byte[] bytes = new byte[0x5000000]; /*~83mb buffer*/ byte[] out = new byte[bytes.length]; System.arraycopy(bytes, 0, out, 0, out.length); }
Я знаю, что тесты JUnit на самом деле не самые лучшие для тестирования, но
testHardCopyBytes занял 0,157 секунды,
а
testArrayCopyBytes - 0,086 секунды.
Я думаю, это зависит от виртуальной машины, но похоже, что она копирует блоки памяти, а не отдельные элементы массива. Это абсолютно повысит производительность.
РЕДАКТИРОВАТЬ:
Похоже, производительность System.arraycopy повсюду. Когда вместо байтов используются строки, а массивы маленькие (размер 10), я получаю следующие результаты:
String HC: 60306 ns String AC: 4812 ns byte HC: 4490 ns byte AC: 9945 ns
Вот как это выглядит, когда массивы имеют размер 0x1000000. Похоже, System.arraycopy определенно выигрывает с большими массивами.
Strs HC: 51730575 ns Strs AC: 24033154 ns Bytes HC: 28521827 ns Bytes AC: 5264961 ns
Как странно!
Спасибо, Дарен, за указание на то, что ссылки копируются по-другому. Это сделало эту задачу гораздо более интересной!
источник
Arrays.copyOf(T[], int)
легче читать. Внутренне он использует,System.arraycopy()
который является родным вызовом.Быстрее не получишь!
источник
copyOf
не всегда можно заменитьarraycopy
, но он подходит для этого варианта использования.Это зависит от виртуальной машины, но System.arraycopy должен максимально приблизить к исходной производительности.
Я проработал 2 года Java-разработчиком для встраиваемых систем (где производительность является огромным приоритетом), и везде, где можно использовать System.arraycopy, я в основном использовал его / видел, как он используется в существующем коде. Когда производительность является проблемой, всегда предпочтительнее циклов. Если производительность не является большой проблемой, я бы пошел с петлей. Намного легче читать.
источник
Arrays.copy
не существует,Arrays.copyOf
это библиотечная функция.Вместо того, чтобы полагаться на предположения и, возможно, устаревшую информацию, я провел несколько тестов, используя каверномер. Фактически, в Caliper есть несколько примеров, в том числе тест,
CopyArrayBenchmark
который измеряет именно этот вопрос! Все, что вам нужно сделать, это бежатьМои результаты основаны на 64-разрядной серверной виртуальной машине Oracle Java HotSpot ™, 1.8.0_31-b13, работающей на MacBook Pro середины 2010 года (macOS 10.11.6 с Intel Arrandale i7, 8 ГиБ ОЗУ). Я не считаю полезным публиковать необработанные данные о времени. Скорее, я обобщу выводы с помощью вспомогательных визуализаций.
В итоге:
for
цикла для копирования каждого элемента во вновь созданный массив никогда не имеет смысла, будь то короткие или длинные массивы.Arrays.copyOf(array, array.length)
иarray.clone()
оба стабильно быстрые. Эти два метода почти идентичны по производительности; какой выбрать - дело вкуса.System.arraycopy(src, 0, dest, 0, src.length)
работает почти так же быстро, как и , но не так стабильно. (См. Случай для 50000 с.) Из-за этого и многословия вызова я бы порекомендовал, если вам нужен точный контроль над тем, какие элементы и куда копируются.Arrays.copyOf(array, array.length)
array.clone()
int
System.arraycopy()
Вот графики времени:
источник
Выполнение собственных методов, например
Arrays.copyOf(T[], int)
, имеет некоторые накладные расходы, но это не означает, что это не так быстро, поскольку вы выполняете его с использованием JNI.Самый простой способ - написать тест и протестировать.
Вы можете проверить, что
Arrays.copyOf(T[], int)
это быстрее, чем ваш обычныйfor
цикл.Код теста отсюда : -
public void test(int copySize, int copyCount, int testRep) { System.out.println("Copy size = " + copySize); System.out.println("Copy count = " + copyCount); System.out.println(); for (int i = testRep; i > 0; --i) { copy(copySize, copyCount); loop(copySize, copyCount); } System.out.println(); } public void copy(int copySize, int copyCount) { int[] src = newSrc(copySize + 1); int[] dst = new int[copySize + 1]; long begin = System.nanoTime(); for (int count = copyCount; count > 0; --count) { System.arraycopy(src, 1, dst, 0, copySize); dst[copySize] = src[copySize] + 1; System.arraycopy(dst, 0, src, 0, copySize); src[copySize] = dst[copySize]; } long end = System.nanoTime(); System.out.println("Arraycopy: " + (end - begin) / 1e9 + " s"); } public void loop(int copySize, int copyCount) { int[] src = newSrc(copySize + 1); int[] dst = new int[copySize + 1]; long begin = System.nanoTime(); for (int count = copyCount; count > 0; --count) { for (int i = copySize - 1; i >= 0; --i) { dst[i] = src[i + 1]; } dst[copySize] = src[copySize] + 1; for (int i = copySize - 1; i >= 0; --i) { src[i] = dst[i]; } src[copySize] = dst[copySize]; } long end = System.nanoTime(); System.out.println("Man. loop: " + (end - begin) / 1e9 + " s"); } public int[] newSrc(int arraySize) { int[] src = new int[arraySize]; for (int i = arraySize - 1; i >= 0; --i) { src[i] = i; } return src; }
System.arraycopy()
использует JNI (собственный интерфейс Java) для копирования массива (или его частей), поэтому он невероятно быстр, как вы можете подтвердить здесьисточник
System.arraycopy
не использует его.System.arraycopy
не использует JNI, который предназначен только для вызова сторонних библиотек. Вместо этого это собственный вызов, что означает, что для него есть собственная реализация в виртуальной машине.Это невозможно
Arrays.copyOf
быстрее, чем,System.arraycopy
поскольку это реализацияcopyOf
:public static int[] copyOf(int[] original, int newLength) { int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
источник
System.arraycopy()
это собственный вызов, который выполняет операцию копирования непосредственно в памяти. Одна копия памяти всегда будет быстрее, чем ваш цикл forисточник