'…! = пустой' или 'пустой указатель! = …' лучшая производительность?

Я записал два метода для проверки там производительности

 public class Test1 {

 private String value;

 public void notNull(){
  if( value != null) {
    //do something
  }
}

public void nullNot(){
 if( null != value) {
  //do something
 }
}

}

и проверенный это - код байта после компиляции

public void notNull();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: getfield #2; //Field value:Ljava/lang/String;
4: ifnull 7
7: return
LineNumberTable: 
line 6: 0
line 9: 7

StackMapTable: number_of_entries = 1
frame_type = 7 /* same */


public void nullNot();
Code:
Stack=2, Locals=1, Args_size=1
0: aconst_null
1: aload_0
2: getfield #2; //Field value:Ljava/lang/String;
5: if_acmpeq 8
8: return
LineNumberTable: 
line 12: 0
line 15: 8

StackMapTable: number_of_entries = 1
frame_type = 8 /* same */


}

в здесь двух кодах операций используются для реализации если условие: в первом случае это использует значение вершины проверки ifnull-стека, является пустым - и во втором случае это использует лучшие два проверки if_acmpeq-, оценивают, равны по стеку -

таким образом это сделает эффект на производительность? (это будет помогать мне доказать, что первая реализация пустого указателя хороша в мудрой производительности, а также в аспекте удобочитаемости:))

41
задан Josh Lee 8 March 2010 в 04:43
поделиться

12 ответов

Сравнение сгенерированных байткодов в основном бессмысленно, поскольку большая часть оптимизации происходит во время выполнения с помощью JIT-компилятора. Я предположу, что в данном случае любое из выражений будет одинаково быстрым. Если и есть какая-то разница, то она незначительна.

Это не то, о чем вам нужно беспокоиться. Ищите более масштабные оптимизации.

76
ответ дан 27 November 2019 в 00:12
поделиться

Разница будет незначительной, так что выбирайте то, что наиболее читабельно (!= null imo)

3
ответ дан 27 November 2019 в 00:12
поделиться

Я бы придерживался (value! = Null) для удобства чтения. Но вы всегда можете использовать утверждения.

2
ответ дан 27 November 2019 в 00:12
поделиться

О, если вы хотите максимальной производительности, не создавайте дополнительных классов или методов. Даже статические методы потребуют немного времени, так как загрузчик классов Java должен загрузить их с помощью JIT.

Итак, всякий раз, когда вам нужно проверить, имеет ли переменная значение NULL, вы просто проверяете ее либо

if (x == null)

, либо

if (null == x)

. Откровенно говоря, я считаю, что бонус к производительности при выборе одного из двух легко компенсируется накладными расходами, связанными с введением ненужных методы.

1
ответ дан 27 November 2019 в 00:12
поделиться

С такими вопросами трудно понять, насколько умной будет JVM (хотя ответ «обычно довольно умный, если возможно», и в данном случае это выглядит очень возможным). Но на всякий случай протестируйте это:

class Nullcheck {
  public static class Fooble { }

  Fooble[] foo = {null , new Fooble(), null , null,
                  new Fooble(), null, null, new Fooble() };

  public int testFirst() {
    int sum = 0;
    for (int i=0 ; i<1000000000 ; i++) if (foo[i&0x7] != null) sum++;
    return sum;
  }

  public int testSecond() {
    int sum = 0;
    for (int i=0 ; i<1000000000 ; i++) if (null != foo[i&0x7]) sum++;
    return sum;
  }

  public void run() {
    long t0 = System.nanoTime();
    int s1 = testFirst();
    long t1 = System.nanoTime();
    int s2 = testSecond();
    long t2 = System.nanoTime();
    System.out.printf("Difference=%d; %.3f vs. %.3f ns/loop (diff=%.3f)\n",
      s2-s1,(t1-t0)*1e-9,(t2-t1)*1e-9,(t0+t2-2*t1)*1e-9);
  }

