Подтвердить что ты не робот

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

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

 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 */


}

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

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

4b9b3361

Ответ 1

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

Это не то, о чем вам нужно беспокоиться. Посмотрите на оптимизацию больших изображений.

Ответ 2

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

Ответ 3

С подобными вопросами трудно понять, насколько разумным будет 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! Кроме того, если вы сомневаетесь, запустите свои собственные тесты. Детали иногда имеют значение - не очень часто для чего-то столь же простого, как это, но если это действительно важно для вас, вы должны проверить состояние, близкое к производству, как вы можете управлять.

Ответ 4

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

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

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

if (var == null)

Я прочитал его как "Мы ​​проверяем var здесь, и мы сравниваем его для равенства, против... ah, null". И наоборот, когда я сканирую

if (null == var)

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

if (null != var)

который мой глаз сразу же набирает.

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

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

Ответ 5

Разница будет небрежной, поэтому переходите к тому, что наиболее читаемо (!= null imo)

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

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

if (x == null)

или

if (null == x)

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

Ответ 10

Вы можете игнорировать эту самую последнюю информацию о оптимизации во время кодирования

Ответ 11

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

Ответ 12

С точки зрения, нет существенной разницы в производительности.

Однако полезно сначала записать null, чтобы улавливать ошибки опечаток.

Например, если вы используете этот код для записи:

if (obj == null)

Может быть написано по ошибке как:

if (obj = null)

С точки зрения компилятора это прекрасно.

Однако, если вы привыкли писать код как:

if (null == obj)

и сделал ошибку, чтобы написать:

if (null = obj)

компилятор сообщит вам, что вы допустили ошибку в этой строке.

Ответ 13

В Java-8 были введены два дополнительных методов Objects класса: объекты # ненулевым и объекты # IsNull, которые вы можете использовать, чтобы заменить null чеки. Интересно то, что они оба сначала используют объекты:

public static boolean isNull(Object obj) {
    return obj == null;
}

а также

public static boolean nonNull(Object obj) {
    return obj != null;
}

соответственно. Я думаю, это означает, что это рекомендуемый способ (по крайней мере, основные разработчики jdk использовали этот подход) Исходный код объектов

Ответ 14

Я бы использовал "новую" функцию Java 8, я пишу несколько примеров:

import java.util.Optional;

public class SillyExample {

public void processWithValidation(final String sampleStringParameter){
    final String sampleString = Optional.ofNullable(sampleStringParameter).orElseThrow(() -> new IllegalArgumentException("String must not be null"));

    //Do what you want with sampleString
}


public void processIfPressent(final String sampleStringParameter){
    Optional.ofNullable(sampleStringParameter).ifPresent(sampleString -> {

        //Do what you want with sampleString

    });

}

public void processIfPressentWithFilter(final String sampleStringParameter){
    Optional.ofNullable(sampleStringParameter).filter("hello"::equalsIgnoreCase).ifPresent(sampleString -> {

        //Do what you want with sampleString

    });

}

}

Ответ 15

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