2017-04-25 34 views
-1

試圖在使用Objects.equals vs Primitive比較時測試等於的速度。如果有人需要的代碼:Java等於原始圖像與對象速度

import org.junit.Test; 
import org.openjdk.jmh.annotations.*; 
import org.openjdk.jmh.runner.Runner; 
import org.openjdk.jmh.runner.RunnerException; 
import org.openjdk.jmh.runner.options.Options; 
import org.openjdk.jmh.runner.options.OptionsBuilder; 
import org.openjdk.jmh.runner.options.TimeValue; 

import java.util.Objects; 
import java.util.concurrent.TimeUnit; 

class BaseEquals { 
    byte bytePrim; 
    short shortPrim; 
    int intPrim; 
    long longPrim; 
    float floatPrim; 
    double doublePrim; 
    boolean booleanPrim; 
    char charPrim; 

    BaseEquals() { 
     bytePrim = 1; 
     shortPrim = 1; 
     intPrim = 1; 
     longPrim = 1; 
     floatPrim = 1.0f; 
     doublePrim = 1.0d; 
     booleanPrim = true; 
     charPrim = '1'; 
    } 
} 

class EqualsObjects extends BaseEquals { 

    @Override 
    public int hashCode() { 
     return Objects.hash(bytePrim, 
       shortPrim, 
       intPrim, 
       longPrim, 
       floatPrim, 
       doublePrim, 
       booleanPrim, 
       charPrim); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj == this) { 
      return true; 
     } 
     if (!(obj instanceof EqualsObjects)) { 
      return false; 
     } 
     EqualsObjects eo = (EqualsObjects)obj; 
     return Objects.equals(bytePrim, eo.bytePrim) 
       && Objects.equals(shortPrim, eo.shortPrim) 
       && Objects.equals(intPrim, eo.intPrim) 
       && Objects.equals(longPrim, eo.longPrim) 
       && Objects.equals(floatPrim, eo.floatPrim) 
       && Objects.equals(doublePrim, eo.doublePrim) 
       && Objects.equals(booleanPrim, eo.booleanPrim) 
       && Objects.equals(charPrim, eo.charPrim); 
    } 
} 

class EqualsPrimitives extends BaseEquals { 

    @Override 
    public int hashCode() { 
     return Objects.hash(bytePrim, 
       shortPrim, 
       intPrim, 
       longPrim, 
       floatPrim, 
       doublePrim, 
       booleanPrim, 
       charPrim); 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj == this) { 
      return true; 
     } 
     if (!(obj instanceof EqualsPrimitives)) { 
      return false; 
     } 
     EqualsPrimitives eo = (EqualsPrimitives)obj; 
     return bytePrim == eo.bytePrim 
       && shortPrim == eo.shortPrim 
       && intPrim == eo.intPrim 
       && longPrim == eo.longPrim 
       && Float.compare(floatPrim, eo.floatPrim) == 0 
       && Double.compare(doublePrim, eo.doublePrim) == 0 
       && booleanPrim == eo.booleanPrim 
       && charPrim == eo.charPrim; 
    } 
} 

public class EqualsTests { 

    @State(Scope.Benchmark) 
    public static class MyState { 
     EqualsObjects eo1; 
     EqualsObjects eo2; 
     EqualsPrimitives ep1; 
     EqualsPrimitives ep2; 

     @Setup 
     public void setup() throws Throwable { 
      eo1 = new EqualsObjects(); 
      eo2 = new EqualsObjects(); 
      ep1 = new EqualsPrimitives(); 
      ep2 = new EqualsPrimitives(); 
     } 
    } 

    @Benchmark 
    public void equalsObject(MyState state) throws Throwable { 
     boolean b1 = state.eo1.equals(state.eo2); 
     boolean b2 = state.eo2.equals(state.eo1); 
    } 

    @Benchmark 
    public void equalsPrimitive(MyState state) throws Throwable { 
     boolean b1 = state.ep1.equals(state.ep2); 
     boolean b2 = state.ep2.equals(state.ep1); 
    } 

