Я записал два метода для проверки там производительности
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-, оценивают, равны по стеку -
таким образом это сделает эффект на производительность? (это будет помогать мне доказать, что первая реализация пустого указателя хороша в мудрой производительности, а также в аспекте удобочитаемости:))
Сравнение сгенерированных байткодов в основном бессмысленно, поскольку большая часть оптимизации происходит во время выполнения с помощью JIT-компилятора. Я предположу, что в данном случае любое из выражений будет одинаково быстрым. Если и есть какая-то разница, то она незначительна.
Это не то, о чем вам нужно беспокоиться. Ищите более масштабные оптимизации.
Разница будет незначительной, так что выбирайте то, что наиболее читабельно (!= null
imo)
Я бы придерживался (value! = Null) для удобства чтения. Но вы всегда можете использовать утверждения.
О, если вы хотите максимальной производительности, не создавайте дополнительных классов или методов. Даже статические методы потребуют немного времени, так как загрузчик классов Java должен загрузить их с помощью JIT.
Итак, всякий раз, когда вам нужно проверить, имеет ли переменная значение NULL, вы просто проверяете ее либо
if (x == null)
, либо
if (null == x)
. Откровенно говоря, я считаю, что бонус к производительности при выборе одного из двух легко компенсируется накладными расходами, связанными с введением ненужных методы.
С такими вопросами трудно понять, насколько умной будет 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! Также, если сомневаетесь, запустите свои собственные тесты. Детали иногда имеют значение - не очень часто для таких простых вещей, как эта, но если это действительно важно для вас, вы должны проверить состояние, максимально приближенное к производственному, насколько это возможно.
Не оптимизируйте за счет удобочитаемости, если прирост скорости (или памяти / в любом случае) будет незначительным. Я думаю, что ! = Null
, как правило, более читабельно, поэтому используйте его.
Помимо с трудом заработанной мудрости избегать случайного присваивания в C, которая способствует размещению константы слева от бинарного оператора, я нахожу константу на левый, чтобы быть более читаемым, потому что он ставит решающее значение на самое видное место.
Обычно тело функции использует только несколько переменных, и обычно из контекста очевидно, какая переменная проверяется. Помещая константу слева, мы более точно имитируем переключатель
и случай
: для данной этой переменной выберите соответствующее значение. Увидев значение слева, можно сосредоточиться на выбранном конкретном условии.
Когда я просматриваю
if (var == null)
, я читаю это так: «Мы проверяем var
здесь, и мы сравниваем его на равенство, против ... ах, null». И наоборот, когда я просматриваю
if (null == var)
, я думаю: «Мы проверяем, является ли значение нулевым, и ... да, мы проверяем var
». Это еще более сильное признание с
if (null != var)
, которое я сразу улавливаю.
Эта интуиция проистекает из постоянства привычки, предпочтения читать то, что пишут, и писать то, что предпочитают читать. Можно узнать это в любом случае, но это не объективно верно, поскольку другие ответили здесь, что размещение переменной слева более ясно. Это зависит от того, какой аспект выражения вы хотите в первую очередь прояснить.
Видеть разницу в байт-кодах было захватывающе. Спасибо, что поделились этим.
Байт-код - это просто простой перевод исходного кода.
Как видите, производительность сильно отличается меньше. Не беспокойтесь о мелочах, всегда лучше сосредоточиться на алгоритме. И, очевидно, важна читабельность.
Вы можете игнорировать этот мельчайший оптимизационный материал во время кодирования
Установка null
сначала, кажется, генерирует дополнительный байт-код, но помимо этого может не быть разницы в производительности.
Лично я бы не стал беспокоиться о производительности, пока не пришло время беспокоиться о производительности.
Я бы использовал подход notNull ()
, чтобы вы не выдали ошибку компилятора, если забудете !
и случайно введите null = значение
.
Такая минутная оптимизация - это работа компилятора, особенно в языках высокого уровня, таких как Java.
Хотя, строго говоря, здесь это не актуально, не оптимизируйте преждевременно!