This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 3 years ago.
I'm doing a problem on hackerRank and the problem is:
Problem Statement
Here we have to count the number of valleys does XYZ person visits.
A valley is a sequence of consecutive steps below sea level, starting with a step down from sea level and ending with a step up to sea level.
For One step up it U, and one step down it is D. We will be given the number of steps does XYZ person traveled plus the ups and down in the form of string, i.e,
UUDDUDUDDUU
Sample Input
8
UDDDUDUU
Sample Output
1
Explanation
If we represent _ as sea level, a step up as /, and a step down as \, Gary's hike can be drawn as:
_/\ _
\ /
\/\/
He enters and leaves one valley.
The code I wrote doesn't work
static int countingValleys(int n, String s) {
int count = 0;
int level = 0;
String[] arr = s.split("");
for(int i = 0; i<n;i++){
if(arr[i] == "U"){
level++;
} else{
level--;
}
if(level==0 && arr[i]=="U"){
count++;
}
}
return count;
}
But another solution I found does, however no matter how I look at it the logic is the same as mine:
static int countingValleys(int n, String s) {
int v = 0; // # of valleys
int lvl = 0; // current level
for(char c : s.toCharArray()){
if(c == 'U') ++lvl;
if(c == 'D') --lvl;
// if we just came UP to sea level
if(lvl == 0 && c == 'U')
++v;
}
return v;
}
So what's the difference I'm missing here that causes mine to not work?
Thanks.
In java, you need to do this to compare String values:
if("U".equals (arr[i])) {
And not this:
if(arr[i] == "U") {
The former compares the value "U" to the contents of arr[i].
The latter checks whether the strings reference the same content or more precisely the same instance of an object. You could think of this as do they refer to the same block of memory? The answer, in this case, is they do not.
To address the other aspect of your question.
Why this works:
for(char c : s.toCharArray()){
if(c == 'U') ++lvl;
if(c == 'D') --lvl;
when this does not:
String[] arr = s.split("");
for(int i = 0; i<n;i++){
if(arr[i] == "U"){
You state that the logic is the same. Hmmmm, maybe, but the data types are not.
In the first version, the string s is split into an array of character values. These are primitive values (i.e. an array of values of a primitive data type) - just like numbers are (ignoring autoboxing for a moment). Since character values are primitive types, the value in arr[i] is compared by the == operator. Thus arr[i] == 'U' (or "is the primitive character value in arr[i] equal to the literal value 'U') results in true if arr[i] happens to contain the letter 'U'.
In the second version, the string s is split into an array of strings. This is an array of instances (or more precisely, an array of references to instances) of String objects. In this case the == operator compares the reference values (you might think of this as a pointer to the two strings). In this case, the value of arr[i] (i.e. the reference to the string) is compared to the reference to the string literal "U" (or "D"). Thus arr[i] == "U" (or "is the reference value in arr[i] equal to the reference value of where the String instance containing a "U" string" is located) is false because these two strings are in different locations in memory.
As mentioned above, since they are different instances of String objects the == test is false (the fact that they just happen to contain the same value is irrelevant in Java because the == operator doesn't look at the content). Hence the need for the various equals, equalsIgnoreCase and some other methods associated with the String class that define exactly how you wish to "compare" the two string values. At risk of confusing you further, you could consider a "reference" or "pointer" to be a primitive data type, and thus, the behaviour of == is entirely consistent.
If this doesn't make sense, then think about it in terms of other object types. For example, consider a Person class which maybe has name, date of birth and zip/postcode attributes. If two instances of Person happen to have the same name, DOB and zip/postcode, does that mean that they are the same Person? Maybe, but it could also mean that they are two different people that just happen to have the same name, same date of birth and just happen to live in the same suburb. While unlikely, it definitely does happen.
FWIW, the behaviour of == in Java is the same behaviour as == in 'C'. For better or worse, right or wrong, this is the behaviour that the Java designers chose for == in Java.
It is worthy to note that other languages, e.g. Scala, define the == operator for Strings (again rightly or wrongly, for better or worse) to perform a comparison of the values of the strings via the == operator. So, in theory, if you addressed other syntactic issues, your arr[i] == "U" test would work in Scala. It all boils down to understanding the rules that the various operators and methods implement.
Going back to the Person example, assume Person was defined as a case class in Scala. If we created two instances of Person with the same name, DOB and zip/postcode (e.g. p1 and p2), then p1 == p2 would be true (in Scala). To perform a reference comparison (i.e. are p1 and p2 instances of the same object), we would need to use p1.eq(p2) (which would result in false).
Hopefully the Scala reference, does not create additional confusion. If it does, then simply think of it as the function of an operator (or method) is defined by the designers of the language / library that you are using and you need to understand what their rules are.
At the time Java was designed, C was prevalent, so it can be argued that it makes sense the C like behaviour of == replicated in Java was a good choice at that time. As time has moved on, more people think that == should be a value comparison and thus some languages have implemented it that way.
Related
set.add(new String(s) + (ch == 0 ? "" : ch) + new StringBuffer(new String(s)).reverse());
I encountered this code from written by someone. It is java code.
s is a char[].
set is a String set.
So why does he use String and then StringBuffer?
String has a constructor which takes an array of chars, hence why they create a new String first.
Then to reverse the String, they create a StringBuffer to use a built in reverse function in order to not implement their own. StringBuffer's constructor takes a String, hence why a String is made first and then a StringBuffer
Let's split the 3 parts on 3 lines to compare:
set.add(
new String(s)
+ (ch == 0 ? "" : ch)
+ new StringBuffer(new String(s)).reverse()
);
Rewritten
It is equivalent with
String trimZero = ch == 0 ? "" : String.valueOf(ch);
set.add(String.valueOf(s) + trimZero + StringUtils.reverse(s));
Well, using Apache's StringUtils.reverse().
If s is a String it can simply added as is, for example, in an alternative way (to emphasize the different structures):
if (ch == 0) {
set.add(s + StringUtils.reverse(s));
} else {
set.add(s + String.valueOf(ch) + StringUtils.reverse(s));
}
Output wise
For example:
alphabet gets added as alphabet8tebahpla (for coincidence ch is a non-zero integer).
an gets added as anna (given that ch == 0)
Abbreviations and naming-conventions
When guessing the types I would say:
ch probably is a primitive char, array of that, or CharSequece
s most-likely is a String (rather than the rarely used short integer)
Usually abbreviations in symbols/names are ambiguous and can be considered a code-smell.
However there seems to be a historical and accepted convention or habit, especially for temporary / looping variables like:
int i
String s
char ch
The Java Pocket Guide, 4th Edition by Robert Liguori, Patricia Liguori, Chapter 1. Naming Conventions assorted them in a table:
Temporary variable names may be single letters such as i, j, k, m, and n for integers and c, d, and e for characters. Temporary and looping variables may be one-character names as shown in Table 1-1.
Even core Java methods have such (ambiguous) abbreviated parameter-names
if the method-context is obvious enough
that the contents and purpose of the parameter is self-explaining
E.g. String.contains(CharSequence s)
I came across the below code snippet in a product's code. It is using bitwise XOR for string comparison. Is this better than the String.equals(Object o) method? What is the author trying to achieve here?
private static boolean compareSecure(String a, String b)
{
if ((a == null) || (b == null)) {
return (a == null) && (b == null);
}
int len = a.length();
if (len != b.length()) {
return false;
}
if (len == 0) {
return true;
}
int bits = 0;
for (int i = 0; i < len; i++) {
bits |= a.charAt(i) ^ b.charAt(i);
}
return bits == 0;
}
For context, the strings being equated are authentication tokens.
This is a common implementation of string comparison function that is invulnerable to timing attacks.
In short, the idea is to compare all the characters every time you compare strings, even if you find any of them are not equal. In "standard" implementation you just break on the first difference and return false.
This is not secure because it gives away the information about the compared strings. Specifically if the left-side string is a secret you want to keep (e.g. password), and the right-side string is something provided by the user, an unsafe method allows the hacker to uncover your password with a relative ease, by repeatedly trying out different strings and measuring the response time.
The more characters in the two strings are identical, the more the 'unsecure' function would take to compare them.
For instance, comparing "1234567890" and "0987654321" using a standard method would result in doing just a single comparison of the first character and returning false, since 1!=0. On the other hand comparing "1234567890" to "1098765432", would result in executing 2 comparison operations, because the first ones are equal, you have to compare the second ones to find they are different. This would take a bit more time and it is measurable, even when we are talking about remote calls.
If you do N attacks with N different strings, each starting with a different character, you should see one of the of the results taking a fraction of a milisecond more then the rest. This means the first character is the same, so the function has to take more time to compare the second one. Rinse and repeat for each position in the string and you can crack the secret orders of magnitude faster then brute force.
Preventing such attack is the point of such implementation.
Edit: As diligently pointed out in comment by Mark Rotteveel, this implementation is still vulnerable to timing attack that is aimed at revealing the length of the string. Still this is not a problem in many cases (either you don't care about attacker knowing the length or you deal with data that is standard and anyone can know the length anyway, for instance some kind of known-length hash)
I am trying to overwrite the compareTo in Java such that it works as follows. There will be two string arrays containing k strings each. The compareTo method will go through the words in order, comparing the kth element of each array. The arrays will then be sorted thusly. The code I have currently is as follows, but it does not work properly.
I need a return statement outside the for-loop. I'm not sure what this return statement should return, since one of the for-loop return statements will always be reached.
Also, am I using continue correctly here?
public int compareTo(WordNgram wg) {
for (int k = 0; k < (this.myWords).length; k++) {
String temp1 = (this.myWords)[k];
String temp2 = (wg.myWords)[k];
int last = temp1.compareTo(temp2);
if (last == 0) {
continue;
} else {
return last;
}
}
}
You want to compare the two string at the same location:
int last = temp1.compare(temp2);
Java compiler mandates all the end points must have a return statement. In your case you must return 0 at end so when both arrays contain completely equal strings the caller will know they are equal.
You should start listening to your compiler, because after looking at your code for 1 minute, I spotted two undefined states: this.myWords.length is 0 and the two words are equal.
Also, I personally find it very difficult to handle multiple method exit points with all possibilities for input considered and rather insert a single returning statement which makes debugging easier and the results more predictable. In your case for example, I would collect the results of compareTo in a collection if they differ from 0 so that after the for-loop has finished, you could decide at the state of this collection if 0 (empty collection) or the first value in the collection could be returned. I like this more formal approach, because it enforces you to think set-like as in "Give me all comparing results where compareTo results in anything else but 0. If this list is empty, the comparing result is 0, otherwise it is the first element of the list."
Why does java require a double equals sign (==) when comparing Integers in a if statement?
For example
if(x = 3.141)
System.out.println("x is equal to pi.");
is incorrect, it should be
if(x == 3.141)
System.out.println("x is equal to pi.");
I know that "==" is used to compare integers and "=" is used to set an integer value, but why in a if statement does this remain true?
Is it even allowed to assign a variable a value in an if statement (or initiate a new variable)?
Is there any reason anyone would ever want to assign a variable a new value inside an if statement (if so please provide an example)?
This seems like a question that should already have an answer, but I was unable to find one on here or using google, if this is a duplicate question please tell me and I will remove it immediately.
Wouldn't it be confusing if = sometimes did assignment, and sometimes comparison, depending in which context you used it?
That sounds like a bad idea, and would introduce errors.
Plus, the current syntax is compatible with C and C++, so a lot of people are familiar with it.
Is there any reason anyone would ever want to assine a variable a new value inside of an if statement (if so please provide an example)?
It's quite common in while loops:
int b;
while ((b=in.read()) != -1){
=
is used for assignment.
==
is used for comparison.
Is it even allowed to assign a variable a value in an if statement (or initiate a new variable)?
yes it is allowed.
Note what error message you get for if (x = 3.141); it is a type error (cannot convert from double to boolean).
The assignment's type is the type of its both sides; if the type of the assignment is boolean (if (x = true), or even if (x = a.equals(b))), then it is legal to write.
So since it is legal to assign a value to a boolean in the condition, you'd have to use == for comparison.
Is it even allowed to assine a variable a value in an if statement (or initiate a new variable)?
Yes. A common idiom for doing this is:
String line = null;
while ( (line = in.readLine()) != null ) {
// do work
}
In the loop, line is assigned a value and then compared to null. I can't think of an example with ints; it certainly wouldn't be clear there.
History of programming languages 101:
Fortran uses = for both.
Algol introduced := for assignment and used = for comparison. This was required to resolve a grammar ambiguity.
Pascal followed suit.
PL/1 did not.
I can't speak for B or BCPL but by the time we got C it was = for assignment and == for comparison, again to resolve a grammar ambiguity
C++ followed C
Java followed C++ in many respects including this one.
The grammar ambiguity arises because of allowing assignments in expressions. Contrary to your assertion, if (x = true) is legal in Java if x is of type boolean.
== is the identity comparator, which works for both objects and primitives. It answers the question "are the two things the same thing".
= is the assignment operator. It sets the value of the left side to the right side.
Things can turn buggy when using your example with booleans:
boolean b;
if (b = true) // This compiles, but is a bug, because it sets b, not tests it
While other types won't compile with this syntax, boolean and Boolean do, so that's why the following pattern is advised:
if (b)
you can absolutely assign a variable in an if statement. also, that's just the way it works: = always is assignment, and == is always comparison.
So..
= is assignment, and == is comparison, and it is always like this, no matter where they are used.
And assignment is different with "declaration". An assignment statement has its return value, while a declaration doesn't. So you can't write boolean a = false in the () of if statement, but you can write a = false when a has been declared before.
Not all assignments are legal. For example:
int index;
if (index = str.indexOf("something")) {
...
}
It's not legal, because String.indexOf(String) returns an int, while if requires a boolean.
Also, there is a huge difference between "legal" and "making sense".
int index;
if ((index = str.indexOf("something")) != -1) {
...
}
It is legal, as != operation returns a boolean, and it makes sense, as I do want to check if the str contains a substring "something";
However,
int index;
boolean flag;
if ( flag = ((index = str.indexOf("something")) != -1) ) {
...
}
is also legal, as the statement as last returns a boolean; but it DOESN'T make sense, because the != statement already returns a boolean.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I compare strings in Java?
(This may be a duplicate, I was not aware of .equals. My apologies.)
I was messing around in Java today when I decided to make a 4 character string generator. I have the program generate every possible combination of characters that I defined. This isn't for a project, I just wanted to see if this was possible. My problem lies with the string checking. I'll post the code first.
String text = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char[] chars = text.toCharArray();
String name = "Mike";
String pass;
outerLoop:
for (int a = 0; a < chars.length; a ++) {
for (int b = 26; b < chars.length; b++) {
for (int c = 26; c < chars.length; c++) {
for (int d = 26; d < chars.length; d++) {
pass = chars[a]+""+chars[b]+""+chars[c]+""+chars[d];
System.out.println(pass);
if (pass == name){
System.out.print("password");
break outerLoop;
}
}
}
}
}
The nested if will check if pass is equal to Mike. If it is, then it prints password and will break the for loop.
Is pass = chars[a]... the correct way to do this? When I tested it without the if, I had it print out pass and it printed all of the combinations correctly. It did print Mike, but it did not catch in the if.
I also changed the nested for loops so they start with the lower case because the program was taking a while to run when I made minor changes.
if (pass == name){
should be
if (pass.equals(name)){
use String.equals() method to check string equality. == operator simply checks if two reference variables refer to the same object. equals() method checks if two strings are meaningfully equal.
Strings should be compared using equals()
This comes up at least once per day. There should be a "close question" option dedicated to it. Nevertheless, here goes again...
The == operator tests if the two operands are the same instance.
The .equals() method compares the values of the two operands, but only if the class has implemented this method (which String does), otherwise it behaves the same as == (which is how the Object class implements it).