PDA

View Full Version : Accidently using == to compare strings in Java.


Jesse Aldridge
10-04-2006, 01:36 PM
I have this habit from my C++ days that I just can't seem to shake. I keep trying compare String objects using the == operator instead of the .equals method. It's a pretty insidious problem - I get no compiler error or warning message when I type: string == "stuff". Even worse, sometimes it works! It's always hell trying to figure out where one of these bugs originates. And then when I track it down to my using if( string == "stuff" ) instead of using if( string.equals( "stuff" ) ), I slap my forhead and vow I will never make that mistake again. But then I do!

So I'm asking this: is there any way to have Eclipse or the java complier spit out a warning whenver I compare strings with the == operator? Or do you have any other ideas regarding how I can address this issue.

oNyx
10-04-2006, 02:06 PM
http://findbugs.sourceforge.net/

There are only about 50% false positives in the first iteration. So, its actually useful to catch those "oh how stupid" bugs.

You can also add your own detectors if you want to.

Applewood
10-04-2006, 02:20 PM
My java is a little shaky so pardon if this is a silly question.

Why do you not get a syntax error ? If == is not supported by the class, it should barf, surely ?

If it's left "undefined", can you not subclass it yourself to always either work or generate an error message ?

EDIT:
PS: A habit I got into a while ago would help you here. I try (still forget a lot) to put constant comparisons the 'other' way around. "if (5==x)" won't compile if I typed "if (5=x)" whereas "if (x=5)" would.

oNyx
10-04-2006, 02:31 PM
>Why do you not get a syntax error ?

Because you can compare the "addresses" just fine like this.

>If it's left "undefined", can you not subclass it yourself to always either work or
>generate an error message ?

There is no operator overloading.

>"if (5==x)" won't compile if I typed "if (5=x)" whereas "if (x=5)" would.

Thats not Java. if(5) wont work at all. (It would work in c/c++ for example, because everything which isnt 0 is true there.)

Applewood
10-04-2006, 02:41 PM
Because you can compare the "addresses" just fine like this.

Is there a reason for that ?. As a newb, I don't see much point(sic) in that if you don't have pointers in your code.

Thats not Java. if(5) wont work at all
Ouch.

Thanks for answering the questions though. I'm trying to get a mindset of doing tools in Java, but I keep seeing stuff like this and it puts me off.

(This is mainly because even though it takes a millenia to boot up, eclipse is the dogs wotsits for editing. Nowadays I yearn for msdev to be more like eclipse instead of being more like brief!)

Backov
10-04-2006, 02:55 PM
I recently had this exact problem. I had used == for lots of compares throughout my project and everything was working great, but occasionally I'd get some really odd bug.

I did a complete search with Eclipse for ==, then went through and replaced every one of them with the proper .equals.. Mysterious bugs went away.

Getting better at putting them in now.

stiill
10-04-2006, 03:57 PM
Is there a reason for that ?

Rarely, but it happens. We had some performance-intensive code that needed to compare strings. We just made sure all the strings were interned (put into Java's internal string table), then we could use == for a much faster comparison.

Of course, given the rarity of that, == should do what .equals does, and strings should get a member like ".internCompare" or something. Well, just my opinion. James Gosling might have another one. :)

Daire Quinlan
10-04-2006, 05:21 PM
yeah, its a sneaky one all right. I've been absentmindedly stung by it myself sometimes, to the degree that at this stage I always automatically put in that .equals instead ...

It works 'sometimes' because Java stores an internal table of strings and -almost- always, if the strings are the same, trys to ensure that identical string variables are pointing to the same object in memory. This is naturally not always the case, local variables for example stored on the stack AFAIK don't get optimized like this. Java can do this because the strings are immutable. Its not recommended that you rely on this of course :-)

D.

Jesse Aldridge
10-04-2006, 06:09 PM
http://findbugs.sourceforge.net/

There are only about 50% false positives in the first iteration. So, its actually useful to catch those "oh how stupid" bugs.

You can also add your own detectors if you want to.

Cool! How do you like to use it, via the Eclipse plug-in or as a seperate utility? It says on the site that the Eclipse plug-in is still experimental, and it seemed a bit glitchy to me.

oNyx
10-04-2006, 06:41 PM
[...]
It works 'sometimes' because Java stores an internal table of strings and -almost- always, if the strings are the same, trys to ensure that identical string variables are pointing to the same object in memory.[...]

Even in bytecode. Thats why...

g.drawString("click to start",(320-metrics.stringWidth("click to start"))/2,420);

is smaller than...

g.drawString(String s="click to start",(320-metrics.stringWidth(s))/2,420);

Not that it would make any difference for a usual application, but its something to keep in mind for 4k.

>How do you like to use it, via the Eclipse plug-in or as a seperate utility?

I only run the GUI thingy occasionally... for checking if I did something horrible again. It tracks down stuff like relying on full block reads etc, which can easily happen.

---

