it-swarm.com.de

'...! = null' oder 'null! = ....' beste Leistung?

Ich habe zwei Methoden geschrieben, um die Leistung zu überprüfen

 public class Test1 {

 private String value;

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

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

}

und überprüfte seinen Bytecode nach dem Kompilieren

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


}

in diesem Fall werden zwei Opcodes verwendet, um die if-Bedingung zu implementieren: Im ersten Fall wird ifnull verwendet. Überprüfen Sie, ob der obere Wert des Stapels null ist. Im zweiten Fall wird if_acmpeq verwendet. Überprüfen Sie, ob die oberen zwei Werte im Stapel gleich sind.

wird sich dies auf die Leistung auswirken? (Dies hilft mir zu beweisen, dass die erste Implementierung von null sowohl in Bezug auf die Leistung als auch in Bezug auf die Lesbarkeit gut ist :))

40
asela38

Der Vergleich der generierten Bytecodes ist meistens bedeutungslos, da der Großteil der Optimierung zur Laufzeit mit dem JIT-Compiler erfolgt. Ich vermute, dass in diesem Fall jeder Ausdruck gleich schnell ist. Wenn es einen Unterschied gibt, ist es vernachlässigbar.

Das ist nichts, worüber Sie sich Sorgen machen müssen. Achten Sie auf Optimierungen für das Gesamtbild.

69

Optimieren Sie nicht auf Kosten der Lesbarkeit, wenn der Geschwindigkeitsgewinn (oder der Speicher oder was auch immer der Fall ist) vernachlässigbar ist. Ich denke, !=null ist im Allgemeinen besser lesbar.

19
Cam

Bei Fragen wie dieser ist es schwer zu wissen, wie intelligent die JVM sein wird (obwohl die Antwort "in der Regel ziemlich klug ist, wenn möglich" und in diesem Fall sehr gut möglich erscheint). Aber nur um sicherzugehen, testen Sie es:

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();
  }
}

Und auf meiner Maschine ergibt das:

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)

Die Antwort lautet also: nein, überhaupt kein bedeutender Unterschied. (Und der JIT-Compiler kann nach der gleichen Anzahl von Wiederholungsläufen zusätzliche Tricks finden, um sie zu beschleunigen.)


Update : Der obige Code führt einen Ad-hoc-Benchmark aus. Die Verwendung von JMH (jetzt, wo es existiert!) Ist eine gute Möglichkeit, um (einige) Mikrobanker-Fallstricke zu vermeiden. Der obige Code vermeidet die schlimmsten Fallstricke, gibt jedoch keine expliziten Fehlerschätzungen an und ignoriert verschiedene andere Dinge, die manchmal von Bedeutung sind. In diesen Tagen: Verwenden Sie JMH! Führen Sie im Zweifelsfall auch Ihre eigenen Benchmarks aus. Details sind manchmal von Bedeutung - nicht sehr oft für etwas so Unkompliziertes wie dieses, aber wenn es Ihnen wirklich wichtig ist, sollten Sie einen Zustand überprüfen, der so nahe an der Produktion ist, wie Sie es schaffen.

9
Rex Kerr

Abgesehen von der hart erarbeiteten Weisheit, zufällige Zuweisungen in C zu vermeiden, die die Konstante links vom binären Operator bevorzugen, finde ich, dass die Konstante links more lesbar ist, weil sie den entscheidenden Wert setzt in der prominentesten Position.

Normalerweise verwendet ein Funktionskörper nur wenige Variablen, und es ist normalerweise anhand des Kontextes erkennbar, welche Variable geprüft wird. Indem wir die Konstante links setzen, ahmen wir switch und case enger nach: gegeben this variable, wählen Sie einen passenden Wert aus. Wenn Sie den Wert auf der linken Seite sehen, fokussiert man auf die jeweils ausgewählte Bedingung.

Wenn ich scanne

if (var == null)

Ich lese es als: "Wir prüfen hier var und vergleichen es für Gleichheit mit ... ah, null." Umgekehrt, wenn ich scanne

if (null == var)

Ich denke, "wir sehen, ob ein Wert null ist, und ... ja, es ist var, das wir untersuchen." Es ist eine noch stärkere Anerkennung mit

