I have to iterate over the elements of a string and in each iteration to perform some checks.
My question is:
What is better to use: String or StringBuilder?
Is there any difference in running time of String.charAt(i) or StringBuilder.charAt(i)?
I do NOT have to modify the string, I just have to iterate over all elements.
The only reason to use a StringBuilder is for modifications (as Strings are immutable). In this case you should be fine with iterating over the String itself.
StringBuilder is useful when you modify a string and String when you dont.
For your case String
Regarding Performance: It will be constant time for both or negligible [1]
Note:
When you modify a string when its defined as string, it creates new string instead of actually modifying it and thats why its better to use StringBuilder
e.g)
string a = "hello";
a = "hai";
a new world string is also created here along with hello already created in string pools
Additional: http://blog.vogella.com/2009/07/19/java-string-performanc/
As others have already said, there is no performance difference between the two. You can convince yourself of this by looking at the source. As you can see below, the two are nigh on identical.
String.charAt()
public char More ...charAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index + offset];
}
StrringBuilder.charAt()
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
In other words, use whatever you already have. If you have a String, use the String, if you have a StringBuilder, use the StringBuilder. The cost of converting from one object to the other will vastly outweigh any performance difference between these two methods.
String and StringBuilder both are classes in Java.
String is used to create a string constant.
StringBuilder name itself indicates to build the string. It means that we can easily do
modification using this class.
In your case you can simply use String class.
Strings are immutable in Java. This means that after each modification a new String is created with latest modified value.
String str = new String("AVINASH");
char check = 's';
int length=str.length();
for(int i=0; i <length ; i++) {
if (check==str.charAt(i)) {
System.out.println("Matched");
}
}
Related
I was trying to write some functional programming code (using lambdas and streams from Java 8) to test if a string has unique characters in it (if it does, return true, if it does not, return false). A common way to do this using vanilla Java is with a data structure like a set, i.e.:
public static boolean oldSchoolMethod(String str) {
Set<String> set = new HashSet<>();
for(int i=0; i<str.length(); i++) {
if(!set.add(str.charAt(i) + "")) return false;
}
return true;
}
The set returns true if the character/object can be added to the set (because it did not exist there previously). It returns false if it cannot (it exists in the set already, duplicated value, and cannot be added). This makes it easy to break out the loop and detect if you have a duplicate, without needing to iterate through all length N characters of the string.
I know in Java 8 streams you cannot break out a stream. Is there anyway way to capture the return value of an intermediate stream operation, like adding to the set's return value (true or false) and send that value to the next stage of the pipeline (another intermediate operation or terminal stream operation)? i.e.
Arrays.stream(myInputString.split(""))
.forEach( i -> {
set.add(i) // need to capture whether this returns "true" or "false" and use that value later in
// the pipeline or is this bad/not possible?
});
One of the other ways I thought of solving this problem, is to just use distinct() and collect the results into a new string and if it is the same length as the original string, than you know it is unique, else if there are different lengths, some characters got filtered out for not being distinct, thus you know it is not unique when comparing lengths. The only issue I see here is that you have to iterate through all length N chars of the string, where the "old school" method best-case scenario could be done in almost constant time O(1), since it is breaking out the loop and returning as soon as it finds 1 duplicated character:
public static boolean java8StreamMethod(String str) {
String result = Arrays.stream(str.split(""))
.distinct()
.collect(Collectors.joining());
return result.length() == str.length();
}
Your solutions are all performing unnecessary string operations.
E.g. instead of using a Set<String>, you can use a Set<Character>:
public static boolean betterOldSchoolMethod(String str) {
Set<Character> set = new HashSet<>();
for(int i=0; i<str.length(); i++) {
if(!set.add(str.charAt(i))) return false;
}
return true;
}
But even the boxing from char to Character is avoidable.
public static boolean evenBetterOldSchoolMethod(String str) {
BitSet set = new BitSet();
for(int i=0; i<str.length(); i++) {
if(set.get(str.charAt(i))) return false;
set.set(str.charAt(i));
}
return true;
}
Likewise, for the Stream variant, you can use str.chars() instead of Arrays.stream(str.split("")). Further, you can use count() instead of collecting all elements to a string via collect(Collectors.joining()), just to call length() on it.
Fixing both issues yields the solution:
public static boolean newMethod(String str) {
return str.chars().distinct().count() == str.length();
}
This is simple, but lacks short-circuiting. Further, the performance characteristics of distinct() are implementation-dependent. In OpenJDK, it uses an ordinary HashSet under the hood, rather than BitSet or such alike.
This code might work for you:
public class Test {
public static void main(String[] args) {
String myInputString = "hellowrd";
HashSet<String> set = new HashSet<>();
Optional<String> duplicateChar =Arrays.stream(myInputString.split("")).
filter(num-> !set.add(num)).findFirst();
if(duplicateChar.isPresent()){
System.out.println("Not unique");
}else{
System.out.println("Unique");
}
}
}
Here using findFirst() I am able to find the first duplicate element. So that we don't need to continue on iterating rest of the characters.
What about just mapping to a boolean?
Arrays.stream(myInputString.split(""))
.map(set::add)
.<...>
That would solve your concrete issue, I guess, but it's not a very nice solution because the closures in stream chains should not have side-effects (that is exactly the point of functional programming...).
Sometimes the classic for-loop is still the better choice for certain problems ;-)
As a novice Java programmer who barely got started in Java programming, I am totally exhausted in trying to find a solution to this issue. A course that I am currently studying gave homework that asked me to create a Java class that has a sort of “reverse” method that returns a new version of the string
of the current string where the capitalization is reversed (i.e., lowercase to uppercase
and uppercase to lowercase) for the alphabetical characters specified in a given condition. Say if I were to reverse “abc, XYZ; 123.” using reverse("bcdxyz#3210."), it must return "aBC, xyz; 123.". (P.S: the class ignores numbers and special characters and the variable "myString" is where the "abc, XYZ; 123." goes to.). So far, I've only managed to return out "aBC, XYZ; 123." with the code below. Am I missing something here?
public String reverse(String arg) {
// TODO Implement method
String arg_no_sym = arg.replaceAll("[^a-zA-Z0-9]","");
String arg_perfect = arg_no_sym.replaceAll("\\d","");
if (myString != null) {
char[] arrayOfReplaceChars = arg_perfect.toCharArray();
char[] arrayOfmyString = myString.toCharArray();
for (int i = 0; i < arg_perfect.length(); i++) {
myString = myString.replace(String.valueOf((arrayOfReplaceChars[i])), String.valueOf((arrayOfReplaceChars[i])).toUpperCase());
}
return myString;
}
else {
return "";
}
}
How about using the methods isUpperCase() and isLowerCase() to check the case of the letters and then use toUpperCase() and toLowerCase() to change the case of them?
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I am implementing a String matching algorithm for a username database. My method takes an existing Username database and a new username that the person wants and it checks to see if the username is taken. if it is taken the method is supposed to return the username with a number that isn't taken in the database.
Example:
"Justin","Justin1", "Justin2", "Justin3"
Enter "Justin"
return: "Justin4"
since Justin and Justin with the numbers 1 thru 3 are already taken.
In my code sample below, newMember returns Justin1 even though it already exists--where is the mistake?
public class UserName {
static int j = 0;
static String newMember(String[] existingNames, String newName){
boolean match = false;
for(int i = 0; i < existingNames.length; i++){
if(existingNames[i] == (newName)){
match = true;
}
}
if(match){
j++;
return newMember(existingNames, newName + j);
}
else{
return newName;
}
}
public static void main(String[] args){
String[] userNames = new String[9];
userNames[0] = "Justin1";
userNames[1] = "Justin2";
userNames[2] = "Justin3";
userNames[3] = "Justin";
System.out.println(newMember(userNames, "Justin"));
// I don't understand why it returns Justin1 when the name is already taken
// in the array.
}
}
This line:
if(existingNames[i] == (newName)){
Should become
if(existingNames[i].equals(newName)){
In general, always use equals instead of == for Strings in Java.
I would change your approach to this. I think it would be better to use a Map<String, Integer>. For example, the fact that "Justin" - "Justin3" are taken usernames can be represented by the map:
{"Justin": 3}
To check if a username is taken, check if it's a key in the map. To get the "next" username for a specific taken username, get the value corresponding to the name from the map and add 1. Something like this:
static String newMember(Map<String, Integer> existingNames, String newName) {
if (existingNames.containsKey(newName)) {
int newNum = existingNames.get(newName) + 1;
existingNames.put(newName, newNum);
return newName + newNum;
}
existingNames.put(newName, 0);
return newName;
}
Oh, and use .equals() instead of == when comparing strings :)
*Never ever compare equality of Strings with ==. use equals() *
Use .equals to compare strings in Java, not ==.
== will determine if the string references are the same which they almost certainly will not be. (There are rare cases when they may be due to the intern pool.)
.equals will determine if the content of the strings are the same.
When comparing strings in Java, you should generally use the equals() methods to do so.
Using == with strings compares the references, not the underlying objects. Use str.equals().
I guess you have a function somewhere in your application answering if a username already exists, I call this usernameExists(String username) returning true or false.
String getOkUsername (String wantedUsername) {
//if it's free, return it!
if(!usernameExists(wantedUsername)) {
return wantedUsername;
};
//OK, already taken, check for next available username
int i=1;
while(usernameExists(wantedUsername+Integer.toString(i))) {
i++;}
return wantedUsername + Integer.toString(i);
}
You're not comparing the strings correctly, and you're adding the integer 1 to a string. Comparing strings is done with .equals. In order to concatenate the integer onto the end of the string:
static Integer j=0;
return newMember(existingNames, newName + j.toString());
It is much easier to do it in SQL:
select ... where ... LIKE username%
I am implementing a form of leftist min heap, which stores arbitrary words by length. So, I have written a wrapper class for Scanner, and changed the compareTo, like so
public class ScannerWrapper implements Comparable<String>
//a Scanner, sc and a String, current
public int compareTo(String str){
if(current.length() > str.length()) return -1;
if(current.length() > str.length()) return 1;
else return 0;
}
where current = sc.next() and is not the \n character.
in this case, if I have ScannerWrapper.next() > foo , where foo is an arbitrary string of length > ScannerWrapper.next();
will it use the compareTo(String) that I have written, returning false, or will it do some other random thing?
After reading your question several times I think I understand what you're asking now. If you're trying to compare two instances of class ScannerWrapper with the comparison operators, then no, it's not going to work.
You can't overload operators in Java (you can in C++), therefore in order to compare instances of ScannerWrapper with each other you're going to have to call the compareTo() method.
Also, both of your if statement conditions are the same, so you might want to fix that up.
It's difficult to understand your question - so you might consider rephrasing it. Here's a shot in the dark :
public class ScannerWrapper implements Comparable<ScannerWrapper>
//your wrapper has a handle to the scanned data. Presumably it's
//initialized on construction, which is omitted here
private final String scannedData;
public String getScannedData() {
return this.scannedData;
}
public int compareTo(ScannerWrapper other) {
//if this scannedData is longer than the other, return 1
if(this.str.length() > other.getStr().length()) {
return 1;
} else if(this.scannedData.length() < other.getScannedData().length()) {
//if the other scannedData is longer return -1
return -1;
}
//if they are equal return 0
return 0;
}
}
Having read the documentation of Java's String class, it doesn't appear to support popping from front(which does make sense since it's basically a char array). Is there an easy way to do something like
String firstLetter = someString.popFront();
which would remove the first character from the string and return it?
A String in Java is immutable, so you can't "remove" characters from it.
You can use substring to get parts of the String.
String firstLetter = someString.substring(0, 1);
someString = someString.substring(1);
You can easily implement this by using java.lang.StringBuilder's charAt() and deleteCharAt() methods. StringBuilder also implements a toString() method.
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html
I don't think there is something like that (even because strings can't be changed - a new one needs to be created), but You can use charAt and subString to implement your own.
An example of charAt:
String aString = "is this your homework Larry?";
char aChar = aString.charAt(0);
Then subString:
String anotherString = aString.substring(1, aString.length());
So you basically want to have the String in a FIFO stack? For that you can use a LinkedList which offers under each a pop() method to pop the first from the stack.
To get all characters of a String in a LinkedList, do so:
String string = "Hello World";
LinkedList<Character> chars = new LinkedList<Character>();
for (int i = 0; i < string.length(); i++) chars.add(string.charAt(i));
Then you can pop it as follows:
char c = chars.pop();
// ...
Update: I didn't see the comment that you'd like to be able to get the remaining characters back as a string. Well, your best bet is to create and implement your own StringStack or so. Here's a kickoff example:
public class StringStack {
private String string;
private int i;
public StringStack(String string) {
this.string = string;
}
public char pop() {
if (i >= string.length()) throw new IllegalStateException("Stack is empty");
return string.charAt(i++);
}
public String toString() {
if (i >= string.length()) throw new IllegalStateException("Stack is empty");
return string.substring(i, string.length());
}
}
You can use it as follows:
String string = "Hello World";
StringStack stack = new StringStack(string);
char c = stack.pop();
String remnant = stack.toString();
// ...
To make it more solid, you can eventually compose a LinkedList.
You should look at a StringReader. The read() method returns a single character.