skipping a condition scope in java [duplicate] - java

This question already has answers here:
comparing arrays in java
(6 answers)
Closed 1 year ago.
I have a program with 2 classes - a Node class and a Problem class.
The Problem class has an PriorityQueue attribute.
The Node class has an char [] state attribute.
I'm trying to run a function at the Problem class with the next input:
(Node node , PriorityQueue q) and check if there is any node in q with the same state as the node. state
public boolean insideQueue (Node node, PriorityQueue<Node> q){
for (Node ele : q) {
if(ele.state == node.state) {
return true;
}
}
return false;
}
I tried to use toString() method to solve the problem, and Im having a problem to understand how I can solve this problem with another way (maybe because I'm using python 95% of my time)
I'm adding a photo from my debugger.
Thank you very much

Java == compares the object references for you, which are char[7]#840 and char[7]#835, so they are different.
Converting to String, and comparing the result as a.equals(b) could work (== would not), but there are pre-defined methods for comparing arrays in the Arrays class, https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#equals(char[],%20char[]) is the one you could use in particular, so
if(ele.state == node.state) {
becomes
if(Arrays.equals(ele.state, node.state)) {

I have absolutely no idea what you mean by
skipping a condition scope in java
However, the code you wrote makes no sense, so presumably the problem with it is what you're struggling with.
A char[] is a java array; an object (all things in java are objects, except primitives, which are a hardcoded list of 8 types: int, double, boolean - the lowercased stuff. char is a primitive, but arrays of primitives are objects).
All expressions that resolve to an object type are references - they are like an entry in a phone book, and not the phone itself. Merely instructions on how to get there.
== in java compares the raw value. For primitives, that just compares values, but for references (and, remember, all expressions of non-primitive types are references), it compares references, i.e. it doesn't check if it's the same phone number, it checks if it's the same entry in the same phone book.
You can therefore have 2 different objects whose contents are identical; with ==, that would return false, because == checks if they are the same object reference, not if the content inside them is equal.
For that you ordinarily want .equals, but arrays in java are low-level primitive things designed for speed and for access to low-level hardware, and not for actual normal use. I have no idea why you don't just have strings here. At any rate, for normal objects, you just call .equals() on it. For arrays, no such luck, their equals method also is a check for same object identity (for somewhat solid reasons). To compare content, you need Arrays.equals.
So:
if (Arrays.equals(ele.state, node.state)) { ... }
will return true even if ele.state and node.state are pointing at different char arrays, but those char arrays have the exact same content. Which, according to your debugger paste, they do.
Alternatively, don't use arrays unless you really know what you are doing. Those should be strings. Then all you really need is ele.state.equals(node.state).

Related

Is == guaranteed to return correct result? [duplicate]

This question already has answers here:
Compare two objects with .equals() and == operator
(16 answers)
Closed 1 year ago.
From what I understand, the == operator in Java compares references (an int) of objects.
This value is what the default implementation of hashCode method in Object returns.
The hashCode method has an implementation note:
As far as is reasonably practical, the hashCode method defined
by class Object returns distinct integers for distinct objects.
reasonably practical: This means that, no matter how small, there is a real possibility that two distinct objects can have equal hashCode or reference value.
So, if I compare two different objects (that don't override hashCode and equals) using ==, it's a real possibility that the result can be true (?). The default implementation of equals does a == check:
public class Test {
public static void main(String[] args) {
var t1 = new Test();
var t2 = new Test();
System.out.println(t1.hashCode() + ":" + t2.hashCode()); // 2055281021:1554547125 (Could've been 1554547125:1554547125 ?)
System.out.println(t1 == t2); // false (Could've been true ?)
System.out.println(t1.equals(t2)); // false (Could've been true ?)
}
}
Why is that equals and hashCode are overridden in certain situations only and rest of the time (many library classes such as Thread) depend on default implementation for equality check when it's not guaranteed to return correct result?
And, how someone extremely risk-averse make sure the above false-positive would never occur? If the class has at least one non-static field, one can override hashCode and equals. But, what if this is not the case (like the Test class above)?
Can you please explain what am I missing here?
Edit 1:
Adding an API note for hashCode (taken form Silvio's answer):
This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language
Okay, there's a lot of questions here, so let's try to break it down.
From what I understand, the == operator in Java compares references (an int) of objects.
This value is what the default implementation of hashCode method in Object returns.
== in Java compares references, yes. Those references are not necessarily compatible with int. On many common architectures, int will probably coincide with most of the observable space that a reference can occupy, but that's not true in general.
In particular.
int is a signed type. That means half of its values are negative. Pointers are generally unsigned.
Even if we ignore the sign problems, int is a 32-bit type. Most modern computers are 64-bit, which means the address space would fit better in a 64-bit integer (i.e. a Java long). So only a small fraction of addresses can even be stored in int.
Second, hashCode is not required to have anything to do with the pointer itself. From the hashCode docs you referenced already
(This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
A Java implementation is free to choose whatever hashCode it wants. Maybe you're running on some bizarre embedded hardware and it makes sense to use some additional flag variable in the computation. hashCode should not be assumed to be the pointer.
Why is that equals and hashCode are overridden in certain situations only and rest of the time (many library classes such as Thread) depend on default implementation for equality check when it's not guaranteed to return correct result?
What is your definition of "correct" here? The guarantees demanded by the Java specification can be summarized from the docs
The equals method implements an equivalence relation on non-null object references:
It is reflexive: for any non-null reference value x, x.equals(x) should return true.
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
For any non-null reference value x, x.equals(null) should return false.
...
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
The default equals implementation clearly satisfies the basic requirements above, and the default hashCode is guaranteed by the standard to be the same for two equal objects.
We override equals when we have a better notion of equality. For instance, two strings should be considered equal if they have the same characters, even if they are distinct objects in memory, and two array lists should be equal if their elements are equal pointwise. But for something like Thread, what would that even mean? When should two arbitrary threads be equal? The default suffices well enough, because we'd gain nothing from overriding it anyway.
If the class has at least one non-static field, one can override hashCode and equals
What does equality have to do with the number of non-static fields? I can override the two just fine. Watch.
public final class MySimpleClass {
public boolean equals(Object other) {
return (other != null) && (other instanceof MySimpleClass);
}
public int hashCode() {
return 42;
}
}
That's a perfectly valid, conformant implementation of equality and hashing for MySimpleClass. In particular, since there's only one meaningfully distinct value of this class, I'd argue that's a good implementation of the two methods. No non-static fields required.
== always returns false if you compare 2 different objects and always returns true if you compare an object to itself.
But it is not guaranteed, that 2 different objects return different hash codes. That's because hashCode() returns int and there's only about 4 billion distinct ints. The number of objects in your code is constrained by the size of heap only.
So, because there can be more than 4 billion distinct objects, their hash codes can sometimes be the same
As for equals, it works as == by default, but can be overridden, so == can return false, when equals returns true and vice versa
equals and hashCode have an unenforceable-at-compile-time contract between them (which itself is different than the == operator).
Fundamentally speaking, an object should override hashCode such that a.equals(b) (and its inverse) is congruent to a.hashCode() == b.hashCode() (and its inverse).
The == operator is only looking to compare numeric equality, which is why the same instance of an object compared against itself (or a == a) will return true, with some caveats given to Strings and string interning.
Because the contract between equals and hashCode is unenforceable, suggesting that == will always return a "correct" result depends on your definition of "correct".
For instance:
It's correct that a square is a parallelogram; it's not correct that any given square is the same as any given parallelogram.
It's correct that a book is a dictionary; it's not correct that any given book is a dictionary.
It's correct that a car has wheels; it's not correct that any given car has any given number of wheels.
Also too - just remember that hashCode is only 32 bits, so there's always going to be the chance of a collision between two unrelated objects (which is where having equals pick up the slack is beneficial here).
In this context, you can only trust == based on the constraints and conditions the individual object has, and what business rules make sense for equality comparisons given a hash code, and nothing further. If your business rules require a deviation between how equals and hashCode behave, then you have to keep that context in mind when comparing through those methods.
Firstly, == checks the memory reference. JVM does this using pointers internally. So each object is literally different as they are stored in different memory address. As compared using memory address location 32 or 64 bit int/number.
For your second question, if you need to have a hash code implementation, but the class has no fields. Then use System.identityHashCode() to do it. It will provide zero for null object and a unique/smal hashcode for same object.
From what I understand, the == operator in Java compares references
(an int) of objects.
On a 64-bit architecture, a reference will need 8 bytes. This is a long, not an int.
This value is what the default implementation of hashCode method in Object returns.
When you cast a long to an int, you will lose information. This is why the default implementation of hashCode() can return equal hashes for different objects.

Comparing two objects, either of which could be null

I have a function in one of my classes that compares itself with another instance of the same class - and finds out which variables differ. This is for the purpose of minimizing network load with a main database (by only uploading data that needs to be uploaded, instead of uploading the whole object).
For this, I have been trying to make use of the object.equals() function to compare the two objects.
I soon found that the object.equals() does not handle nulls, and after reading this question, I understand why.
So an example of my broken code is as follows:
public class MyObject {
String myString;
String myString2;
public String getChangedVars(MyObject comparisonObj) {
ArrayList<String> changedVars = new ArrayList<String>();
if (!this.myString.equals(comparisonObj.myString))
changedVars.add("myString");
if (!this.myString2.equals(comparisonObj.myString2))
changedVars.add("myString2");
return changedVars.toString();
}
}
My question is - on the basis that either one of the variables being compared could be null, what is a simple way to compare two variables whilst avoiding a NullPointerException?
Edit:
Simply checking for null on both objects first doesn't work well, as I still want to compare if the object has a reference or not. Eg, if one item is null and the other is not, I want this to resolve to true, as the variable has changed.
There is new utility class available in jdk since 1.7 that is Objects .
This class consists of static utility methods for operating on
objects. These utilities include null-safe or null-tolerant methods
for computing the hash code of an object, returning a string for an
object, and comparing two objects.
You can use Objects.equals, it handles null.
Objects.equals(Object a, Object b) Returns true if the arguments are equal to each other and false
otherwise. Consequently, if both arguments are null, true is returned
and if exactly one argument is null, false is returned. Otherwise,
equality is determined by using the equals method of the first
argument.
if(Objects.equals(myString,myString2)){...}
You can use Apache object utils
ObjectUtils.equals(Object object1, Object object2) -- Returns boolean
this method has been replaced by java.util.Objects.equals(Object, Object) in Java 7
if (this.myString != null && this.myString.equals(comparisonObj.myString))
{
changedVars.add("myString");
}
Use StringUtils provided by apache
StringUtils.equals(myString,comparisonObj.myString);

Comparing String and Integer with equals

The output of the below code is false
String str = "3456";
String str1 = "3456";
System.out.println(Integer.valueOf(str).equals(str1));
I didn't understand it. I thought it will return true. As I am preparing for SCJP, understanding the reason behind it may be helpful. Can someone please help?
An Integer will never be equal to a String.
Both classes have very strict equals() definitions that only accept objects of their respective types.
Integer.equals():
The result is true if and only if the argument is not null and is an Integer object that contains the same int value as this object.
String.equals():
The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
That's actually a quite common way to implement equals(): only objects of the same class (and occasionally subclasses) can be equal. Other implementations are possible, but are the exception.
One common exception are the collections such as List: every List implementation that follows the convention will return true when compared to any other implementation, if it has the same content in the same order.
Usually, when implementing equals(), one of the first things to do is to check whether the objects are of one and the same type.
public boolean equals(Object obj) {
if (!(obj instanceof SomeType)) return false;
...
}
This is also applied in the Integer and String classes, which answers the question why do you receive false as a result.
The general contract of the equals() methods states (among other things) that the objects that are being compared need to be of the same class. That's why you'll never be able to compare Apples with Oranges.
For the full contract of the equals() method, see the javadocs.
a Integer Object can't equals with String Object
use :
boolean a = str.equals(str1);
OR
boolean a = (Integer.parseInt(str) == Integer.parseInt(str1));

Android: String equals and contains not matching

I'm testing out the JSON functionality for an Android application and have the following JSON object.
{"result":"fail"}
I then use the following code to get my value:
JSONObject jObject = new JSONObject(ReturnValue); //Return value is what's shown above
String r = jObject.getString("result");
Then using the following I don't get a match
if(r.trim() == "fail")
I wrote it out to the screen just to make sure with this:
et.setText("-" + r + "-");
That results in -fail-
I don't understand why this doesn't match. If I used r.Contains it returns true, but I can't use that for my checks.
Use equals .equals instead of ==. This is because of in Java, if you use == you compare the Object pointers to each other. In the source code of String they have overriden the equals method so they instead compare the letters.
You can't override operators in Java.
Also this is general, always use equals for any object comparison if you don't want to check the references you are comparing are actually pointing on the same object in the heap.
Use
if(r.trim().equals("fail"))
to compare Strings.
as others pointed out, in Java == means "exactly the same object", not "an identical object". You can have two, say, SimpleDateFormat objects that are identical, yet if they occupy different places on the heap, they are not the same object. fyi, C# behaves in quite similar way, but manages to hide it from programmers most of the time.
btw, Since you are already writing Java code, it might be a good idea to, you know, study the language a bit. Saves an awful lot of problems later on. A lot of other surprises await for people who try to write C# in Java (like non-static inner classes).

Is Java's assertEquals method reliable?

I know that == has some issues when comparing two Strings. It seems that String.equals() is a better approach. Well, I'm doing JUnit testing and my inclination is to use assertEquals(str1, str2). Is this a reliable way to assert two Strings contain the same content? I would use assertTrue(str1.equals(str2)), but then you don't get the benefit of seeing what the expected and actual values are on failure.
On a related note, does anyone have a link to a page or thread that plainly explains the problems with str1 == str2?
You should always use .equals() when comparing Strings in Java.
JUnit calls the .equals() method to determine equality in the method assertEquals(Object o1, Object o2).
So, you are definitely safe using assertEquals(string1, string2). (Because Strings are Objects)
Here is a link to a great Stackoverflow question regarding some of the differences between == and .equals().
assertEquals uses the equals method for comparison. There is a different assert, assertSame, which uses the == operator.
To understand why == shouldn't be used with strings you need to understand what == does: it does an identity check. That is, a == b checks to see if a and b refer to the same object. It is built into the language, and its behavior cannot be changed by different classes. The equals method, on the other hand, can be overridden by classes. While its default behavior (in the Object class) is to do an identity check using the == operator, many classes, including String, override it to instead do an "equivalence" check. In the case of String, instead of checking if a and b refer to the same object, a.equals(b) checks to see if the objects they refer to are both strings that contain exactly the same characters.
Analogy time: imagine that each String object is a piece of paper with something written on it. Let's say I have two pieces of paper with "Foo" written on them, and another with "Bar" written on it. If I take the first two pieces of paper and use == to compare them it will return false because it's essentially asking "are these the same piece of paper?". It doesn't need to even look at what's written on the paper. The fact that I'm giving it two pieces of paper (rather than the same one twice) means it will return false. If I use equals, however, the equals method will read the two pieces of paper and see that they say the same thing ("Foo"), and so it'll return true.
The bit that gets confusing with Strings is that the Java has a concept of "interning" Strings, and this is (effectively) automatically performed on any string literals in your code. This means that if you have two equivalent string literals in your code (even if they're in different classes) they'll actually both refer to the same String object. This makes the == operator return true more often than one might expect.
In a nutshell - you can have two String objects that contain the same characters but are different objects (in different memory locations). The == operator checks to see that two references are pointing to the same object (memory location), but the equals() method checks if the characters are the same.
Usually you are interested in checking if two Strings contain the same characters, not whether they point to the same memory location.
public class StringEqualityTest extends TestCase {
public void testEquality() throws Exception {
String a = "abcde";
String b = new String(a);
assertTrue(a.equals(b));
assertFalse(a == b);
assertEquals(a, b);
}
}
The JUnit assertEquals(obj1, obj2) does indeed call obj1.equals(obj2).
There's also assertSame(obj1, obj2) which does obj1 == obj2 (i.e., verifies that obj1 and obj2 are referencing the same instance), which is what you're trying to avoid.
So you're fine.
Yes, it is used all the time for testing. It is very likely that the testing framework uses .equals() for comparisons such as these.
Below is a link explaining the "string equality mistake". Essentially, strings in Java are objects, and when you compare object equality, typically they are compared based on memory address, and not by content. Because of this, two strings won't occupy the same address, even if their content is identical, so they won't match correctly, even though they look the same when printed.
http://blog.enrii.com/2006/03/15/java-string-equality-common-mistake/
"The == operator checks to see if two Objects are exactly the same Object."
http://leepoint.net/notes-java/data/strings/12stringcomparison.html
String is an Object in java, so it falls into that category of comparison rules.

Categories