Confused about StringBuilder equals

S

sunstormrider

Hi guys

OK - I have a pretty basic problem:

If I do

String a = "fred";
String b = "fred";

if (a.equals(b))
{ System.out.println("Equal"); }
else {System.our.println("Not equal"); }

then everything is as I'd expect - i.e. it returns Equal.

However, if I make my Strings StringBuilders, I'm getting a response
I'm not expecting:

StringBuilder a = new StringBuilder("fred");
StringBuilder b = new StringBuilder("fred");

if (a.equals(b))
{ System.out.println("Equal"); }
else {System.our.println("Not equal"); }

I'm getting Not equal. I know StringBuilder inherits from Object but
I can't see how to get around this one with casting. Can anyone help
please it's driving me nuts?

Cheers
Sun
 
P

Patricia Shanahan

However, if I make my Strings StringBuilders, I'm getting a response
I'm not expecting:

To find out what to expect from an API class method, read its documentation:

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html#toString()

A StringBuilder is equal to itself, and nothing else. Anything else
would be a bad idea, given the fact that StringBuilder is not only
mutable, it is positively designed for change.
I'm getting Not equal. I know StringBuilder inherits from Object
but I can't see how to get around this one with casting. Can anyone
help please it's driving me nuts?

If you want to ask whether two StringBuilder instances currently contain
equal Strings:

a.toString().equals(b.toString())

However, remember this can change at any time. If you do not intend
changes, use String rather than StringBuilder.

Patricia
 
S

sunstormrider

(e-mail address removed) wrote:

...


To find out what to expect from an API class method, read its documentation:

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html#...()

A StringBuilder is equal to itself, and nothing else. Anything else
would be a bad idea, given the fact that StringBuilder is not only
mutable, it is positively designed for change.


If you want to ask whether two StringBuilder instances currently contain
equal Strings:

a.toString().equals(b.toString())

However, remember this can change at any time. If you do not intend
changes, use String rather than StringBuilder.

Patricia

Brilliant - thanks very much. Of course - a StringBuilder is an
object, so it's the textual representations of each that I needed to
test - not the objects themselves.

Many many thanks

Sun
 
T

Thomas Kellerer

Patricia Shanahan wrote on 23.10.2007 20:23:
A StringBuilder is equal to itself, and nothing else. Anything else
would be a bad idea, given the fact that StringBuilder is not only
mutable, it is positively designed for change.

There are classes in the JDK that are mutable and still implement a decent
equals() method (e.g.: Point, AbstractList, Date).

The only thing that equals() == true means, is that the two objects are equal at
that point in time when they are compared to each other.

The equals() contract does not guarantee that they will stay equal forever.

The documentation for equals() even takes mutable objects into account:

"for any non-null reference values x and y, multiple invocations of x.equals(y)
consistently return true or consistently return false, provided no information
used in equals comparisons on the objects is modified."

So why shouldn't it be possible for StringBuilder to implement equals() based on
comparing all characters and thus avoiding the overhead of copying the char
array around just for comparing.
I would very much appreciate that and I don't see a problem with the fact that
it's mutable.


Thomas
 
J

Joshua Cranmer

Thomas said:
Patricia Shanahan wrote on 23.10.2007 20:23:

There are classes in the JDK that are mutable and still implement a
decent equals() method (e.g.: Point, AbstractList, Date).

AFAIK, the classes that are mutable and have an actual comparative
equals() method fall into two categories:
1. Collections and related components.
2. Classes that are mutable by design mistake (e.g., Point, Date).

