File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Java in General and the fly likes When to use new String( Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Soft Skills this week in the Jobs Discussion forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "When to use new String("") against string literal" Watch "When to use new String("") against string literal" New topic
Author

When to use new String("") against string literal

Anand Kane
Greenhorn

Joined: Mar 15, 2005
Posts: 10
1. When you need to create string as a ThreadLocal.
2. When a string is doesnt have to be living throughout the life of JVM. If you have a code that creates too many strings (in a loop for eg) and this is code is run highly infrequently in application life time, it is perhaps preferable to create strings on heap and let them be garbage collector in next GC run.

I do not have any suitable example for the second point. Members are requested to share their thoughts on second point.

Thanks
Anand
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19784
    
  20

Anand Kane wrote:1. When you need to create string as a ThreadLocal.

Which you should never have to do. Strings are immutable so they can be shared among many threads without any problems.

2. When a string is doesnt have to be living throughout the life of JVM. If you have a code that creates too many strings (in a loop for eg) and this is code is run highly infrequently in application life time, it is perhaps preferable to create strings on heap and let them be garbage collector in next GC run.

But the String literal used to construct the String is still stored in the String pool. If you need a short-term String and want it to be garbage collected you probably want to use another String constructor, like the String(char[], ...), String(StringBuilder) or String(StringBuffer) ones.

Even the API itself discourages use of the String(String) constructor:
Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.
And I cannot think of any reason why an explicit copy would ever be needed.
Ninad Kulkarni
Ranch Hand

Joined: Aug 31, 2007
Posts: 802

Hi Anand,

String is a object it is always created on heap. String literal specially handled by JVM. String literal is referenced through String literal pool. String literal pool holds reference of string object which is available on heap.
See this for more information.


SCJP 5.0 - JavaRanch FAQ - Java Beginners FAQ - SCJP FAQ - SCJP Mock Tests - Tutorial - JavaSE7 - JavaEE6 -Generics FAQ - JLS - JVM Spec - Java FAQs - Smart Questions
Mike Simmons
Ranch Hand

Joined: Mar 05, 2008
Posts: 3018
    
  10
I'm going to guess that this question is about using new String(String) in general, not new String("") in particular. Because there is really never any reason to call new String("") with a zero-length argument; just use "". However if this was shorthand for the constructor that creates a String from another String, there is on rare occasions an actual use for this. Read on...

Rob Spoor wrote:
Anand Kane wrote:1. When you need to create string as a ThreadLocal.

Which you should never have to do. Strings are immutable so they can be shared among many threads without any problems.

Unless the point of using the ThreadLocal is that you want different threads to see different values. Then it may be perfectly reasonable to have a ThreadLocal<String>. There is still no use here for the new String(String) constructor however.

Rob Spoor wrote:Even the API itself discourages use of the String(String) constructor:
Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.
And I cannot think of any reason why an explicit copy would ever be needed.

Aside from teaching examples, say for discussing garbage collection, there is only one real use for this constructor - but it's a legitimate one: Sometimes you need to reduce the memory usage of the data before you save it (e.g. in a Collection of some sort).

For example, if you have a large file with one record per line, and each line is fairly long, but you just want to extract the first 8 characters on each line - let's say it represents an id. And you want to make a list of all ids in the file. A reasonable approach might be this:

However, this may have a problem: it uses much more memory than it needs to. The reason is that the line variable gets a String representing the entire line, with a backing array of char[] containing characters from the entire line. And the substring() method creates a new String representing just the first 6 characters - but that new String actually shares the same backing array that the original line did. Even though the later characters are not visible as part of the new String, they are there in the JVM, taking up space.

The authors of String did this as a speed optimization - substring() can return quicker if it doesn't have to create a completely new char[] and copy the old data to the new array. But it's a tradeoff, memory for speed, and sometimes it turns out you need the memory more than the speed. In this case, the problem can be fixed with new String(String):

This runs a little slower. But each new String is exactly as big as it needs to be, no more, and the old line string is available for GC at the end of each iteration of the loop.
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19784
    
  20

Rob Spoor wrote:And I cannot think of any reason why an explicit copy would ever be needed.

Congrats Mike, you just gave a valid reason
Jesper de Jong
Java Cowboy
Saloon Keeper

Joined: Aug 16, 2005
Posts: 14430
    
  23

Ok Mike, that's a valid reason to use the new String(String) constructor.

But Anand's title for this topic is "When to use new String("") against string literal" which explicitly mentions using new String("some literal") - with a string literal.

Like Rob I don't know of any legitimate use of this String constructor with a string literal. Anand's reason number 2 is incorrect:
Anand Kane wrote:2. When a string is doesnt have to be living throughout the life of JVM. If you have a code that creates too many strings (in a loop for eg) and this is code is run highly infrequently in application life time, it is perhaps preferable to create strings on heap and let them be garbage collector in next GC run.

The literal is in the string pool anyway, so it will never be cleaned up during the lifetime of the JVM, and making a copy of the literal string doesn't make sense since it's immutable anyway - it's more efficient to just use the literal directly.

I suspect that Anand's reason 2 actually is about the use case that Mike mentioned, but that is not about using string literals with the new String() constructor.


Java Beginners FAQ - JavaRanch SCJP FAQ - The Java Tutorial - Java SE 8 API documentation
Anand Kane
Greenhorn

Joined: Mar 15, 2005
Posts: 10
Thank you all for the responses. And my apologies that the title seems to have created some confusion. I did not mean String("") constructor specifically. I meant any String constructor against literal.

Originally my intention was to initiate the discussion on this and it has been met. When I searched about this on net and could not find anything, thought there should be something. However, the discussion above leads me to belive that the code

String s = new String("abcd");

creates string instance in pool anyway. But my understanding is that it creates String on heap that is eligible for garbage collection. So, does it mean that the code creates two instances? Or is my understanding incorrect? Please comment.

Thanks
Anand
Jesper de Jong
Java Cowboy
Saloon Keeper

Joined: Aug 16, 2005
Posts: 14430
    
  23

When you do this:

String s = new String("abcd");

then there will be two String objects: one for the literal "abcd", which will be in the string pool, and another one, which will not be in the string pool, that is a copy of the first String object. The second one will be eligible for garbage collection, but the first one (for the literal) will remain in memory until the JVM exits.

Since String objects are immutable (you cannot change the content of a String object after it has been constructed), it's almost never necessary to make a copy of a String object - the copy will always have the exact same content as the original String object, so you might just as well not make the copy and just use the original String object. Mike shows a special case where you'd want to make a copy of a String object, but that doesn't involve a literal string.

The conclusion is that a statement like new String("some literal"); is never necessary and only wastes memory.
adithya narayan
Ranch Hand

Joined: Jan 05, 2009
Posts: 79

Mike Simmons wrote:
For example, if you have a large file with one record per line, and each line is fairly long, but you just want to extract the first 8 characters on each line - let's say it represents an id. And you want to make a list of all ids in the file. A reasonable approach might be this:
view plaincopy to clipboardprint?



However, this may have a problem: it uses much more memory than it needs to. The reason is that the line variable gets a String representing the entire line, with a backing array of char[] containing characters from the entire line. And the substring() method creates a new String representing just the first 6 characters - but that new String actually shares the same backing array that the original line did. Even though the later characters are not visible as part of the new String, they are there in the JVM, taking up space.

The authors of String did this as a speed optimization - substring() can return quicker if it doesn't have to create a completely new char[] and copy the old data to the new array. But it's a tradeoff, memory for speed, and sometimes it turns out you need the memory more than the speed. In this case, the problem can be fixed with new String(String):
view plaincopy to clipboardprint?


This runs a little slower. But each new String is exactly as big as it needs to be, no more, and the old line string is available for GC at the end of each iteration of the loop.


I am not understanding this approach. In the solution we are still calling the subString() method, so in that case too the JVM will still preserve the trailing characters in the pool as well as in the non-pool memory(I guess the subString() method will create two objects ; 1 in non-pool memory and 1 in pool memory . Please correct me if i am wrong). So,how does calling the String(string) help save memory ?


Thanks,
Adithya.
Stephan van Hulst
Bartender

Joined: Sep 20, 2010
Posts: 3649
    
  17

The long lines read from the file are not added to the String pool. When calling substring, the new Strings will refer to the same array as the original lines, so even when the original Strings are garbage collected, the backing array is not, because it's still referenced by the substrings. These arrays are way too long, because you only need the first few characters, and the rest is junk. Making new Strings from these substrings will apparently create new arrays, to which only the necessary characters are copied. Then, the old backing arrays are eligible for garbage collection.
adithya narayan
Ranch Hand

Joined: Jan 05, 2009
Posts: 79

For example,

If the line was

It would actually be appending the whole line again in the form of an character array ? i.e.


and when we call method ,we actually would get something like
'System' which will be visible and 'System.out.println("end date = "+date);' this char[] array will be appended to the string created using the subString() method which is actually present in the memory but not visible to the user ?

Is my interpretation correct ? Why does this behavior even exist ?Was there any requirement to implement it in this fashion ?

Thanks,
Adithya.
Mike Simmons
Ranch Hand

Joined: Mar 05, 2008
Posts: 3018
    
  10
adithya narayan wrote:Is my interpretation correct ?

Um, I don't think so. But honestly, I can barely tell what you're thinking. It's possible you understand perfectly, but I can't tell from your description. Sorry.

adithya narayan wrote:Why does this behavior even exist ?Was there any requirement to implement it in this fashion ?

The behavior of subset() was probably chosen to provide the best possible speed (by avoiding the need to allocate a new char[] array and copy its contents) with an unfortunate side effect of using more memory than necessary - in some situations. It's difficult, and often impossible, to design a method to provide the best possible behavior under all possible conditions. Sometimes you need to memorize memory usage, and sometimes you need to minimize execution time. And sometimes other things.
adithya narayan
Ranch Hand

Joined: Jan 05, 2009
Posts: 79

Well,it would be more clear if you could explain it with an example i.e. what the contents of the object(s) look like after each operation.

Thanks,
Adithya.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: When to use new String("") against string literal