20

I had an interesting conversation with one of my team mate.

Is CONSTANT.equals(VARIABLE) faster than VARIABLE.equals(CONSTANT)in Java?

I suspect this to be a false statement. But I am trying to figure out what should be qualitative reasoning behind this?

I know in both the cases the performance will not differ to any kind of significant state. But it was a recommendation under BEST PRACTICES which is making me uncomfortable. That's the reason I am looking towards a good reasoning that I want to present with this case.

Please HELP

Ashish Agarwal
  • 6,215
  • 12
  • 58
  • 91

8 Answers8

45

Interesting question. Here is the test I wrote:

public class EqualsTest {
    public static String CONST = "const";
    public void constEqVar(String var) {
        CONST.equals(var);
    }
    public void varEqConst(String var) {
        var.equals(CONST);
    }
}

Then I compiled it using javac: javac EqualsTest.java and disassembled it using javap: javap -c EqualsTest.

Here is the relevant snippet of javap output:

public void constEqVar(java.lang.String);
  Code:
   0:   getstatic       #2; //Field CONST:Ljava/lang/String;
   3:   aload_1
   4:   invokevirtual   #3; //Method java/lang/String.equals:(Ljava/lang/Object;)Z
   7:   pop
   8:   return

public void varEqConst(java.lang.String);
  Code:
   0:   aload_1
   1:   getstatic       #2; //Field CONST:Ljava/lang/String;
   4:   invokevirtual   #3; //Method java/lang/String.equals:(Ljava/lang/Object;)Z
   7:   pop
   8:   return

As you can see the only difference between theses 2 methods is order of operations: getstatic and then aload_1 in first case and aload_1 + getstatic in second case.

Pretty obvious that the execution time should not depend on this order.

The only reason to prefer const.equals(var) rather than var.equals(const) is to avoid NullPointerException.

AlexR
  • 114,158
  • 16
  • 130
  • 208
26

For me its not a speed issue, its a relability issue.

e.g.

"Hello".equals(a); // will never throw a NPE
a.equals("Hello"); // can throw an NPE.

You may prefer it to blow up when a is null but usually I don't.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

That depends only on the implementation of the equals method. It could be quicker, it could be the slower and it could be the same... Often it is the same. Also it does not depend on the fact that one is a variable and the other a constant but on the content both objects.

One advantage of Constant.equals(variable) is that you can't have a NullPointerException on the .equals

tibo
  • 5,326
  • 4
  • 37
  • 53
  • NullPointerException is very much known that's the reason my primarily focus is Performance. – Ashish Agarwal Jun 06 '12 at 09:18
  • 1
    @Frank: 1. Java is not an acrynom, so it's "Java", 2. Even if Performance is not great, performance considerations might still be interesting (difference between "bad" and "abysmal") and 3. Java is pretty good with performance these days, you're spreading FUD. – Joachim Sauer Jun 06 '12 at 09:23
  • 1
    @Joachim Sauer 1. I write JAVA the way I want whether you have 76k or not, 2. Talking about Performance on a JVM running on a (assumption) DOS-NT-attachment (DOS& NT are acronyms) is fundamentally dense, 3. This is a QA Site and my last entry was an answer contrary to yours. – Franz Ebner Jun 06 '12 at 09:41
2

If we compare CONSTANT key(Left side of equals method) with any Object(Right side of equals method) then compiler can do check comparison and give the expected result, but if we do vice versa Object((Left side of equals method)) comparison with Constant key((Right side of equals method)) then your program might through the NULL POINTER EXCEPTION.

public static void main(String[] args) {
    String CONSTANT_KEY = "JAVA";
    String string = null;

    // CASE 1
    if (CONSTANT_KEY.equals(string)) {
        System.out.println("I am in if block");
    }

    // CASE 2   
    if (string.equals(string)) {
        System.out.println("I am in if block");
    }
}

In above code case 1 is always safe to compare the objects to avoid NULL POINTER EXCEPTION instead of case 2.

Samuel Philipp
  • 10,631
  • 12
  • 36
  • 56
Vinod Pattanshetti
  • 2,465
  • 3
  • 22
  • 36
1

Made a simple test with Strings:

final String constHello = "Hello";
final int times = 1000000000;

long constTimeStart = System.nanoTime();

for (int i = 0; i < times; ++i) {
    constHello.equals("Hello");
}

long constTimeStop = System.nanoTime();

System.out.println("constHello.equals(\"Hello\"); " + times + " times: " + (constTimeStop - constTimeStart) + " ns");


constTimeStart = System.nanoTime();

for (int i = 0; i < times; ++i) {
    "Hello".equals(constHello);
}

constTimeStop = System.nanoTime();

System.out.println("\"Hello\".equals(constHello); " + times + " times: " + (constTimeStop - constTimeStart) + " ns");

Edit: As mentioned in the comments below, this wasn't a good way of doing micromeasurements. Switching which part of the code which was going to be executed first proved that warm up time played a significant role here. The first test always runs slower. Repeating the test multiple times in the same code to quickfix this makes the results more or less the same.

Mats Adborn
  • 504
  • 2
  • 7
  • 1
    Note that you will always hit the fast-path in your comparison, since both objects are actually the same objects. Also, youre testing code is broken, because it does not take into account the warmup time. – Joachim Sauer Jun 06 '12 at 09:23
  • See [this question on how to do correct microbenchmarks in Java](http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java). – Joachim Sauer Jun 06 '12 at 09:24
  • @Joachim Sauer: You are right. Had an incomplete understanding of how to do these tests. Thanks for clarifying. – Mats Adborn Jun 06 '12 at 09:42
1

One good comparison can be:

private static String EXAMPLE = "Example";
private String obj = null;

case 1:

if(obj.equals(EXAMPLE) {
}

This is throw null pointer exception..

case 2 :

if(EXAMPLE.equals(obj)) {
}

This will not throw null pointer exception..

Govind
  • 2,482
  • 1
  • 28
  • 40
0

I guess the code in java.lang.String supports my answer:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = offset;
            int j = anotherString.offset;
            while (n-- != 0) {
                if (v1[i++] != v2[j++])
                    return false;
            }
            return true;
        }
    }
    return false;
}
Samuel Philipp
  • 10,631
  • 12
  • 36
  • 56
Ashish Agarwal
  • 6,215
  • 12
  • 58
  • 91
0
  • take this example : object.equals(value)

if object is null than

if(null.equals(value) { } This is throw null pointer exception..

if(value.equals(null)) { } This will not throw null pointer exception.. and do not entre the bloc

it is best to use the second chose if you don't know what this null object is.