HashMap value and variable value match, but are not considered equal - java

I have a method that is called every time a player right-clicks a chest (Minecraft item), and if this block's location matches one of the values in the HashMap, it should check to see that the player's username matches the key in the HashMap. Simply put: is this location saved, and does this player who is trying to interact with it own it? My if statement to check if the player and the location match is not working correctly.
Problematic line:
if (DeathChestManager.deathChestLocation.get(playerName) == b.getLocation()) {}
HashMap and block (b) location values (what the `println()'s output):
HashMap value:
Location{world=CraftWorld{name=world},x=59.0,y=64.0,z=-30.0,pitch=0.0,yaw=0.0}
Block location value:
Location{world=CraftWorld{name=world},x=59.0,y=64.0,z=-30.0,pitch=0.0,yaw=0.0}
HashMap from the DeathChestManager class:
public static Map<String, Location> deathChestLocation = new HashMap<String, Location>();
PlayerInteract Class:
public void onPlayerInteract(PlayerInteractEvent e) {
Player p = e.getPlayer();
String playerName = p.getName();
Block b = e.getClickedBlock();
if (b != null && b.getType() == Material.CHEST) {
if (DeathChestManager.deathChestLocation.containsValue(b.getLocation())) {
e.setCancelled(true);
System.out.println(DeathChestManager.deathChestLocation.get(playerName));
System.out.println(b.getLocation());
if (DeathChestManager.deathChestLocation.get(playerName) == b.getLocation()) {
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
b.setType(Material.AIR);
Location loc = p.getLocation();
for (final ItemStack item : DeathChestManager.inventoryContents.get(p.getName())) {
int count = 0;
for (ItemStack i : p.getInventory().getContents()) {
if (i == null) {
count++;
} else if (i.getType() == Material.AIR) {
count++;
}
}
if (count == 0) {
if (item.getType() != Material.AIR) {
p.getWorld().dropItemNaturally(loc, item);
}
} else {
if (item != null) {
p.getInventory().addItem(item);
p.updateInventory();
}
}
}
DeathChestManager dcManager = new DeathChestManager();
dcManager.endTimer(p, p.getWorld().getName());
}
} else {
MessageManager.getInstance().severe(p, "You do not own that death-chest.");
}
}
}
}

Use .equals() as opposed to == when comparing objects. == will compare the objects' addresses in memory, whereas .equals() will check to see if they have the same values. Since two objects will very rarely have the same address you should never use == except for comparing primitive types (int, char, but String is not a primitive type!) where it doesn't matter.
So you want:
if (DeathChestManager.deathChestLocation.get(playerName).equals(b.getLocation())) {}

You are comparing object references. This will return true only if they both refer to same same instance.
If you wish to compare the contents of these objects, use .equals().

You should use .equals(), not ==, when testing equality for anything other than primitives (int, boolean, etc.). This includes Strings.

Related

JSONObject.similar(JSONObject) what does this really compare?

I was looking for a way to compare two JSONObjects besides using
JSONObject.toString().equals(JSONObject.toString())
and came across this similar method but it's really vague about what it compares.
"Determine if two JSONObjects are similar. They must contain the same set of names which must be associated with similar values." Link
What is that supposed to mean? How similar? Exactly the same?
I searched really hard and couldn't find anything that could clear it up.
Here's the source for JSONObject.similar():
/**
* Determine if two JSONObjects are similar.
* They must contain the same set of names which must be associated with
* similar values.
*
* #param other The other JSONObject
* #return true if they are equal
*/
public boolean similar(Object other) {
try {
if (!(other instanceof JSONObject)) {
return false;
}
if (!this.keySet().equals(((JSONObject)other).keySet())) {
return false;
}
for (final Entry<String,?> entry : this.entrySet()) {
String name = entry.getKey();
Object valueThis = entry.getValue();
Object valueOther = ((JSONObject)other).get(name);
if(valueThis == valueOther) {
continue;
}
if(valueThis == null) {
return false;
}
if (valueThis instanceof JSONObject) {
if (!((JSONObject)valueThis).similar(valueOther)) {
return false;
}
} else if (valueThis instanceof JSONArray) {
if (!((JSONArray)valueThis).similar(valueOther)) {
return false;
}
} else if (valueThis instanceof Number && valueOther instanceof Number) {
if (!isNumberSimilar((Number)valueThis, (Number)valueOther)) {
return false;
};
} else if (!valueThis.equals(valueOther)) {
return false;
}
}
return true;
} catch (Throwable exception) {
return false;
}
}
Essentially similar() recursively compares the names and values of the JSONObjects and returns true if they're the same.
First, it checks if the keySets are equal, then moves on to the values.
It recursively checks each value in the keySet to see if they are equal in each JSONObject. If not, it returns false.
The description you found relates to method JSONObject.similar(), which compares if two JSON objects are the same, but having perhaps a different order of its attributes.
The equals() will compare each string caracter, one-by-one checking if it is the same, having the same order.

Comparing An Entry In A Map With An Object

I have a Map in Java like so,
private HashMap<String, Object[][]> theMap;
Where the key is a String and the entry is going to be something along the line of,
theMap = new HashMap<>();
Object[][] theData = {
{Boolean.FALSE, "Text"}
};
theMap.put("Key1", theData);
Somewhere along the line I would like to check if an entry in the map is equivalent to another object. Currently I am doing it like this,
Object[][] tempData = {
{Boolean.FALSE, "Text"}
};
for(Object key: entries.keySet()) {
if(entries.get(key).equals(tempData)) {
entries.remove(key);
}
}
And it is not working.
I would prefer the comparison to be done with an object rather than with another map. I'm wondering what I'm doing wrong with this comparison here?
The reason you are not getting equality is that arrays inherit Object#equals() which is based on identity, not equality of contents. You could consider using java.util.Arrays.deepEquals(Object[], Object[]) to compare.
That is the answer to the immediate question. However, using a 2-dimensional array of Object to hold a boolean and a String is really bad code smell and indicates you need to encapsulate what you are putting in the array.
Identity vs Equivalence
Please make sure that you understand that by default the equals() method of Object checks on whether two object references are referring to the same object (identity), which is not what your code is checking.
Instead, your code is checking whether the two objects (the values you put on the map) are having the same value (equivalence).
Here are two articles about this topic:
What is the difference between identity and equality in OOP?
Overriding equals method in Java
In this particular problem of yours, I think the solution involves two steps:
Your tempData and theData does not seems to be an array
of elements of the same type (it does not appear to be a 2-dimensional
array either). Instead, it contains a Boolean value and then a
String value. In this case, I think you really should think
through what this thingy is and design a class for it (I am showing
an example below)
The class should override the equals() (and hashCode()) methods
so that you can use its equals() for equivalence checking.
Note also that your IDE (e.g. Eclipse) probably can generate a template for equals() and hashCode() for you.
Example: (here I assume your Boolean represents a condition, and your String represents a message)
class MyRecord {
private Boolean condition;
private String message;
public Boolean getCondition() {
return condition;
}
public void setCondition(Boolean condition) {
this.condition = condition;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((condition == null) ? 0 : condition.hashCode());
result = prime * result
+ ((message == null) ? 0 : message.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyRecord other = (MyRecord) obj;
if (condition == null) {
if (other.condition != null)
return false;
} else if (!condition.equals(other.condition))
return false;
if (message == null) {
if (other.message != null)
return false;
} else if (!message.equals(other.message))
return false;
return true;
}
}

contains giving faulty results

I have a class 'CoAutoria' that's suposed to hold 2 instances of an 'Author' class (which only has a name, for now) and the number of articles those authors have in common.
In order to figure out the top 10 of co-authors (regarding number of articles) I created a TreeSet of 'CoAutoria', to hold the total of articles, for each pair.
I need to cycle through a Map of years, gather the different authors and their respective Set of co-Authors. Then, for each pair, create an instance of 'CoAutoria' and: add it to the treeset (if it doesn't already exists); or simply sum its number of articles to the one existing on the set.
I already created the compareTo method, to insert it on the treeset, and created the equals method so that the order of the authors doesn't matter.
Here's the main code:`
public class CoAutoria implements Comparable<CoAutoria>
{
private Autor autor1;
private Autor autor2;
private int artigosComum;
(...)
}
#Override
public int compareTo(CoAutoria a2)
{
String thisAutor1 = autor1.getNome();
String thisAutor2 = autor2.getNome();
String caAutor1 = a2.getAutor1().getNome();
String caAutor2 = a2.getAutor2().getNome();
if((autor1.equals(a2.getAutor1()) && autor2.equals(a2.getAutor2())) || (autor1.equals(a2.getAutor2()) && autor2.equals(a2.getAutor1())))
{
return 0;
}
else
{
return 1;
}
}
#Override
public boolean equals(Object o)
{
if(this == o)
{
return true;
}
if( o == null || o.getClass() != this.getClass())
return false;
CoAutoria ca = (CoAutoria) o;
String thisAutor1 = autor1.getNome();
String thisAutor2 = autor2.getNome();
String caAutor1 = ca.getAutor1().getNome();
String caAutor2 = ca.getAutor2().getNome();
if((thisAutor1.equals(caAutor1) && thisAutor2.equals(caAutor2)) || (thisAutor1.equals(caAutor2) && thisAutor2.equals(caAutor1)))
{
return true;
}
else
{
return false;
}
}
The main problem is: When I check if the set already has a certain instance of 'CoAutoria', (I'm using the contains() method of TreeSet), it gives me faulty results...sometimes it checks correctly that the Pair A-B already exists in that set (on the form of B-A), but sometimes it doesn't... For what I've read, the contains uses the equals method, so that's not suposed to happen..right?
[EDIT:]
Since the first post I started to think that maybe the problem resided on the compareTo..So I changed it to
public int compareTo(CoAutoria a2)
{
String thisAutor1 = autor1.getNome();
String thisAutor2 = autor2.getNome();
String caAutor1 = a2.getAutor1().getNome();
String caAutor2 = a2.getAutor2().getNome();
if(this.equals(a2))
{
System.out.println("return 0");
return 0;
}
else
{
int aux = thisAutor1.compareTo(caAutor1);
if(aux != 0)
{
return aux;
}
else
{
return thisAutor2.compareTo(caAutor2);
}
}
}
But it still gives my bad results..I thought I'd figured it now: if it's the same 'CoAutoria', I return 0, if not I go through the names, and order it by their compareTo values..but something's missing
Your contains method is breaking, because your compareTo method is always returning 0 or positive, no negatives. This means your compareTo is inconsistent. A correct implementation should return 0 if the authors are the same, or positive and negative values when the authors are different.
Example (assuming author1 is different than author2):
int i = author1.compareTo(author2); // i should be positive or negative
int j = author2.compareTo(author1); // j should be the opposite of i
Yours will return 1 for both of the above cases, which will make ordered Collections not work as no element is ever smaller. As another example imagine if you had a Binary Tree(an ordered collection) that had the elements [1-10]. If you were searching for the element 5, your binary tree when comparing 5 against any element would always say that it was equal or greater.
How exactly you should change it is up to you. But an idea would be to sort the authors by name, then iterate over both collections and compare the authors together lexicographically.
EDIT: Even after your edit to your methods they are still not consistent. Try the following, they aren't the most efficient but should work unless you really want to optimize for speed. Notice they first sort to make sure author1 and author2 are in order before they are compared with the other CoAutor which is also sorted. I don't do any null checking and assume both are valid authors.
#Override
public boolean equals(Object o){
if (o == null || !(o instanceof CoAutoria)) return false;
if (o == this) return true;
return this.compareTo((CoAutoria)o) == 0;
}
#Override
public int compareTo(CoAutoria o) {
List<String> authors1 = Arrays.asList(autor1.getNome(), autor2.getNome());
List<String> authors2 = Arrays.asList(o.autor1.getNome(), o.autor2.getNome());
Collections.sort(authors1);
Collections.sort(authors2);
for (int i=0;i<authors1.size();i++){
int compare = authors1.get(i).compareTo(authors2.get(i));
if (compare != 0)
return compare;
}
return 0;
}

Searching an ArrayList for a String; always return false

I am having trouble with this method of my class. It always returns false.
Passenger is a separate class. This is a method in my Train class which creates an array list of Passenger objects. I am making a method that will search the ArrayList passengerList for a Passanger object with the name as the parameter.
public boolean search(String a){
Passenger temp;
boolean query = false;
for (int i =0; i<passengerList.size(); i++)
{
temp=passengerList.get(i);
if (temp.getName() == a)
{
query = true;
}
}
return query;
}
if (temp.getName() == a)
should be
if (temp.getName().equals(a))
String comparison should always use equals() method instead of == (except that strings literals).
if temp.getName() and a both not pointing to same object, == condition will fail.
== checks for references equality. equals() checks for content equality.
This tutorial may help you.
if (temp.getName() == a) should be if (temp.getName().equals(a)).
The former compares references for equality. The latter actually checks to see if the string values are equal.
I would suggest writing this code more elegant and cleaner (with checking for null):
public boolean search(String a){
boolean query = false;
for (Passenger temp : passengerList)
{
if (temp != null && temp.getName()!=null && temp.getName().equals(a))
{
query = true;
}
}
return query;
}

How to compare value in array?

how to compare value in an array?
I have array named list which contains 12 elements. I see if value in index 0 is equal or not equal to value in index 2.
I have tried this code but it doesnt seems to work.
if ((list.get(0)==list.get(2) && list.get(1)==list.get(3))
{
System.out.println("equal")
}
If it's really an array, you want:
if (list[0] == list[2] && list[1] == list[3])
Note that if the array is of reference types, that's comparing by reference identity rather than for equality. You might want:
if (list[0].equals(list[2])) && list[1].equals(list[3]))
Although that will then go bang if any of the values is null. You might want a helper method to cope with this:
public static objectsEqual(Object o1, Object o2)
{
if (o1 == o2)
{
return true;
}
if (o1 == null || o2 == null)
{
return false;
}
return o1.equals(o2);
}
Then:
if (objectsEqual(list[0], list[2]) && objectsEqual(list[1], list[3]))
If you've really got an ArrayList instead of an array then all of the above still holds, just using list.get(x) instead of list[x] in each place.
if(list[0] == list[2] && list[1] == list[3]){
System.out.println("equal");
}
If they are strings:
if(list[0].equals(list[2]) && list[1].equals(list[3])){
System.out.println("equal");
}
You are comparing object references, not objects themselves. You need to use a method call. All classes inherit equals() from the root Object class, so it might work:
if(list.get(0).equals(list.get(2)) && list.get(1).equals(list.get(3)))
{
System.out.println("equal");
}
This article seems to be a good summary of other comparison methods available.

Categories

Resources