Oh and just a few minutes ago I found something, which is very odd about Java.
for(int i=al.size()-1;i>=0;--i){
Object o=al.get(i);
}
Without the curly brackets you'll get a "not a statement" error and just "al.get(i);" is fine. Well, that never happend to me before since that line is nonsense (and usually you would do something with that thing after assigning it... so you would have curly brackets in place), but I did it for benchmarking fairness and I was damn irritated by that behaviour.

Sharkbait
10-05-2006, 01:41 AM
Is there a reason for that ?. As a newb, I don't see much point(sic) in that if you don't have pointers in your code.


The Java '==' operator for non-native types simple compares references so it is only true if references to the same object are being compaired. Bear in mind that all variables of non-native type are essentially managed pointers to the actual objects.

In C#, the '==' operator behaves in the same way by default, however it can be overloaded like in C++ to allow approprirate comparisions to be carried out on the object contents.

I would have thought that Java version 5 had operator overloading by now.. hasn't it been implemented in Java yet?

jeb_
10-05-2006, 04:14 AM
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html#intern()

This can be good to know since it means that if you write something like,
String a = "Hello";
String b = "Hello";

then a == b is true (try it yourself!). But if 'b' was read from an input buffer they may have created different objects and the strings must be compared using equals().

oNyx
10-05-2006, 01:53 PM
[...]
I would have thought that Java version 5 had operator overloading by now.. hasn't it been implemented in Java yet?

Operator overloading makes code hard to read, because you cant be sure what a line of code does w/o reading everything. Thats the reason why there is no operator overloading in Java (except the build-in + for Strings).

Daire Quinlan
10-05-2006, 05:16 PM
Operator overloading makes code hard to read, because you cant be sure what a line of code does w/o reading everything. Thats the reason why there is no operator overloading in Java (except the build-in + for Strings).

yeah, I love Java's wonderful little gotchas ...

EVERYTHING IS AN OBJECT (oh,except for those primitive types ...)
THERE IS NO OPERATOR OVERLOADING (except for those string bits and bobs)
THERE ARE NO READONLY PROPERTIES (eh ? oh yes, except for Array.length)

Bless their little cotton socks ! Wipe a tear from the eye etc etc etc

D.

oNyx
10-05-2006, 05:38 PM
>THERE ARE NO READONLY PROPERTIES (eh ? oh yes, except for Array.length)

Its a public final class var.

Like:
public class Foo{
public final int bar;
public Foo(int bar){
this.bar=bar;
}
}

Daire Quinlan
10-06-2006, 09:16 AM
>THERE ARE NO READONLY PROPERTIES (eh ? oh yes, except for Array.length)

Its a public final class var.

Like:
public class Foo{
public final int bar;
public Foo(int bar){
this.bar=bar;
}
}

You know, I was about to issue a stern self righteous rebuttal on this, until I wisely decided to try it first !

And whaddya know, I actually somehow missed for the last 5 years the fact that you can initialise a final variable at declaration time OR in all the constructors ... I feel a little slow ...

D.

Sharkbait
10-08-2006, 05:09 PM
Operator overloading makes code hard to read, because you cant be sure what a line of code does w/o reading everything. Thats the reason why there is no operator overloading in Java (except the build-in + for Strings).

Somehow I find that argument a little weak. By the same stream of logic, method overriding makes code harder to read because you cannot really know if a method has been overridden in a current class or inherited from a parent, and, well, every other feature can be argued against if this line of thought is taken to its extreme conclusion.

oNyx
10-08-2006, 06:34 PM
Somehow I find that argument a little weak. By the same stream of logic, method overriding makes code harder to read because you cannot really know if a method has been overridden in a current class or inherited from a parent, and, well, every other feature can be argued against if this line of thought is taken to its extreme conclusion.

http://en.wikipedia.org/wiki/Operator_overloading#Criticisms ;)

Aldacron
10-08-2006, 10:44 PM
Somehow I find that argument a little weak. By the same stream of logic, method overriding makes code harder to read because you cannot really know if a method has been overridden in a current class or inherited from a parent, and, well, every other feature can be argued against if this line of thought is taken to its extreme conclusion.

The problem is that symbols are not expressive enough to indicate their function to the programmer reading the code. You expect * to be the multiplication operator, yet some people will use it for other things -- like a dot product on a vector object. Is the + operator an addition or an appender?

I don't miss operator overloads in Java. They are only syntactic sugar, anyway. I come from mostly a C background, though, and have never really been fond of C++. Perhaps I'm just used to not having them. But not including operator overloads in a language is just one solution to the problem. D takes a different tack.

In D, operator overloads are named to indicate their function. So if you overload the * operator, it is called opMul, + is called opAdd, and so on. The idea is that operator overloads have a contract that the programmer is meant to follow. It's like an interface in Java, or a pure virtual class in C++. When you implement these methods, you are expected to implement them a certain way. The names help to drive that home. Unfortunately, there is no way to enforce it so you can still wind up with the crazy abuse of operators.

princec
10-09-2006, 02:22 AM
I was always rather fond of the idea of being able to define ordinary methods as operators, so you'd get code that looked like this:

c = a dot b;
m1 = m0 x m2;


Cas :)