    @Test 
    public void launch() throws RunnerException { 
     Options options = new OptionsBuilder() 
       .include(this.getClass().getName() + ".*") 
       .mode(Mode.AverageTime) 
       .timeUnit(TimeUnit.MICROSECONDS) 
       .warmupTime(TimeValue.seconds(1)) 
       .warmupIterations(5) 
       .measurementTime(TimeValue.seconds(5)) 
       .measurementIterations(10) 
       .threads(2) 
       .forks(1) 
       .shouldFailOnError(true) 
       .shouldDoGC(true) 
       .build(); 
     new Runner(options).run(); 
    } 
} 

我到底看到的是什麼結果:

Benchmark     Mode Cnt Score Error Units 
EqualsTests.equalsObject  avgt 10 0.026 ± 0.001 us/op 
EqualsTests.equalsPrimitive avgt 10 0.011 ± 0.001 us/op 

你覺得它使用基本比較有更快的equals方法(可能忽略其它操作值得在代碼中),或使用Objects.equals具有統一的代碼(不要考慮在equals方法中分別使用Double.compare和Float.compare作爲double和float基元,而==用於其他基元)?

+2

請,取出水平的scollbar。 – reporter

+2

什麼是15%更快? Primitive'=='與Object.equals相比,還是整個複雜的'equals'方法,包括所有對'Arrays.equals'的調用? –

+0

完整的功能執行。但是因爲兩者都是平等的,所以我認爲你可以說它和Object.equals相比是==。 – bojanv55

回答

0

使用包裝而不是原語應該總是有原因的。基本上,你應該使用原始的,但有時你需要一個包裝。

區別在於包裝可以是null並且基元始終設置爲初始值。這意味着,當你想擁有你自己的初始狀態,或者你想知道收到的int是0還是不存在,你肯定會使用包裝。

比較原語比比較包裝更快並不奇怪。調用equals成本爲調用任何其他方法成本。無論如何,你的測試還應該比較大數字時的差異。現在,我們只能說,比較原始的比比較包裝的要快。

Look Integer緩存從-128到127的數字。這個變化很大。

+0

好吧,在這裏使用包裝的原因是要有更統一的代碼,不要擔心你應該使用Double.compare而不是==等......但另一方面它更快......這不是問題,更多檢查其他意見是否對您有更明確的代碼或速度更重要 – bojanv55

0

您必須使用equals方法,因爲'=='檢查基元類型或相等對象標識之間的值相等(即操作數是否是相同的實例,而不僅僅是邏輯相等)。

這一切都計算爲true:

42 == 42 // primitive values 
int i = 42, j = 42; i == j // primitive values 
Integer i = new Integer(42); i == 42 // auto-unboxing 
Integer i = 42, j = 42; i == j // cached interned Integer instance 

然而,這個計算結果爲假,相反你所期望的:

Integer i = new Integer(42); Integer j = new Integer(42); i == j // not cached, different objects 
Integer i = new Integer("42"); Integer j = new Integer("42"); i == j 

僅使用==如果您要比較原始類型或希望實際檢查引用相等來查看兩個操作數是否是相同的實例。即使作爲一個操作數的基本類型和作爲另一個操作數的包裝類型,最好也不要這樣做,因爲如果包裝器變量爲空,自動拆箱可能導致空指針異常。可以認爲==也可以用於枚舉常量,但這往往會導致......辯論。

1

兩個代碼之間的差異可以在它們的字節碼輸出中看到。

原始值比較只需要一個if_icmpne指令就可以完成,就這些了。

見,說明bytePrim == eo.bytePrim

20: astore_2 
21: aload_0 
22: getfield  #3     // Field bytePrim:B 
25: aload_2 
26: getfield  #3     // Field bytePrim:B 
29: if_icmpne  246     

在otherhand,對象對比(Object.equals)需要的原語被盒裝到其對象當量(即INT到整型,字節到字節,字符到字符等)在比較發生之前。一旦兩個原語盒裝,附加invokestatic指令(Objects.equals)被調用來完成比較(其內部不具有空檢查等原始比較)

說明Objects.equals(bytePrim, eo.bytePrim)

21: aload_0 
22: getfield  #3     // Field bytePrim:B 
25: invokestatic #4     // Method java/lang/Byte.valueOf:(B)Ljava/lang/Byte; 
28: aload_2 
29: getfield  #3     // Field bytePrim:B 
32: invokestatic #4     // Method java/lang/Byte.valueOf:(B)Ljava/lang/Byte; 
35: invokestatic #30     // Method java/util/Objects.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z 
38: ifeq 
相關問題