  public static void main(String[] args) {
    Nullcheck me = new Nullcheck();
    for (int i=0 ; i<5 ; i++) me.run();
  }
}

И на моей машине это дает:

Difference=0; 2.574 vs. 2.583 ns/loop (diff=0.008)
Difference=0; 2.574 vs. 2.573 ns/loop (diff=-0.001)
Difference=0; 1.584 vs. 1.582 ns/loop (diff=-0.003)
Difference=0; 1.582 vs. 1.584 ns/loop (diff=0.002)
Difference=0; 1.582 vs. 1.582 ns/loop (diff=0.000)

Итак, ответ: нет, никакой значимой разницы. (И JIT-компилятор может найти дополнительные приемы для ускорения каждого из них после того же количества повторных запусков.)


Обновление : Код выше запускает специальный тест. Использование JMH (теперь, когда он существует!) - хороший способ помочь избежать (некоторых) ошибок микробенчмаркинга. Приведенный выше код позволяет избежать наихудших ошибок, но не дает явных оценок ошибок и игнорирует различные другие вещи, которые иногда имеют значение. В наши дни: используйте JMH! Также, если сомневаетесь, запустите свои собственные тесты. Детали иногда имеют значение - не очень часто для таких простых вещей, как эта, но если это действительно важно для вас, вы должны проверить состояние, максимально приближенное к производственному, насколько это возможно.

10
ответ дан 27 November 2019 в 00:12
поделиться

Не оптимизируйте за счет удобочитаемости, если прирост скорости (или памяти / в любом случае) будет незначительным. Я думаю, что ! = Null , как правило, более читабельно, поэтому используйте его.

21
ответ дан 27 November 2019 в 00:12
поделиться

Помимо с трудом заработанной мудрости избегать случайного присваивания в C, которая способствует размещению константы слева от бинарного оператора, я нахожу константу на левый, чтобы быть более читаемым, потому что он ставит решающее значение на самое видное место.

Обычно тело функции использует только несколько переменных, и обычно из контекста очевидно, какая переменная проверяется. Помещая константу слева, мы более точно имитируем переключатель и случай : для данной этой переменной выберите соответствующее значение. Увидев значение слева, можно сосредоточиться на выбранном конкретном условии.

Когда я просматриваю

if (var == null)

, я читаю это так: «Мы проверяем var здесь, и мы сравниваем его на равенство, против ... ах, null». И наоборот, когда я просматриваю

if (null == var)

, я думаю: «Мы проверяем, является ли значение нулевым, и ... да, мы проверяем var ». Это еще более сильное признание с

if (null != var)

, которое я сразу улавливаю.

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

Видеть разницу в байт-кодах было захватывающе. Спасибо, что поделились этим.

7
ответ дан 27 November 2019 в 00:12
поделиться

Байт-код - это просто простой перевод исходного кода.

-3
ответ дан 27 November 2019 в 00:12
поделиться

Как видите, производительность сильно отличается меньше. Не беспокойтесь о мелочах, всегда лучше сосредоточиться на алгоритме. И, очевидно, важна читабельность.

1
ответ дан 27 November 2019 в 00:12
поделиться

Вы можете игнорировать этот мельчайший оптимизационный материал во время кодирования

1
ответ дан 27 November 2019 в 00:12
поделиться

Установка null сначала, кажется, генерирует дополнительный байт-код, но помимо этого может не быть разницы в производительности.

Лично я бы не стал беспокоиться о производительности, пока не пришло время беспокоиться о производительности.

Я бы использовал подход notNull () , чтобы вы не выдали ошибку компилятора, если забудете ! и случайно введите null = значение .

1
ответ дан 27 November 2019 в 00:12
поделиться

Такая минутная оптимизация - это работа компилятора, особенно в языках высокого уровня, таких как Java.

Хотя, строго говоря, здесь это не актуально, не оптимизируйте преждевременно!

2
ответ дан 27 November 2019 в 00:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: