java - how the subString() function of string class works - Stack Overflow
Java substring new to learning - Stack Overflow
The String.substring() in java - Stack Overflow
How to correctly use the substring method? (Java)
Videos
As pointed out by Pete Kirkham, this is implementation specific. My answer is only correct for the Sun JRE, and only prior to Java 7 update 6.
You're right about a normal substring call just creating a new string referring to the same character array as the original string. That's what happens on line 5 too. The fact that the new string object reference happens to be assigned to a variable doesn't change the behaviour of the method.
Just to be clear, you say that in line 2 the new string will still point to "Monday" - the char array reference inside the string will be to the same char array as one used for "Monday". But "Monday" is a string in itself, not a char array. In other words, by the time line 2 has finished (and ignoring GC) there are two string objects, both referring to the same char array. One has a count of 6 and the other has a count of 3; both have an offset of 0.
You're wrong about line 4 using a "string pool" though - there's no pooling going on there. However, it is different to the other lines. When you call the String(String) constructor, the new string takes a copy of the character data of the original, so it's completely separate. This can be very useful if you only need a string which contains a small part of a very large original string; it allows the original large char array to be garbage collected (assuming nothing else needs it) while you hold onto the copy of the small portion. A good example of this in my own experience is reading lines from a line. By default, BufferedLineReader will read lines using an 80-character buffer, so every string returned will use a char array of at least 80 characters. If you're reading lots of very short lines (single words) the difference in terms of memory consumption just through the use of the odd-looking
line = new String(line);
can be very significant.
Does that help?
I know that line 2 will still point to "Monday" and have a new String object with the offset and count set to 0,3.
That is currently true of the Sun JRE implementation. I seem to recall that was not true of the Sun implementation in the past, and is not true of other implementations of the JVM. Do not rely on behaviour which is not specified. GNU classpath might copy the array (I can't remember off hand what ratio is uses to decide when to copy, but it does copy if the copy is a small enough fraction of the original, which turned one nice O(N) algorithm to O(N^2)).
The line 4 will create a new String "Mon" in string pool and point to it.
No, it creates a new string object in the heap, subject to the same garbage collection rules as any other object. Whether or not it shares the same underlying character array is implementation dependant. Do not rely on behaviour which is not specified.
The String(String) constructor says:
Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string.
The String(char[]) constructor says:
Allocates a new String so that it represents the sequence of characters currently contained in the character array argument. The contents of the character array are copied; subsequent modification of the character array does not affect the newly created string.
Following good OO principles, no method of String actually requires that it is implemented using a character array, so no part of the specification of String requires operations on an character array. Those operations which take an array as input specify that the contents of the array are copied to whatever internal storage is used in the String. A string could use UTF-8 or LZ compression internally and conform to the API.
However, if your JVM doesn't make the small-ratio sub-string optimisation, then there's a chance that it does copy only the relevant portion when you use new String(String), so it's a case of trying it a seeing if it improves the memory use. Not everything which effects Java runtimes is defined by Java.
To obtain a string in the string pool which is equal to a string, use the intern() method. This will either retrieve a string from the pool if one with the value already has been interned, or create a new string and put it in the pool. Note that pooled strings have different (again implementation dependent) garbage collection behaviour.
For example. In the following string we have 6 characters. So if you call .length() on the string it will return 6. Note that its indices will range from 0 to 5 (not to 6).
"A tree"
The indices would be like the following:
0 -> 'A'
1 -> ' '
2 -> 't'
3 -> 'r'
4 -> 'e'
5 -> 'e'
Using substring you can get a part of this string. Your result will be starting at the specifed begin index and will end at the specified end index.
Important:
The start index is inclusive, while the end index is exclusive.
Which means that if we use substring from 2 to 4, we won't get "tre". We will get "tr", since the end index is not included.
Programmers often use excluded end indices, since it is easier to work with them. For example. Imagine our string "A tree" is called s like this:
String s = "A tree";
if you would want everything starting at index 2 you could do:
String result = s.substring(2, s.length()); // Result would also be 'tree' for this example
If the end index wouldn't be exclusive you would need to write:
String result = s.substring(2, s.length() - 1); // This is an example that would return "tree", IF and only if end indices wouldn't be excluded
That is why programmers often exclude the end index.
Of corse if you want to start at a certain index and want to go till the end you don't need to use
String result = s.substring(2, s.length()); // Result would also be 'tree' for this example
but instead you could use the alternative version of substring, where you only provide a begin index and not an end index. Like this:
String result = s.substring(2); // Result would also be 'tree' for this example
Please take a look at the documentation for
- substring(int, int) -> https://docs.oracle.com/javase/9/docs/api/java/lang/String.html#substring-int-int-
- substring(int) -> https://docs.oracle.com/javase/9/docs/api/java/lang/String.html#substring-int-
String text = "abcxyz";
The substring is on a loop so at the first pass text will be equal to :
System.out.println(text.substring(0, 0 + 3)); // abc
At the second pass :
System.out.println(text.substring(1, 1 + 3)); // bcx
Etc.
substring method throws the StringIndexOutOfBoundsException only when the beginIndex is greater than the length of the string as shown in the below code (taken from String class substring method):
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
Also, the same has been explained in the Javadoc as well, you can look here:
Returns a new string that is a substring of this string. The substring begins with the character at the specified index and extends to the end of this string. Examples:
"unhappy".substring(2) returns "happy"
"Harbison".substring(3) returns "bison"
"emptiness".substring(9) returns "" (an empty string)
string.substring(int id) returns a substring of the string which starts at index id. id is an index, but not the position!
Remember, indexes start counting from 0! Please, check the Javadoc.
The part of subString method looks like this:
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}