2010-03-08 10 views
36

Ich schrieb zwei Methoden gibt'...! = Null' oder 'null! = ....' beste Leistung?

public class Test1 { 

private String value; 

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

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

} 

Leistung zu überprüfen und überprüft es nach Bytecode ist

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


} 

hier zwei OP-Codes, die, wenn die Bedingung zu implementieren verwendet: es in ersten Fall verwenden ifnull- check top value of stack ist null-, und im zweiten Fall if_acmpeq- check top zwei Werte sind gleich im Stack-

also, wird dies einen Effekt auf die Leistung machen? (dieser Wille hilft mir erste Implementierung von null zu beweisen, ist klug, sowie unter dem Aspekt der Lesbarkeit in Leistung gut :))

+4

Die Antwort von polygene ist diejenige, auf die Sie hören sollten. Aber wenn Sie wirklich denken, dass der Unterschied von Bedeutung ist, führen Sie jede Version eine Milliarde Mal oder so, und sehen Sie, ob es einen messbaren Unterschied gibt. dann komm zurück und erzähl uns davon. –

+0

Warum ist es wichtig, ist Ihr Programm nur 3 Zeilen lang, dass es so wichtig ist, wie schnell oder langsam diese eine einsame if-Anweisung abläuft? –

+7

Während wir zu diesem Thema sind, möchte ich beweisen, dass das Öffnen der geschweiften Klammer in derselben Zeile wie die Bedingung leistungsfähiger ist als andere geschweifte Klammern. –

Antwort

63

die erzeugten Bytecode Vergleich ist meist sinnlos, den größten Teil der Optimierung, da in der Laufzeit geschieht mit der JIT-Compiler. Ich vermute, dass in diesem Fall beide Ausdrücke gleich schnell sind. Wenn es einen Unterschied gibt, ist es vernachlässigbar.

Dies ist nicht etwas, über das Sie sich Sorgen machen müssen. Achten Sie auf große Bildoptimierungen.

+6

+1 für die Unterscheidung zwischen Bytecode und Assembly - das ist ein sehr wichtiger Unterschied zu beachten. – Cam

+4

Es ist wirklich ziemlich einfach: Wenn einer schneller als der andere wäre, hätten einige kluge Leute bei Microsoft den Compiler oder den JIT * bereits * den langsamen in den schnellen umgewandelt. –

+0

Guter Punkt auf Bytecodes, aber woher wissen Sie, dass dies keine große Bildoptimierung ist? Wenn Sie nur dünn besetzte Daten sehen, könnte die Suche nach Null der Code sein, in dem der Code die meiste Zeit verbringt. –

1

Das Setzen von null scheint zuerst einen zusätzlichen Bytecode zu erzeugen, aber abgesehen davon gibt es möglicherweise keinen Leistungsunterschied.

Persönlich würde ich mich über die Leistung nicht sorgen, bis es an der Zeit ist, sich um die Leistung zu sorgen.

würde ich den notNull() Ansatz verwenden, nur damit Sie nicht über einen Compiler-Fehler auslösen, wenn die ! vergessen und geben Sie versehentlich null = value.

+0

aber in der if-Bedingung, wenn Sie den gleichen Fehler machen, wird es nicht kompilieren, wenn nicht Wert ist Boolean Typ – asela38

+1

Ich denke, dass Sie eher einen Tippfehler machen, wenn Sie 'notNull (Wert)' als 'Wert eingeben ! = null'. – Ponkadoodle

+0

Ja, einverstanden, ich wollte allgemein sprechen, wenn ich eine Typprüfung durchführe, das habe ich aber nicht klargestellt. Vielen Dank. –

15

Nicht auf Kosten der Lesbarkeit optimieren, wenn die Geschwindigkeit (oder Speicher/was auch immer der Fall sein mag) die Verstärkung vernachlässigbar ist. Ich denke, !=null ist in der Regel besser lesbar, also verwenden Sie das.

+0

Ich stimme dem zu, was Sie über die Lesbarkeit sagen. null ist konstant, und für Vergleiche, die Konstanten beinhalten, ist die Variable constant am besten lesbar. – Ponkadoodle

+4

... es sei denn, Sie lesen von rechts nach links – CodyBugstein

3

Der Unterschied wird sein negligable so geht mit dem, was am besten lesen (!= null imo)

1

Oh, wenn Sie für ultimative Leistung fragen, erstellen Sie keine zusätzliche Klasse oder Methoden. Selbst statische Methoden benötigen etwas Zeit, da der Java Class Loader sie JIT laden muss.

Also, wenn Sie überprüfen müssen, ob eine Variable null ist, testen Sie es einfach durch entweder

if (x == null) 

oder

if (null == x) 

Ehrlich gesagt ich die Leistung Bonus rechnen eines der beiden holen wird leicht durch den Overhead der Einführung unnötiger Methoden ausgeglichen.

+0

Ich bin sicher, diese Methoden wurden nur als eine einfache Möglichkeit, den Unterschied in generierten Bytecode zu sehen eingeführt. –

2

Ich bleibe mit (Wert! = Null) für die Lesbarkeit. Aber Sie können Assertions immer verwenden.

5

Neben dem hart verdienten Weisheit in C zufälligen Zuordnung zu vermeiden, die die Konstante begünstigt auf der linken Seite des Binäroperators setzen, finde ich die Konstante auf der linken Seite mehr lesbar sein, weil sie den entscheidenden Wert legt in der prominentesten Position.

