I have a task which is to create a memory efficient method that takes a String consisting of numbers and removes any beginning zeros.
For instance "001112" becomes "1112".
public static String hej (String v)
{
StringBuilder h = new StringBuilder(v);
while(true)
{
if (h.charAt(0) == '0')
h.deleteCharAt(0);
else
break;
}
return h.toString();
}
This is my solution. Of course it does the work, but my question is, is it memory efficient to use the StringBuilder or is it more efficient to use the String itself and for instance v.substring()? Cant find too much information about what is more efficient. If anyone has links to some documentation, please share them.
Cheers
Using the String.substring(int) method will be the least memory used
public static String hej(String input)
{
int i;
for(i = 0; i < input.length(); i++)
if(input.charAt(i) != '0')
break;
return input.substring(i);
}
Source code from String:
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
This calls the String(char[], int, int) constructor
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
Using a StringBuilder uses a bit of memory to create the StringBuilder for the size of the input, while using String.substring(int) will just use up as much memory as needed to represent the modified input
If your string were to have n amount of leading zeros, then using String instead of StringBuilder would consume n times more memory. You know that String creates a new space in memory everytime some char changes in it so StringBuilder is the way to go.
Keep in mind
Every string builder has a capacity. As long as the length of the
character sequence contained in the string builder does not exceed the
capacity, it is not necessary to allocate a new internal buffer. If
the internal buffer overflows, it is automatically made larger.
Oracle Docs
So
String
String is immutable ( once created can not be changed )object . The
object created as a String is stored in the Constant String Pool .
Every immutable object in Java is thread safe ,that implies String is
also thread safe . String can not be used by two threads
simultaneously. String once assigned can not be changed.
String demo = " hello " ; // The above object is stored in constant
string pool and its value can not be modified.
demo="Bye" ; //new "Bye" string is created in constant pool and
referenced by the demo variable // "hello" string still
exists in string constant pool and its value is not overrided but we
lost reference to the "hello"string
StringBuffer
StringBuffer is mutable means one can change the value of the object .
The object created through StringBuffer is stored in the heap .
StringBuffer has the same methods as the StringBuilder , but each
method in StringBuffer is synchronized that is StringBuffer is thread
safe .
Due to this it does not allow two threads to simultaneously access
the same method . Each method can be accessed by one thread at a time
.
But being thread safe has disadvantages too as the performance of the
StringBuffer hits due to thread safe property . Thus StringBuilder is
faster than the StringBuffer when calling the same methods of each
class.
StringBuffer value can be changed , it means it can be assigned to the
new value . Nowadays its a most common interview question ,the
differences between the above classes . String Buffer can be converted
to the string by using toString() method.
StringBuffer demo1 = new StringBuffer("Hello") ; // The above object
stored in heap and its value can be changed . demo1=new
StringBuffer("Bye"); // Above statement is right as it modifies the
value which is allowed in the StringBuffer
Java Hungry
Related
When working with a StringBuilder, I often append 2 char values to a StringBuilder using StringBuilder#append(char) twice, rather than StringBuilder#append(String).
I.e.:
StringBuilder builder = new StringBuilder();
builder.append(' ').append('t'); // would append(" t") work better here?
return builder.toString();
I would like to know:
Which approach is better performance-wise
Which approach is more common and why
I have already read through Using character instead of String for single-character values in StringBuffer append but it does not answer my question.
That question pertains to whether appending a single character (append('c')) is better than a single-character string (append("c")). I already understand why appending a single character is better than a single-character string, but I do not know whether appending a two-character string (append("ab")) is better than twice appending each character (append('a').append('b')).
In my testing, both of them seemed to take about the same time, however appending a string might be slightly slower (maybe 10 or so nanoseconds)
However, appending a string is much more popular as it's easier to use/understand.
This is really interesting to figure out this one.
As we all know the array is fast and internally String is using Character Array for storing the values.
internally both the method called the super.append(XXX) method ofAbstractStringBuilderclass.
if you see the code of append in AbstractStringBuilder for String and CharSeq
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
count += len;
return this;
}
These are the method internally called when you call append method.
Both the method calls the ensureCapacityInternal method to expand the array. So let's leave this method call as it is.
Now, the main difference comes in the next line of code.
The method with String args calls the getChars method. which internally call the System.arraycopy method, it's a native method and we can't predict the complexity of that method. it's based on the OS/JVM.
CharSeq method uses a for loop till the length of input charSequence.
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
i.e. it's completixity is depend on the length of input.
As I study, Other posts related to System.arraycopy method. They all say that it's effective than copying an array by a loop. even in an Effective Java Programing book.
So finally opinion, I would suggest that if the input is of small length then use the CharSequence only. Why waste the JVM for the small length String.
If you have long length string like a statement then go for a method with String args. Also, remember Space complexity increases in this case. i.e. String is immutable and you are creating more String every time in a pool. String.valueof(), (String)obj are examples.
Edited:
public AbstractStringBuilder append(char c) { ensureCapacityInternal(count + 1); value[count++] = c; return this; }
This method used when the args is char.
And seems that. It's more fast then others.
Because of assignment at count++ index of char. This method only contain the system.arraycopy method, which is common in all other method for ensuringcapacity.
Hope this will help. :)
Given the string in the form of char array. Modify it the way that all the exclamation point symbols '!' are shifted to the start of the array, and all ohters are in the same order. Please write a method with a single argument of type char[]. Focus on either memory and time consumption of alghoritm.
Feedback that i've received: it was possible to use working with arrays instead of strings. Where can i find info about memory?
public static String formatString(char[] chars) {
StringBuilder exclamationSymbols = new StringBuilder();
StringBuilder otherSymbols = new StringBuilder();
for (char c : chars) {
if (c == '!') {
exclamationSymbols.append(c);
} else {
otherSymbols.append(c);
}
}
return (exclamationSymbols.toString() + otherSymbols.toString());
}
You can do this faster using a char[] than a StringBuilder because:
a StringBuilder is just a wrapper around a char[], so there's no way it can be faster. The indirection means it will be slower.
you know exactly how long the result will be, so you can allocate the minimum-sized char[] that you'll need. With a StringBuilder, you can pre-size it, but with two StringBuilders you can't exactly, so you either have to over-allocate the length (e.g. make both the same length as chars) or rely on StringBuilder resizing itself internally (which will be slower than not; and it uses moer memory).
My idea would be to use two integer pointers to point to the next position that you'll write a char to in the string: one starts at the start of the array, the other starts at the end; as you work your way through the input, the two pointers will move closer together.
Once you've processed the entire input, the portion of the result array corresponding to the "end pointer" will be backwards, so reverse it.
You can do it like this:
char[] newChars = new char[chars.length];
int left = 0;
int right = chars.length;
for (char c : chars) {
if (c == '!') {
newChars[left++] = c;
} else {
newChars[--right] = c;
}
}
// Reverse the "otherSymbols".
for (int i = right, j = newChars.length - 1; i < j; ++i, --j) {
char tmp = newChars[i];
newChars[i] = newChars[j];
newChars[j] = tmp;
}
return new String(newChars);
Ideone demo
Why is StringBuilder much faster than string concatenation using the + operator? Even though that the + operator internally is implemented using either StringBuffer or StringBuilder.
public void shortConcatenation(){
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime <= 1000){
character += "Y";
}
System.out.println("short: " + character.length());
}
//// using String builder
public void shortConcatenation2(){
long startTime = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
while (System.currentTimeMillis() - startTime <= 1000){
sb.append("Y");
}
System.out.println("string builder short: " + sb.length());
}
I know that there are a lot of similar questions posted here, but these don't really answer my question.
Do you understand how it works internally?
Every time you do stringA += stringB; a new string is created an assigned to stringA, so it will consume memory (a new string instance!) and time (copy the old string + new characters of the other string).
StringBuilder will use an array of characters internally and when you use the .append() method it will do several things:
check if there are any free space for the string to append
again some internal checks and run a System.arraycopy to copy the characters of the string in the array.
Personally, I think the allocation of a new string every time (creating a new instance of string, put the string, etc.) could be very expensive in terms of memory and speed (in while/for, etc. especially).
In your example, use a StringBuilder is better, but if you need (example) something simple like a .toString(),
public String toString() {
return StringA + " - " + StringB;
}
makes no differences (well, in this case it is better you avoid StringBuilder overhead which is useless here).
Strings in Java are immutable. This means that methods that operate on strings cannot ever change the value of a string. String concatenation using += works by allocating memory for an entirely new string that is the concatenation of the two previous ones, and replacing the reference with this new string. Each new concatenation requires the construction of an entirely new String object.
In contrast, the StringBuilder and StringBuffer classes are implemented as a mutable sequence of characters. This means that as you append new Strings or characters onto a StringBuilder, it simply updates its internal array to reflect the changes you've made. This means that new memory is only allocated when the string grows past the buffer already existing in a StringBuilder.
I can list a very nice example for understanding the same (I mean I felt it's a nice example). Check the code here taken from a LeetCode problem: https://leetcode.com/problems/remove-outermost-parentheses/
1: Using String
public String removeOuterParentheses(String S) {
String a = "";
int num = 0;
for(int i=0; i < S.length()-1; i++) {
if(S.charAt(i) == '(' && num++ > 0) {
a += "(";
}
if(S.charAt(i) == ')' && num-- > 1) {
a += ")";
}
}
return a;
}
And now, using StringBuilder.
public String removeOuterParentheses(String S) {
StringBuilder sb = new StringBuilder();
int a = 0;
for(char ch : S.toCharArray()) {
if(ch == '(' && a++ > 0) sb.append('(');
if(ch == ')' && a-- > 1) sb.append(')');
}
return sb.toString();
}
The performance of both varies by a huge margin. The first submission uses String while the latter one uses StringBuilder.
As explained above the theory is the same. String by property is immutable and synchronous,i.e. its state cannot be changed. The second, for example, is expensive owing to the creation of a new memory allocation whenever a concatenation function or "+" is used. It will consume a lot of heap and in return be slower. In comparison StringBuilder is mutable, it will only append and not create an overload on the memory consumed.
I needed to use this method, and after looking at the source code, I noticed a StringBuilder initialization which is not familar to me (I always use the no-argument constructor from StringBuilder, i.e. new StringBuilder()).
In the method:
StringBuilder sb = new StringBuilder(items.size() << 3);
From the JavaDoc:
java.lang.StringBuilder.StringBuilder(int capacity)
Constructs a string builder with no characters in it and an initial
capacity specified by the capacity argument.
Why a bit shift is needed here?
Source code:
/** Creates a backslash escaped string, joining all the items. */
public static String join(List<?> items, char separator) {
StringBuilder sb = new StringBuilder(items.size() << 3);
boolean first=true;
for (Object o : items) {
String item = o.toString();
if (first) {
first = false;
} else {
sb.append(separator);
}
for (int i=0; i<item.length(); i++) {
char ch = item.charAt(i);
if (ch=='\\' || ch == separator) {
sb.append('\\');
}
sb.append(ch);
}
}
return sb.toString();
}
Bitshift by 3 means multiplying by 2^3 which is 8. The author must have assumed that each item will take at most 8 characters in the resulting string. Therefore she or he initialized the StringBuilder with that capacity so it run efficiently. If the assumption is correct StringBuilder will not reallocate internal structures.
X << 3 means multiply X by 8. In your situation it means to allocate space for 8*list.size() characters. In general you should not care about the implementation details of a class that you are using
Is a modality to multiply by 8 items.size().
I think coder just speculate to initialCapacity to prevent (or reduce to minimum) StringBuilder() internal buffer reallocation.
This question already has answers here:
Simple way to repeat a string
(32 answers)
Closed 4 years ago.
I did check the other questions; this question has its focus on solving this particular question the most efficient way.
Sometimes you want to create a new string with a specified length, and with a default character filling the entire string.
ie, it would be cool if you could do new String(10, '*') and create a new String from there, with a length of 10 characters all having a *.
Because such a constructor does not exist, and you cannot extend from String, you have either to create a wrapper class or a method to do this for you.
At this moment I am using this:
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
char[] array = new char[length];
int pos = 0;
while (pos < length) {
array[pos] = charToFill;
pos++;
}
return new String(array);
}
It still lacks any checking (ie, when length is 0 it will not work). I am constructing the array first because I believe it is faster than using string concatination or using a StringBuffer to do so.
Anyone else has a better sollution?
Apache Commons Lang (probably useful enough to be on the classpath of any non-trivial project) has StringUtils.repeat():
String filled = StringUtils.repeat("*", 10);
Easy!
Simply use the StringUtils class from apache commons lang project. You have a leftPad method:
StringUtils.leftPad("foobar", 10, '*'); // Returns "****foobar"
No need to do the loop, and using just standard Java library classes:
protected String getStringWithLengthAndFilledWithCharacter(int length, char charToFill) {
if (length > 0) {
char[] array = new char[length];
Arrays.fill(array, charToFill);
return new String(array);
}
return "";
}
As you can see, I also added suitable code for the length == 0 case.
Some possible solutions.
This creates a String with length-times '0' filled and replaces then the '0' with the charToFill (old school).
String s = String.format("%0" + length + "d", 0).replace('0', charToFill);
This creates a List containing length-times Strings with charToFill and then joining the List into a String.
String s = String.join("", Collections.nCopies(length, String.valueOf(charToFill)));
This creates a unlimited java8 Stream with Strings with charToFill, limits the output to length and collects the results with a String joiner (new school).
String s = Stream.generate(() -> String.valueOf(charToFill)).limit(length).collect(Collectors.joining());
In Java 11, you have repeat:
String s = " ";
s = s.repeat(1);
(Although at the time of writing still subject to change)
char[] chars = new char[10];
Arrays.fill(chars, '*');
String text = new String(chars);
To improve performance you could have a single predefined sting if you know the max length like:
String template = "####################################";
And then simply perform a substring once you know the length.
Solution using Google Guava
String filled = Strings.repeat("*", 10);
public static String fillString(int count,char c) {
StringBuilder sb = new StringBuilder( count );
for( int i=0; i<count; i++ ) {
sb.append( c );
}
return sb.toString();
}
What is wrong?
using Dollar is simple:
String filled = $("=").repeat(10).toString(); // produces "=========="
Solution using Google Guava, since I prefer it to Apache Commons-Lang:
/**
* Returns a String with exactly the given length composed entirely of
* the given character.
* #param length the length of the returned string
* #param c the character to fill the String with
*/
public static String stringOfLength(final int length, final char c)
{
return Strings.padEnd("", length, c);
}
The above is fine. Do you mind if I ask you a question - Is this causing you a problem? It seams to me you are optimizing before you know if you need to.
Now for my over engineered solution. In many (thou not all) cases you can use CharSequence instead of a String.
public class OneCharSequence implements CharSequence {
private final char value;
private final int length;
public OneCharSequence(final char value, final int length) {
this.value = value;
this.length = length;
}
public char charAt(int index) {
if(index < length) return value;
throw new IndexOutOfBoundsException();
}
public int length() {
return length;
}
public CharSequence subSequence(int start, int end) {
return new OneCharSequence(value, (end-start));
}
public String toString() {
char[] array = new char[length];
Arrays.fill(array, value);
return new String(array);
}
}
One extra note: it seems that all public ways of creating a new String instance involves necessarily the copy of whatever buffer you are working with, be it a char[], a StringBuffer or a StringBuilder. From the String javadoc (and is repeated in the respective toString methods from the other classes):
The contents of the character array are copied; subsequent modification of
the character array does not affect
the newly created string.
So you'll end up having a possibly big memory copy operation after the "fast filling" of the array. The only solution that may avoid this issue is the one from #mlk, if you can manage working directly with the proposed CharSequence implementation (what may be the case).
PS: I would post this as a comment but I don't have enough reputation to do that yet.
Try this Using the substring(int start, int end); method
String myLongString = "abcdefghij";
if (myLongString .length() >= 10)
String shortStr = myLongString.substring(0, 5)+ "...";
this will return abcde.
Mi solution :
pw = "1321";
if (pw.length() < 16){
for(int x = pw.length() ; x < 16 ; x++){
pw += "*";
}
}
The output :
1321************
Try this jobber
String stringy =null;
byte[] buffer = new byte[100000];
for (int i = 0; i < buffer.length; i++) {
buffer[i] =0;
}
stringy =StringUtils.toAsciiString(buffer);