Is this creating 12 string objects? - java

I'm trying to understand if this code below creates 12 objects for a string like "stephan"
public String reverse(String str) {
if ((null == str) || (str.length() <= 1)) {
return str;
}
return reverse(str.substring(1)) + str.charAt(0);
}
This recursively reverses a string. I understand how it works. But I was thinking if there is a relationship in this case between the length of the strings and number of string objects created through concatenation?

Yes, it will create tons of string objects.
Every recursive call to "reverse()" will create 2:
str.substring(1) will create a new String object
reverse() call will create a new string for its return value, but we will NOT count that since that's counted when analyzing that recursive call (e.g. it will be the string from bullet point #3 from the next reverse() call).
And since Java Strings are immutable, adding a char via "+" will create a second String object.
Therefore, for a string of length N, it will create (N-1)*2 objects (since a reverse of 1-char string does NOT create new strings); so for "stephan"'s 7 characters, it will create 6*2=12 string objects.

Theorem:
When a string is N characters long, #Phoenix's reverse implementation will create (N-1)*3 new objects.
Proof (by induction):
When str is 1 character long, it is returned directly. (1*1)*3 = 0.
When str is N characters long:
a new String will be created by .substring(1).
by the induction hypothesis, the call to reverse(...) will be returned after (N-2)*3 objects have been created.
a new StringBuilder will be created to append the string and first char (you can see this by de-compiling your byte-code).
a new String will be created by StringBuilder.toString()--this is the return value.
Altogether, there were 3 + (N-2)*3 = (N-2 + 1)*3 = (N-1)*3 objects created.
QED.
[Edit] StringBuilders:
StringBuilder (extending AbstractStringBuilder) does its own fancy footwork:
When an StringBuilder is constructed, it is initialized with a char[] of size 16.
When you append something more than it's present size, it throws that away and creates a new char[] of size (<old size> + <size of new data> + 1) * 2.
So, as soon as your input string is > 16 characters, you have essentially 2x as much StringBuilder capacity as you need. (When the input string size is less, you've got more char[] than you need.)
Considering Strings are essentially char[]s (with a few ints for good measure), you're effectively using 4 times the length of the substring in char[]s -- at each step. :(

Related

Java String Concatenation using '+' operator [duplicate]

This question already has answers here:
String concatenation: concat() vs "+" operator
(12 answers)
Closed 1 year ago.
What does actually happens when we concatenate a string S2 of size Y to a string S1 of size X ( already present on the heap) using the + operator?
This is what I think:
If I execute the following function:
class StringConcatenation{
String S1;
String concat(String S2){
this.S1 = this.S1 + S2;
}
}
If S1 was present in the string pool (which is stored in the heap) and we execute the concat method, then the method gets executed on the stack.
So, the CPU will need to copy the S1 in the stack => READ S1
As strings are immutable, Java must make a new object (let's name its reference as S3).
Now, contents of S1 and S2 are copied at new object => COPY S1 + COPY S2
Then the reference S1 points to the new object.
Therefore, the total time complexity is O(READ S1 + COPY S1 + COPY S2 ) = O(X + X + Y) = O(2*X + Y).
Is my thought process correct?
in the doc you can read:
The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method.
a = a + b is the equivalent of a += b or:
a = new StringBuilder()
.append(a)
.append(b)
.toString();
Disclaimer: The String class has undergone multiple changes to improve performance and space utilization. What happens when JIT compiles code is then entirely undefined. The following is a simplification, and ignores any optimizations that may or may not be applied.
String is a class that encapsulates a char[]. The array length is always exactly the length() of the string. The class, and the underlying array, is immutable.
class String {
private final char[] arr;
}
StringBuilder (and StringBuffer) is another class that encapsulates a char[], but the array is almost always larger than the number of characters in the array. The class, and the array, is mutable.
class StringBuilder {
private char[] arr;
private int len;
}
When you do string concatenation with the + operator, the compiler generates that as:
// Java code
s = s1 + s2 + s3;
// Generated code
s = new StringBuilder().append(s1).append(s2).append(s3).toString();
StringBuilder will initially create the array with length 16, and will re-allocate the array when needed. Worst case is that s1, s2, and s3 are all too large for the current array, so each append() call needs to re-size the array.
This means that the would progress as follows:
new StringBuilder() - Creates char[16].
append(s1) - Resizes arr, then copies chars from s1.arr to the array.
append(s2) - Resizes arr, copies existing content (chars from s1) to new array, then copies chars from s2.arr to the array.
append(s3) - Resizes arr, copies existing content (chars from s1 and s2) to new array, then copies chars from s3.arr to the array.
toString() - Create new String with char[] sized to exactly fit the characters in the StringBuilder, then copies the content (chars from s1, s2, and s3) to the new String.
All-in-all the chars from s1 ends up being copied 4 times.
If the string concatenation is S1 + S2, like in the question, then the characters from S1 are copied 2 or 3 times, and the characters from S2 are copied 2 times.
Since time complexity is generally worst case, that means O(3m + 2n), not the O(2m + n) suggested in the question. Of course, Big-O eliminates constant factors, so it is actually O(m + n).

Converting an integer and a character to a string in java

I'm trying to create a string comprised of a single letter, followed by 4 digits e.g. b6789. I'm getting stuck when I try to convert a character, and integer to one String. I can't use toString() because I've overwritten it, and I assume that concatenation is not the best way to approach it? This was my solution, until I realised that valueof() only takes a single parameter. Any suggestions? FYI - I'm using Random, because I will be creating multiples at some point. The rest of my code seemed irrelevant, and hence has been omitted.
Random r = new Random();
Integer numbers = r.nextInt(9000) + 1000;
Character letter = (char)(r.nextInt(26) + 'a');
String strRep = String.valueOf(letter, numbers);
I think they mean for you not to use concatenation with + operator.
Rather than that, there's a class called StringBuilder which will do the trick for you. Just create an empty one, append anything you need on it (takes Objects or primitives as arguments and does all the work for you), and at the end, just call at its "toString()" method, and you'll have your concatenated String.
For example
StringBuilder sb = new StringBuilder();
sb.append("Foo");
sb.append(123);
return sb.toString();
would return the string Foo123
you can use:
Character.toString(char)
which is
String.valueOf(char)
in reality which also works.
or just use
String str = "" + 'a';
as already mentioned but not very efficient as it is
String str = new StringBuilder().append("").append('a').toString();
in reality.
same goes for integer + string or char + int to string. I think your simpliest way would be to use string concatenation
Looks like you want
String.valueOf(letter).concat(numbers.toString());

Delete char at position in string

Currently, I am working on a project that requires to delete a char at a set position in a string. Is there a simple way to do this?
Use a StringBuilder, which has the method deleteCharAt(). Then, you can just use stringBuilder.toString() to get your string.
EDIT, here's an example:
public static void main(String[] args) {
String string = "bla*h";
StringBuilder sb = new StringBuilder(string);
sb.deleteCharAt(3);
// Prints out "blah"
System.out.println(sb.toString());
}
Strings are immutable ! But to accomplish your task, you can
Copy the substring from the start of the string to the character that has to be deleted
Copy the substring from the character that has to be deleted to the end of the String.
Append the second String to the first one.
For example, let's say you have to remove the third character:
String input = "Hello, World";
String first = input.substring(0, 3);
String second = input.substring(4);
String result = first + second;
You can convert your string to StringBuilder, which have convinient deletaCharAt method.
String strWithoutChar = new StringBuilder(yourString).deleteCharAt(yourIndex).toString();
But keep in mind, this gives to you ability to remove some boilerplate code, but it takes more memory in compassion to using String#substring method.
The way you would do this is by copying the oldstring into a newstring, being careful to remove the one character, like so:
String newString = oldString.substring(0, index) + oldString.substring(index+1);
Keep in mind that if you are doing this several times, constantly making new strings is rather inefficient.
Whatever is being said here by fellow scholars, I agree to them that it gives the correct answer. But if you are dealing with a production level program where every loophole gets magnified, I would suggest you to not use "Substring" method of string because:
(1). substring method actually leaves the parent string unflagged for garbage collector. Due to this garbage collector cannot clean it up in its process, the heap space gets occupied and unused parent strings still remains to exist in the heap space even when it is\ not in use.
(2). If you deal with a number of string manipulations such as these, it may eventually result in 'Out of Heap Memory' exception which is not desirable at any point in time in the program.
Use char array and its manipulations to achieve what you want :
public static void fn1()
{
String a = "Stack Overflow";
char[] b = a.toCharArray();
j // index position of the character that you want to delete
for(int i=j;i<b.length-1;i++)
{
b[i]=b[i+1];
}
b[b.length-1]='\000'; // '\000' is the null character
System.out.println(new String(b));
}
An alternative is to use the substring method but using concat instead of +
String removeCharAt(String s, int index) {
return s.substring(0, index).concat(s.substring(index + 1));
}

Should StringBuilders always be used for string manipulation? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
when to use StringBuilder in java
If not which of these pieces of code is better and why
public String backAround(String str) {
int len = str.length();
StringBuilder sb = new StringBuilder(str);
char chEnd = sb.charAt(len-1);
if(len > 0){
sb = sb.append(chEnd);
sb= sb.insert(0,chEnd);
str= sb.toString();
return str;
}else{ return str;}
}
or
public String backAround(String str) {
// Get the last char
String back = str.substring(str.length()-1, str.length());
return back + str + back;
}
If you are just "sticking a few elements together" as in your backAround() method, you may as well just use the + notation. The compiler will convert this into appropriate StringBuilder.append()s for you, so why bother 'spelling things out'.
The idea of explicitly using StringBuilder is that in principle you can hand-optimise how exactly the elements are appended to the string, including setting the initial buffer capacity and ensuring that you don't accidentally create intermediate String objects that are unnecessary in cases where the compiler might not predict these things.
So essentially, explicitly use a StringBuilder when there is slightly more complex logic to deciding what to append to the string. For example, if you are appending things in a loop, or where what is appended depends on various conditions at different points. Another case where you might use StringBuilder is if the string needs to be built up from various methods, for example: you can then pass the StringBuilder into the different methods and ask them to append the various elements.
P.S. I should say that StringBuilder buys you a little more editing power as well (e.g. among other things, you can set its length) and, given the presence of the Appendable interface, you can actually create more generic methods that either append to a StringBuilder or to e.g. a StringWriter. But these are marginal cases, I would submit.
It really depends on what you are trying to do. In your case it seems like your trying to take a string and take the last letter and add it to the front and then add another to the end. For this i would probably do this:
public String manipulate(String string)
{
char c = string.charAt(string.length);
return c + string + c;
}
In this case you didn't have to use a StringBuilder. There are cases where the StringBuilder class is useful. Here are some things that are hard to do with a String that StringBuilder can do:
delete chars at an index
append chars at an index
get the index of a specific sequence
and much much more
if you want to see the documentation for StringBuilder:
String Builder
I hope this helped you out!

What is the difference between String and String Buffer? [duplicate]

What is the difference between String and StringBuffer in Java?
Is there a maximum size for String?
String is used to manipulate character strings that cannot be changed (read-only and immutable).
StringBuffer is used to represent characters that can be modified.
Performance wise, StringBuffer is faster when performing concatenations. This is because when you concatenate a String, you are creating a new object (internally) every time since String is immutable.
You can also use StringBuilder which is similar to StringBuffer except it is not synchronized. The maximum size for either of these is Integer.MAX_VALUE (231 - 1 = 2,147,483,647) or maximum heap size divided by 2 (see How many characters can a Java String have?).
More information here.
A String is immutable, i.e. when it's created, it can never change.
A StringBuffer (or its non-synchronized cousin StringBuilder) is used when you need to construct a string piece by piece without the performance overhead of constructing lots of little Strings along the way.
The maximum length for both is Integer.MAX_VALUE, because they are stored internally as arrays, and Java arrays only have an int for their length pseudo-field.
The performance improvement between Strings and StringBuffers for multiple concatenation is quite significant. If you run the following test code, you will see the difference. On my ancient laptop with Java 6, I get these results:
Concat with String took: 1781ms
Concat with StringBuffer took: 0ms
public class Concat
{
public static String concatWithString()
{
String t = "Cat";
for (int i=0; i<10000; i++)
{
t = t + "Dog";
}
return t;
}
public static String concatWithStringBuffer()
{
StringBuffer sb = new StringBuffer("Cat");
for (int i=0; i<10000; i++)
{
sb.append("Dog");
}
return sb.toString();
}
public static void main(String[] args)
{
long start = System.currentTimeMillis();
concatWithString();
System.out.println("Concat with String took: " + (System.currentTimeMillis() - start) + "ms");
start = System.currentTimeMillis();
concatWithStringBuffer();
System.out.println("Concat with StringBuffer took: " + (System.currentTimeMillis() - start) + "ms");
}
}
String StringBuffer
Immutable Mutable
String s=new String("karthik"); StringBuffer sb=new StringBuffer("karthik")
s.concat("reddy"); sb.append("reddy");
System.out.println(s); System.out.println(sb);
O/P:karthik O/P:karthikreddy
--->once we created a String object ---->once we created a StringBuffer object
we can't perform any changes in the existing we can perform any changes in the existing
object.If we are trying to perform any object.It is nothing but mutablity of
changes with those changes a new object of a StrongBuffer object
will be created.It is nothing but Immutability
of a String object
Use String--->If you require immutabilty
Use StringBuffer---->If you require mutable + threadsafety
Use StringBuilder--->If you require mutable + with out threadsafety
String s=new String("karthik");
--->here 2 objects will be created one is heap and the other is in stringconstantpool(scp) and s is always pointing to heap object
String s="karthik";
--->In this case only one object will be created in scp and s is always pointing to that object only
String is an immutable class. This means that once you instantiate an instance of a string like so:
String str1 = "hello";
The object in memory cannot be altered. Instead you will have to create a new instance, copy the old String and append whatever else as in this example:
String str1 = "hello";
str1 = str1 + " world!";
What is really happening hear is that we are NOT updating the existing str1 object... we are reallocating new memory all together, copying the "hello" data and appending " world!" to the end, then settings the str1 reference to point to this new memory. So it really looks more like this under the hood:
String str1 = "hello";
String str2 = str1 + " world!";
str1 = str2;
So it follows that this "copy + paste and move stuff around in memory" process can be very expensive if done repitively especially recursively.
When you are in that situation of having to do things over and over utilize StringBuilder. It is mutable and can append strings to the end of the current one because it's back by an [growing array] (not 100% if that is the actual data structure, could be a list).
From the API:
A thread-safe, mutable sequence of characters. A string buffer is like a String, but can be modified. At any point in time it contains some particular sequence of characters, but the length and content of the sequence can be changed through certain method calls.
A StringBuffer is used to create a single string from many strings, e.g. when you want to append parts of a String in a loop.
You should use a StringBuilder instead of a StringBuffer when you have only a single Thread accessing the StringBuffer, since the StringBuilder is not synchronized and thus faster.
AFAIK there is no upper limit for String size in Java as a language, but the JVMs probably have an upper limit.
I found interest answer for compare performance String vs StringBuffer by Reggie Hutcherso
Source: http://www.javaworld.com/javaworld/jw-03-2000/jw-0324-javaperf.html
Java provides the StringBuffer and String classes, and the String class is used to manipulate character strings that cannot be changed. Simply stated, objects of type String are read only and immutable. The StringBuffer class is used to represent characters that can be modified.
The significant performance difference between these two classes is that StringBuffer is faster than String when performing simple concatenations. In String manipulation code, character strings are routinely concatenated. Using the String class, concatenations are typically performed as follows:
String str = new String ("Stanford ");
str += "Lost!!";
If you were to use StringBuffer to perform the same concatenation, you would need code that looks like this:
StringBuffer str = new StringBuffer ("Stanford ");
str.append("Lost!!");
Developers usually assume that the first example above is more efficient because they think that the second example, which uses the append method for concatenation, is more costly than the first example, which uses the + operator to concatenate two String objects.
The + operator appears innocent, but the code generated produces some surprises. Using a StringBuffer for concatenation can in fact produce code that is significantly faster than using a String. To discover why this is the case, we must examine the generated bytecode from our two examples. The bytecode for the example using String looks like this:
0 new #7 <Class java.lang.String>
3 dup
4 ldc #2 <String "Stanford ">
6 invokespecial #12 <Method java.lang.String(java.lang.String)>
9 astore_1
10 new #8 <Class java.lang.StringBuffer>
13 dup
14 aload_1
15 invokestatic #23 <Method java.lang.String valueOf(java.lang.Object)>
18 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)>
21 ldc #1 <String "Lost!!">
23 invokevirtual #15 <Method java.lang.StringBuffer append(java.lang.String)>
26 invokevirtual #22 <Method java.lang.String toString()>
29 astore_1
The bytecode at locations 0 through 9 is executed for the first line of code, namely:
String str = new String("Stanford ");
Then, the bytecode at location 10 through 29 is executed for the concatenation:
str += "Lost!!";
Things get interesting here. The bytecode generated for the concatenation creates a StringBuffer object, then invokes its append method: the temporary StringBuffer object is created at location 10, and its append method is called at location 23. Because the String class is immutable, a StringBuffer must be used for concatenation.
After the concatenation is performed on the StringBuffer object, it must be converted back into a String. This is done with the call to the toString method at location 26. This method creates a new String object from the temporary StringBuffer object. The creation of this temporary StringBuffer object and its subsequent conversion back into a String object are very expensive.
In summary, the two lines of code above result in the creation of three objects:
A String object at location 0
A StringBuffer object at location 10
A String object at location 26
Now, let's look at the bytecode generated for the example using StringBuffer:
0 new #8 <Class java.lang.StringBuffer>
3 dup
4 ldc #2 <String "Stanford ">
6 invokespecial #13 <Method java.lang.StringBuffer(java.lang.String)>
9 astore_1
10 aload_1
11 ldc #1 <String "Lost!!">
13 invokevirtual #15 <Method java.lang.StringBuffer append(java.lang.String)>
16 pop
The bytecode at locations 0 to 9 is executed for the first line of code:
StringBuffer str = new StringBuffer("Stanford ");
The bytecode at location 10 to 16 is then executed for the concatenation:
str.append("Lost!!");
Notice that, as is the case in the first example, this code invokes the append method of a StringBuffer object. Unlike the first example, however, there is no need to create a temporary StringBuffer and then convert it into a String object. This code creates only one object, the StringBuffer, at location 0.
In conclusion, StringBuffer concatenation is significantly faster than String concatenation. Obviously, StringBuffers should be used in this type of operation when possible. If the functionality of the String class is desired, consider using a StringBuffer for concatenation and then performing one conversion to String.
By printing the hashcode of the String/StringBuffer object after any append operation also prove, String object is getting recreated internally every time with new values rather than using the same String object.
public class MutableImmutable {
/**
* #param args
*/
public static void main(String[] args) {
System.out.println("String is immutable");
String s = "test";
System.out.println(s+"::"+s.hashCode());
for (int i = 0; i < 10; i++) {
s += "tre";
System.out.println(s+"::"+s.hashCode());
}
System.out.println("String Buffer is mutable");
StringBuffer strBuf = new StringBuffer("test");
System.out.println(strBuf+"::"+strBuf.hashCode());
for (int i = 0; i < 10; i++) {
strBuf.append("tre");
System.out.println(strBuf+"::"+strBuf.hashCode());
}
}
}
Output:
It prints object value along with its hashcode
String is immutable
test::3556498
testtre::-1422435371
testtretre::-1624680014
testtretretre::-855723339
testtretretretre::2071992018
testtretretretretre::-555654763
testtretretretretretre::-706970638
testtretretretretretretre::1157458037
testtretretretretretretretre::1835043090
testtretretretretretretretretre::1425065813
testtretretretretretretretretretre::-1615970766
String Buffer is mutable
test::28117098
testtre::28117098
testtretre::28117098
testtretretre::28117098
testtretretretre::28117098
testtretretretretre::28117098
testtretretretretretre::28117098
testtretretretretretretre::28117098
testtretretretretretretretre::28117098
testtretretretretretretretretre::28117098
testtretretretretretretretretretre::28117098
A StringBuffer or its younger and faster brother StringBuilder is preferred whenever you're going do to a lot of string concatenations in flavor of
string += newString;
or equivalently
string = string + newString;
because the above constructs implicitly creates new string everytime which will be a huge performance and drop. A StringBuffer / StringBuilder is under the hoods best to be compared with a dynamically expansible List<Character>.
A String is an immutable character array.
A StringBuffer is a mutable character array. Often converted back to String when done mutating.
Since both are an array, the maximum size for both is equal to the maximum size of an integer, which is 2^31-1 (see JavaDoc, also check out the JavaDoc for both String and StringBuffer).This is because the .length argument of an array is a primitive int. (See Arrays).
String is immutable, meaning that when you perform an operation on a String you are really creating a whole new String.
StringBuffer is mutable, and you can append to it as well as reset its length to 0.
In practice, the compiler seems to use StringBuffer during String concatenation for performance reasons.
String is immutable.
Why? Check here.
StringBuffer is not. It is thread safe.
Further questions like when to use which and other concepts can be figured out following this.
Hope this helps.
While I understand that this is not a major differentiating factor, I noticed today that StringBuffer(and StringBuilder) provides some interesting methods that String doesn't.
reverse()
setCharAt()
The differences are
Only in String class + operator is overloaded. We can concat two String object using + operator, but in the case of StringBuffer we can't.
String class is overriding toString(), equals(), hashCode() of Object class, but StringBuffer only overrides toString().
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.equals(s2)); // output true
StringBuffer sb1 = new StringBuffer("abc");
StringBuffer sb2 = new StringBuffer("abc");
System.out.println(sb1.equals(sb2)); // output false
String class is both Serializable as well as Comparable, but StringBuffer is only Serializable.
Set<StringBuffer> set = new TreeSet<StringBuffer>();
set.add(sb1);
set.add(sb2);
System.out.println(set); // gives ClassCastException because there is no Comparison mechanism
We can create a String object with and without new operator, but StringBuffer object can only be created using new operator.
String is immutable but StringBuffer is mutable.
StringBuffer is synchronized, whereas String ain't.
StringBuffer is having an in-built reverse() method, but String dosen't have it.
Performance wise StringBuffer is much better than String ; because whenever you apply concatenation on String Object then new String object are created on each concatenation.
Principal Rule : String are immutable(Non Modifiable) and StringBuffer are mutable(Modifiable)
Here is the programmatic experiment where you get the performance difference
public class Test {
public static int LOOP_ITERATION= 100000;
public static void stringTest(){
long startTime = System.currentTimeMillis();
String string = "This";
for(int i=0;i<LOOP_ITERATION;i++){
string = string+"Yasir";
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
public static void stringBufferTest(){
long startTime = System.currentTimeMillis();
StringBuffer stringBuffer = new StringBuffer("This");
for(int i=0;i<LOOP_ITERATION;i++){
stringBuffer.append("Yasir");
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
public static void main(String []args){
stringTest()
stringBufferTest();
}
}
Output of String are in my machine
14800
Output of StringBuffer are in my machine
14

Categories

Resources