Normalerweise wird ein Funktionskörper nur ein paar Variablen verwenden, und es wird normalerweise durch den Kontext ersichtlich, welche Variable gerade überprüft wird. Indem wir die Konstante auf die linke Seite stellen, ahmen wir genauer switch und case nach: gegeben diese Variable, wählen Sie einen passenden Wert. Wenn Sie den Wert auf der linken Seite sehen, konzentriert sich der Fokus auf den ausgewählten Zustand.

Wenn ich scannen

if (var == null) 

Ich las es als: "Wir Inspektion var hier, und wir vergleichen es für Gleichheit, gegen ... ah, null." Umgekehrt, wenn ich scannen

if (null == var) 

Ich denke, „Wir sehen, wenn ein Wert Null ist, und ... ja, es ist var wir inspizieren.“ Es ist eine noch stärkere Anerkennung mit

, die mein Auge gerade sofort aufgreift.

Diese Intuition kommt aus der Konsistenz der Gewohnheit, lieber zu lesen, was man schreibt, und schreiben, was man lieber liest. Man kann es auf jede Weise 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, welchen Aspekt des Ausdrucks man zuerst am klarsten haben möchte.

Den Bytecodeunterschied zu sehen war faszinierend. Danke für das Teilen.

+17

Jedem seine eigene Intuition ... (Obwohl Sie sich diesbezüglich definitiv irren.;)) –

+4

Die "hart verdiente Weisheit, zufällige Zuweisungen in C zu vermeiden" ist ungefähr 20 Jahre veraltet, da C-Compiler jetzt Warnungen davor aussenden (anstatt sie von 'Lint' zu bekommen), und es trifft eigentlich nicht auf Java zu. – EJP

+0

Dass Compiler davor warnen, ändert nicht den Grund, warum Langzeit-Programmierer diesen Stil zuerst angenommen haben, aber das macht nichts. Mein Punkt hier ist, dass das Vermeiden solcher zufälliger Zuweisung nicht der einzige Vorteil des Stils ist, und es gibt noch einen guten Grund, es heute anzunehmen. Abhängig davon, was der Leser am meisten interessiert, kann dieser Stil "besser lesen". – seh

2

Minute Optimierung wie das ist die Aufgabe des Compilers, vor allem in Hochsprachen wie Java.

Obwohl streng hier nicht relevant, nicht vorzeitig optimieren!

9

Bei Fragen wie dieser ist es schwer zu wissen, wie schlau die JVM sein wird (obwohl die Antwort "normalerweise ziemlich schlau, wenn möglich" ist und in diesem Fall sehr gut aussieht). Aber nur um sicher zu sein, es testen:

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 meinem Rechner Dies ergibt:

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) 

So lautet die Antwort: nein, kein sinnvoller Unterschied. (Und der JIT-Compiler kann zusätzliche Tricks jeweils bis nach der gleichen Anzahl von Wiederholungsläufe zu beschleunigen.)


aktualisieren: Der obige Code führt eine Ad-hoc-Benchmark. Die Verwendung von JMH (jetzt, wo es existiert!) Ist ein guter Weg, um (einige) Microbenchmarking-Fallstricke zu vermeiden. Der obige Code vermeidet die schlimmsten Fallstricke, gibt jedoch keine expliziten Fehlerschätzungen und ignoriert verschiedene andere Dinge, die manchmal von Bedeutung sind. In diesen Tagen: benutze JMH! Führen Sie im Zweifelsfall Ihre eigenen Benchmarks aus. Details sind manchmal wichtig - nicht sehr oft für etwas so Einfaches wie dies, aber wenn es wirklich wichtig für Sie ist, sollten Sie einen Zustand prüfen, der so nah an der Produktion liegt, wie Sie es schaffen können.

1

Sie können während der Codierung

1

dieser Minute Optimierung Sachen ignorieren, wie Sie die Leistung unterschiedlich ist sehr weniger zu sehen. Mach dir keine Sorgen über die kleinen Dinge, es ist immer besser, sich mehr auf den Algorithmus zu konzentrieren.Und offensichtlich ist Lesbarkeit ein Faktor.

-2

Byte-Code ist nur eine einfache Übersetzung des Quellcodes.

+0

Das hängt ganz davon ab, welchen Compiler Sie verwenden. – EJP

1

Aus der Sicht gibt es keinen signifikanten Unterschied in der Leistung.

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

Zum Beispiel, wenn Sie verwendet werden, diesen Code zu schreiben:

if (obj == null) 

könnte versehentlich als geschrieben werden:

if (obj = null) 

Aus der Sicht des Compilers, das ist in Ordnung.

jedoch Wenn Sie verwendet werden, um den Code zu schreiben:

if (null == obj) 

und machte den Fehler schreiben:

if (null = obj) 

der Compiler lässt Sie wissen, dass Sie in dieser Zeile einen Fehler gemacht .

+2

Dies wurde bereits diskutiert, siehe [Kommentare zu einer anderen Antwort] (http://stackoverflow.com/a/2398688/224132). Sie sollten diese Antwort bearbeiten, um zu erklären, warum Sie denken, dass dies nützlich ist, auch wenn diese Kommentatoren sagen, dass dies nicht der Fall ist. –

Verwandte Themen