The second category should generally be assumed (except for defensive
purposes) to be used immutably, so the verity of equals /should/ remain
constant throughout all points of time, so they are an exception to the
rule that `mutability should generally not use equals.'

The first category has two use cases: highly ephemeral instances with
high mutability, and long-term backings for which changes are made only
sporadically. It is for the latter purpose where equals() comes in.
So why shouldn't it be possible for StringBuilder to implement equals()
based on comparing all characters and thus avoiding the overhead of
copying the char array around just for comparing.
I would very much appreciate that and I don't see a problem with the
fact that it's mutable.

The problem with StringBuilder -- and any other class with similar usage
patterns -- is that it only exists for the small amount of time in which
it is constructing the final object. It is not only mutable, but it does
not really have a sense of an immutable state or use case. The equals()
method implies some sort of immutability which can generally be
supplied, but which is generally idiotic in the use case of
StringBuilder, since it shouldn't exist for long as a StringBuilder.
 
P

Patricia Shanahan

Joshua said:
Thomas Kellerer wrote: ....

The problem with StringBuilder -- and any other class with similar usage
patterns -- is that it only exists for the small amount of time in which
it is constructing the final object. It is not only mutable, but it does
not really have a sense of an immutable state or use case. The equals()
method implies some sort of immutability which can generally be
supplied, but which is generally idiotic in the use case of
StringBuilder, since it shouldn't exist for long as a StringBuilder.

And if you find yourself wanting to use a StringBuilder without
intending its value to change you have finished building, and should be
using the String it built.

Patricia
 
M

Mike Schilling

Roedy Green said:
And just when you thought you understood it all2,

boolean same = a == b;

same is true.

Why shouldn't it be? Both a and b point to the object "fred".

I would guess that

Integer i = 0;
Integert j = 0;

boolean same = i == j;

also results in "true", though at the moment I'm too lazy to check.
 
D

Daniel Dyer

Why shouldn't it be? Both a and b point to the object "fred".

I would guess that

Integer i = 0;
Integert j = 0;

boolean same = i == j;

also results in "true", though at the moment I'm too lazy to check.

It does, but this doesn't:

Integer i = 128;
Integer j = 128;

boolean same = i == j;

One of the many joys of autoboxing.

Dan.
 
L

Lew

Daniel said:
It does, but this doesn't [evaluate to true]:

Integer i = 128;
Integer j = 128;

boolean same = i == j;

One of the many joys of autoboxing.

Doesn't /necessarily/ evaluate to true. Does autoboxing use valueOf()?

If so, it might return cached values that actually would evaluate to the same
object for the same primitive value.

Of course, the key word is "might".
 
D

Daniel Dyer

Daniel said:
It does, but this doesn't [evaluate to true]:
Integer i = 128;
Integer j = 128;
boolean same = i == j;
One of the many joys of autoboxing.

Doesn't /necessarily/ evaluate to true. Does autoboxing use valueOf()?

If so, it might return cached values that actually would evaluate to the
same object for the same primitive value.

Of course, the key word is "might".

Yes, in practice 128 is not cached (at least by Sun's implementation), but
the JLS does allow for it to be:

http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5..1.7

<jls>
If the value p being boxed is true, false, a byte, a char in the range
\u0000 to \u007f, or an int or short number between -128 and 127, then let
r1 and r2 be the results of any two boxing conversions of p. It is always
the case that r1 == r2.

Discussion

Ideally, boxing a given primitive value p, would always yield an identical
reference. In practice, this may not be feasible using existing
implementation techniques. The rules above are a pragmatic compromise. The
final clause above requires that certain common values always be boxed
into indistinguishable objects. The implementation may cache these, lazily
or eagerly.

For other values, this formulation disallows any assumptions about the
identity of the boxed values on the programmer's part. This would allow
(but not require) sharing of some or all of these references.
</jls>
 
R

Roedy Green

Integer i = 128;
Integer j = 128;

boolean same = i == j;

Surely there is no need for an unbox.

Does the boxing use valueOf to shortcut share Integers with low values
or does it create two different 128 objects?

Some experiments are in order.
 
D

Daniel Pitts

Roedy said:
Surely there is no need for an unbox.

Does the boxing use valueOf to shortcut share Integers with low values
or does it create two different 128 objects?

Some experiments are in order.
I believe that Integer.valueOf will "intern" a certain range of values.
(possibly -128 to 127, but I don't know OTTOMH), The same is true about
the other primitive wrappers I believe.
 
L

Lew

Daniel said:
I believe that Integer.valueOf will "intern" a certain range of values.
(possibly -128 to 127, but I don't know OTTOMH), The same is true about
the other primitive wrappers I believe.

Daniel Dyer explained this fully in his post on this topic yesterday,
including a detailed citation from the JLS.
 
D

Daniel Pitts

Lew said:
Daniel Dyer explained this fully in his post on this topic yesterday,
including a detailed citation from the JLS.
Ah, must have missed that one.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
DewittMill
Top