Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / November 2006

Tip: Looking for answers? Try searching our database.

Why can a final(!) StringBuffer can be appended?

Thread view: 
Mize-ze - 16 Nov 2006 13:56 GMT
How could it be that I declare a StringBuffer to be final but when I
try to append it to something its value
changes to the appended value?

The StringBuffer is not re-created on the system (immutable right?) so
I don't understand how this "final" bits in the heap are modified

Thanks.
Robert Klemme - 16 Nov 2006 14:06 GMT
> How could it be that I declare a StringBuffer to be final but when I
> try to append it to something its value
> changes to the appended value?
>
> The StringBuffer is not re-created on the system (immutable right?) so
> I don't understand how this "final" bits in the heap are modified

"final" only refers to the reference, i.e. you cannot assign another
StringBuffer to the variable.  StringBuffer itself is mutable, i.e. can
be changed at any time.  If you want a fixed string you need to convert
it (easiest with toString()).

Kind regards

    robert
Mark Space - 16 Nov 2006 17:22 GMT
>> How could it be that I declare a StringBuffer to be final but when I
>> try to append it to something its value
[quoted text clipped - 11 lines]
>
>     robert

Or perhaps derive your own type of StringBuffer with the mutable methods
disabled.

Hmm, actually toString is probably best.  You can just change the String
back to a StringBuffer at any time, yes?  This seems the easiest...

Also, I've run into problems trying to change a StringBuffer when you
declare it's size on creation.  If append is specifically your problem,
you could get around it by setting the StringBuffer to be the exact size
you need.  Then appending will throw an exception if it's attempted.
Oliver Wong - 16 Nov 2006 21:03 GMT
> Also, I've run into problems trying to change a StringBuffer when you
> declare it's size on creation.  If append is specifically your problem,
> you could get around it by setting the StringBuffer to be the exact size
> you need.  Then appending will throw an exception if it's attempted.

   Are you sure? This program:

<SSCCE>
public class StringBTest {
public static void main(String[] args) {
 {
  StringBuffer sb = new StringBuffer(1);
  sb.append("More than 1 character.");
  System.out.println(sb.toString());
 }
 {
  StringBuilder sb = new StringBuilder(1);
  sb.append("More than 1 character.");
  System.out.println(sb.toString());
 }
}
}
</SSCCE>

Produces this output for me:

<output>
More than 1 character.
More than 1 character.
</output>

   - Oliver
Robert Klemme - 16 Nov 2006 22:49 GMT
> Or perhaps derive your own type of StringBuffer with the mutable methods
> disabled.

Not worth the effort IMHO unless you need to change often between
mutable and immutable.  But in that case I'd also add a flag which
switches mutability.  But since any client can set that flag...

> Hmm, actually toString is probably best.  You can just change the String
> back to a StringBuffer at any time, yes?  This seems the easiest...

Yes, although that change is less efficient because the String has to be
copied while StringBuffer.toString() creates a String that shares the
buffer.  That's optimized for the typical use case where you use a SB to
construct a String.

> Also, I've run into problems trying to change a StringBuffer when you
> declare it's size on creation.  If append is specifically your problem,
> you could get around it by setting the StringBuffer to be the exact size
> you need.  Then appending will throw an exception if it's attempted.

Huh?  Since when has a StringBuffer a size limit other than the RAM
available?

Regards

    robert
Daniel Pitts - 17 Nov 2006 00:41 GMT
> > Or perhaps derive your own type of StringBuffer with the mutable methods
> > disabled.
[quoted text clipped - 10 lines]
> buffer.  That's optimized for the typical use case where you use a SB to
> construct a String.

Somehow I doubt that a String shares a buffer with a StringBuffer,
since StringBuffer is still mutable, and the String is not.

Double checking the API source code, I see that String makes a copy of
the portion of the Array that is passed to it from
StringBuffer.toString().

Worrying too much about converting between Strings and StringBuffers is
one of the signs of the deadly sin known as "premature optimization".
After you've created your project, see if it runs fast enough, most
times it will.  If it doesn't run fast enough, run it through a
profiler, and optimize bigist time hog.

In most cases, StringBuffer is overkill anyway, String + String +
String is good enough.
Robert Klemme - 17 Nov 2006 10:21 GMT
>> Yes, although that change is less efficient because the String has to be
>> copied while StringBuffer.toString() creates a String that shares the
[quoted text clipped - 7 lines]
> the portion of the Array that is passed to it from
> StringBuffer.toString().

They changed that in 1.5.  In 1.4 it was shared.  The concept is know as
"copy on write".

> Worrying too much about converting between Strings and StringBuffers is
> one of the signs of the deadly sin known as "premature optimization".
> After you've created your project, see if it runs fast enough, most
> times it will.  If it doesn't run fast enough, run it through a
> profiler, and optimize bigist time hog.

I was not worrying I just made a side remark to indicate a potential
issue since I do not know the app at hand - so /if/ there is an issue
that's a potential place to look.

> In most cases, StringBuffer is overkill anyway, String + String +
> String is good enough.

Which is translated into StringBuffer.append() - or
StringBuilder.append() on 1.5 - unless of course all strings are constants.

Regards

    robert
Chris Uppal - 17 Nov 2006 12:24 GMT
> They changed that in 1.5.  In 1.4 it was shared.  The concept is know as
> "copy on write".

They didn't change it, it's the same in 1.5 as in 1.4 (and, as far as I
remember) all the previous versions too.

I haven't checked 1.6 or 1.7.

   -- chris
Robert Klemme - 17 Nov 2006 13:41 GMT
>> They changed that in 1.5.  In 1.4 it was shared.  The concept is know as
>> "copy on write".
>
> They didn't change it, it's the same in 1.5 as in 1.4 (and, as far as I
> remember) all the previous versions too.

I beg to differ.  JDK 1.4.2-11 (copy on write)

StringBuffer:

    public String toString() {
    return new String(this);
    }

    final void setShared() { shared = true; }
    final char[] getValue() { return value; }

String:

    public String (StringBuffer buffer) {
        synchronized(buffer) {
            buffer.setShared();
            this.value = buffer.getValue();
            this.offset = 0;
            this.count = buffer.length();
        }
    }

JDK 1.5.0-6 (always copy)

StringBuffer:

    public synchronized String toString() {
    return new String(value, 0, count);
    }

    public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        char[] v = new char[count];
        System.arraycopy(value, offset, v, 0, count);
        this.offset = 0;
        this.count = count;
        this.value = v;
    }

Regards

    robert
Chris Uppal - 17 Nov 2006 15:04 GMT
> > > They changed that in 1.5.  In 1.4 it was shared.  The concept is know
> > > as "copy on write".
[quoted text clipped - 3 lines]
>
> I beg to differ.

My apologies, yes you are right.

Thanks for the correction.

   -- chris
Mark - 16 Nov 2006 14:10 GMT
> How could it be that I declare a StringBuffer to be final but when I
> try to append it to something its value
> changes to the appended value?
>
> The StringBuffer is not re-created on the system (immutable right?)

StringBuffers are mutable: its their big difference from Strings
> so I don't understand how this "final" bits in the heap are modified

(One of) the meaning(s) of "final" is that the reference can't change
(so you can't change what it is by assigning a new StringBuffer to it),
but the object can, assuming it has methods that allow it to change
like StringBuffer and Java5's StringBuilder  do.

> Thanks.

HTH,
Mark


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.