if (null != var)

was mein Auge gerade aufnimmt.

Diese Intuition kommt von der Konsistenz der Gewohnheit, sie zieht es vor zu lesen, was man schreibt, und schreibt, was man lieber liest. Man kann es so oder so lernen, aber es ist nicht objektiv wahr, da andere hier geantwortet haben, dass das Setzen der Variablen auf der linken Seite klarer ist. Es hängt davon ab, welcher Aspekt des Ausdrucks zuerst klar sein soll.

Es war faszinierend, den Bytecode-Unterschied zu sehen. Danke, dass du das geteilt hast.

6
seh

Der Unterschied wird vernachlässigbar sein. Gehen Sie also zu dem, was am lesbarsten ist (!= null imo).

3
Matthew H

Ich würde zur besseren Lesbarkeit bei (Wert! = Null) bleiben. Sie können Assertions jedoch immer verwenden.

2

Eine solche Minutenoptimierung ist die Aufgabe des Compilers, insbesondere in Hochsprachen wie Java. 

Obwohl dies streng genommen nicht relevant ist, optimieren Sie nicht vorzeitig!

2
Humphrey Bogart

Sie können dieses winzige Optimierungsmaterial während der Codierung ignorieren

1
gmhk

Wie Sie sehen können, ist die Performance weniger. Machen Sie sich keine Sorgen über die kleinen Dinge. Es ist immer besser, sich mehr auf Algorithmen zu konzentrieren. Und natürlich ist Lesbarkeit ein Faktor.

1
Bipul

Das Setzen von null scheint zuerst einen zusätzlichen Bytecode zu generieren, aber ansonsten besteht möglicherweise kein Leistungsunterschied.

Ich persönlich würde mich nicht um die Leistung kümmern, bis es Zeit ist, sich um die Leistung zu sorgen.

Ich würde den notNull()-Ansatz verwenden, nur damit Sie keinen Compiler-Fehler werfen, wenn Sie den ! vergessen und versehentlich null = value eingeben.

1

Wenn Sie nach der ultimativen Leistung fragen, erstellen Sie keine zusätzlichen Klassen oder Methoden. Selbst statische Methoden benötigen etwas Zeit, da der Java-Klassenladeprogramm JIT laden muss.

Wann immer Sie überprüfen müssen, ob eine Variable null ist, testen Sie sie einfach mit einem der beiden

if (x == null)

oder

if (null == x)

Ehrlich gesagt rechne ich mit dem Leistungsbonus für die Wahl einer der beiden Möglichkeiten leicht durch den Aufwand an, unnötige Methoden einzuführen.

1
Michael Mao

Aus der Sicht gibt es keinen signifikanten Leistungsunterschied.

Es ist jedoch nützlich, zuerst die Null zu schreiben, um Tippfehler zu ermitteln.

Wenn Sie beispielsweise zum Schreiben dieses Codes verwendet werden:

if (obj == null)

Könnte aus Versehen geschrieben werden als:

if (obj = null)

Aus der Sicht des Compilers ist dies in Ordnung.

Wenn Sie den Code jedoch wie folgt schreiben:

if (null == obj)

und machte den Fehler zu schreiben:

if (null = obj)

der Compiler teilt Ihnen mit, dass Sie einen Fehler in dieser Zeile gemacht haben.

1
acarlstein

In Java-8 wurden zwei weitere Methoden für die Klasse Objects eingeführt: Objekte # nonNull und Objekte # isNull , mit denen Sie null-Prüfungen ersetzen können. Interessant ist, dass beide zuerst Objekte verwenden:

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

und 

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

entsprechend. Ich vermute, dies bedeutet, dass dies der empfohlene Weg ist (zumindest die wichtigsten JDK-Entwickler verwendeten diesen Ansatz) Quellcode für Objekte

0
Anton Balaniuc

Ich würde die "neue" Java 8-Funktion verwenden, ich schreibe einige Beispiele:

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

    });

}

}

Ich würde bevorzugen null != object wie es deutlich sichtbar macht, dass es nur für die Nullprüfung ist.

0
Bhaumik Thakkar