В моей заявке obj.getClass().isArray()
вызывается очень часто и становится узким местом приложения.
Я хочу эффективно проверить во время выполнения, если объект является массивом. Примитивный массив и массив объектов должны возвращать значение true.
Способ, которым я могу представить, - это instanceof
все примитивные массивы, но не может обрабатывать такие типы, как int [] []. И приложение используется как lib, поэтому я не могу перечислить все типы.
Есть ли ключ к этому?Object.isArray() медленный, есть ли быстрый способ сделать это?
ответ
Эталонный Я только что сделал, дал следующие результаты:
{s instanceof Object[]} spends 44ms
{s.getClass().getName().charAt(0) == '['} spends 58ms
{s.getClass().isArray()} spends 303ms
Benchmark был сделан с помощью Benchmark.java, называемых с Main.java.
После того, как обсуждались использование final
переменных в приведенном выше тесте, увидеть новые результаты, используя локальную один:
{s instanceof Object[]} spends 83ms
{s.getClass().getName().charAt(0) == '['} spends 93ms
{s.getClass().isArray()} spends 354ms
Даже если длительности все немного больше (интересно кстати) , их порядок сохранился.
Benchmark.java был вызван с этим новым Main.java.
И используя примитивный массив с именем с этим другим Main.java:
{a instanceof int[]} spends 71ms
{a.getClass().getName().charAt(0) == '['} spends 82ms
{a.getClass().isArray()} spends 340ms
Все тот же порядок результатов.
Можете ли вы опубликовать контрольный код? Я получил [противоположные результаты] (http://stackoverflow.com/a/16171137/521799) –
@LukasEder [Benchmark.java] (http://pastebin.com/pskJ1tSy) и [Main.java] (http: //pastebin.com/KbptdWaB). Я должен сказать, что это инструмент, который я разработал сам по себе, поэтому я надеюсь, что в этом нет никакой ошибки. Не стесняйтесь сказать мне, если вы заметили одного, возможно, я сделал что-то не так :) – sp00m
Да, я подозреваю, что 'boolean b = s instanceof Object [];' оптимизирован компилятором, так как '' '' 'final ', и вышеприведенное выражение, таким образом, всегда оценивается как true ... –
isArray()
- самый эффективный способ проверить, является ли объект экземпляром массива во время выполнения. Если производительность является проблемой, вы можете использовать один из следующих методов для решения этой проблемы:
- рефакторинга кода, так объекты массивов и объекты без массива обрабатываются по отдельности, так что результаты
isArray()
известны во время компиляции , - Используйте локальные переменные и/или аргументы для кэширования значения
isArray()
во время операции, поэтому его нужно только вызывать один раз.
Я согласен с рефакторингом, но может ли кто-нибудь ответить на их утверждения, что 'isArray()' намного медленнее, чем 'instanceof'? Я чувствую, что кеширование результата может принести больше вреда, чем решить проблемы здесь! –
Кажется, что ваше (необоснованное) утверждение о том, что 'usArray()' является самым быстрым, неверно - см. Ответ sp00n. Однако я согласен с предложениями. – Bohemian
@Bohemian: тест sp00m может быть неточным, см. Комментарии ... –
Из ваших комментариев я пришел к выводу, что вы можете страдать от интерпретирующей ошибки при исследовании результатов профилирования. Инструментарий уровня вашего профилировщика может сильно искалечить getClass()
и isArray()
звонки, в то же время не впечатляя выражениями instanceof
. Другими словами, вы, вероятно, измеряете измерительные накладные расходы вашего профилировщика.
Кроме того, в быстром тесте я не могу поддержать ваше требование. Я запускать следующий, очень глупый тест:
public class Test {
public static void main(String[] args) {
final int rep = 10000000;
Object[] o = {
null,
1,
"x",
new Object[0],
new Object[0][],
new int[0],
new int[0][]
};
// "Warmup" to avoid potential JVM startup overhead
long x = 0;
for (int i = 0; i < rep; i++) {
x+=checkInstanceOf(o);
}
for (int i = 0; i < rep; i++) {
x+=checkIsArray(o);
}
for (int i = 0; i < rep; i++) {
x+=checkClassName(o);
}
// Actual test
long t1 = System.nanoTime();
for (int i = 0; i < rep; i++) {
x+=checkInstanceOf(o);
}
long t2 = System.nanoTime();
for (int i = 0; i < rep; i++) {
x+=checkIsArray(o);
}
long t3 = System.nanoTime();
for (int i = 0; i < rep; i++) {
x+=checkClassName(o);
}
long t4 = System.nanoTime();
System.out.println(t2 - t1);
System.out.println(t3 - t2);
System.out.println(t4 - t3);
}
private static int checkInstanceOf(Object[] o) {
int i = 0;
for (Object x : o) {
if (x instanceof Object[]) i++; // Perform some logic
else if (x instanceof boolean[]) i++; // to keep the compiler or
else if (x instanceof byte[]) i++; // the JVM from optimising
else if (x instanceof short[]) i++; // this code away
else if (x instanceof int[]) i++;
else if (x instanceof long[]) i++;
else if (x instanceof float[]) i++;
else if (x instanceof double[]) i++;
else if (x instanceof char[]) i++;
}
return i;
}
private static int checkIsArray(Object[] o) {
int i = 0;
for (Object x : o) {
if (x != null && x.getClass().isArray()) i++;
}
return i;
}
private static int checkClassName(Object[] o) {
int i = 0;
for (Object x : o) {
if (x != null && x.getClass().getName().charAt(0) == '[') i++;
}
return i;
}
}
я получаю:
394433000 // instanceof
110655000 // getClass().isArray()
396039000 // getClass().getName().charAt(0) == '['
Таким образом, вы не вообще претензии getClass().isArray()
может быть медленнее, чем тщательный набор instanceof
проверок. Конечно, есть много разных способов переписать мой тест, но вы получите эту идею.
Этот тест является ошибочным. Он не учитывает разминку JVM. (Я не удивлюсь, что вы получили бы противоположные «результаты», выполнив тесты в другом порядке ...) –
@StephenC: Конечно, я подумал об этом и попытался в обоих направлениях. Я обновлю результаты ... –
- 1. Есть ли более быстрый способ сделать это?
- 2. Есть ли способ сделать это?
- 3. Есть ли более быстрый способ сделать это? (местоположение python twitter)
- 4. Есть ли более быстрый способ сделать это LINQ?
- 5. Есть ли способ сделать это?
- 6. Есть ли способ сделать это?
- 7. PHP - Быстрый способ сделать это?
- 8. Есть ли лучший способ сделать это?
- 9. Параллельный массив Python (Numpy) медленный ... есть ли более быстрый способ?
- 10. Есть ли другой способ сделать это?
- 11. Есть ли более быстрый способ?
- 12. Есть ли способ сделать это в Grails?
- 13. Есть ли более элегантный способ сделать это?
- 14. Есть ли способ сделать это корпусом коммутатора?
- 15. Есть ли лучший способ сделать это?
- 16. Есть ли способ сделать это в MySQL?
- 17. Есть ли более рубиновый способ сделать это
- 18. Есть ли способ сделать это валидацию общим?
- 19. Есть ли лучший способ сделать это соединение?
- 20. Есть ли способ сделать это, css 3?
- 21. Есть ли способ сделать это быстрее?
- 22. Есть ли более рекурсивный способ сделать это?
- 23. Есть ли более простой способ сделать это?
- 24. Есть ли способ сделать это в javascript?
- 25. Есть ли более простой способ сделать это?
- 26. Есть ли лучший способ сделать это? MySQL
- 27. Есть ли более эффективный способ сделать это?
- 28. есть ли короткий способ сделать это?
- 29. Есть ли функциональный способ сделать это?
- 30. Есть ли способ сделать это более эффективным?
Это не отвечает на ваш вопрос, но это приятное дополнение к обсуждению: http://stackoverflow.com/questions/219881/java-array-reflection-isarray-vs-instanceof –
Я думаю, что вопрос в том, почему вы нужно часто называть этот метод? Надеюсь, что если бы был более быстрый способ, разработчики JDK основывали бы на себе свою реализацию. Если этого не происходит, вы должны дать более подробную информацию о реальной проблеме, которую пытаетесь решить. – Axel
Ваши аргументы 'instanceof' не совсем корректны. 'int [] [] instanceof Object []' дает 'true' (так же, как' int [] instanceof Object'), поэтому эти случаи покрываются ... Не уверен, что это относится к вашему фактическому проблемному домену (см. Комментарий Акселя). –