HashMap get comes back with null even tho key is in it - java

I'm trying to create a swing chessboard with icons and i have trouble with putting the icons onto the JButtons using a HashMap.
Here are the classes that i'm working with:
Main Class
public class GameGUI extends JFrame {
private JButton tiles[][] = new JButton[8][8];
private HashMap<PieceKey, ImageIcon> icons = new HashMap<>();
public GameGUI(){
//swing shenannigans
initImages();
Tile[][] fenTiles = game.getFen().getTiles();
for(int row = 0; row <= 7; row++){
for(int column = 0; column <= 7; column++){
Piece piece = fenTiles[row][column].getPiece();
if(piece != null) {
tiles[row][column].setIcon(icons.get(new PieceKey(piece.getType(), piece.getColor())));
}
}
}
}
public void initImages(){
icons.put(new PieceKey(PieceType.pawn, Team.white), new ImageIcon("pieces/wpawn.png"));
//.....
}
public static void main(String args[]){
GameGUI asd = new GameGUI();
}
}
PieceKey class
public class PieceKey {
PieceType type; //enum
Team color; //enum
public PieceKey(PieceType type, Team color) {
this.color = color;
this.type = type;
}
#Override
public boolean equals(Object o){
if(this == o)
return true;
if(!(o instanceof PieceType))
return false;
PieceKey key = (PieceKey) o;
return this.type == key.type && this.color == key.color;
}
#Override
public int hashCode(){
return type.toString().hashCode() * color.toString().length();
}
}
Team enum
public enum Team {
white, black;
}
PieceType enum
public enum PieceType {
pawn, rook, knight, bishop, king, queen;
}
My problem is that whenever i call
icons.get(new PieceKey(piece.getType(), piece.getColor()));
It return null, so i cant put the icons onto the buttons, it works fine if i do it manually so the problem is with the HashMap. I tried to override the equals and the hashcode function in the PieceKey class but it doesn't seem to work.

The problem may be in your PieceKey equals method. You are using incorrectly PieceType while using instanceof:
#Override
public boolean equals(Object o){
if(this == o)
return true;
// Please, note this, it will always return false, and the `Map`
// `equals` method for `get` and `put` will not work
if(!(o instanceof PieceType))
return false;
PieceKey key = (PieceKey) o;
return this.type == key.type && this.color == key.color;
}
If should be:
#Override
public boolean equals(Object o){
if(this == o)
return true;
// Please, note this
if(!(o instanceof PieceKey))
return false;
PieceKey key = (PieceKey) o;
return this.type == key.type && this.color == key.color;
}

The Answer by jccampanero seems correct about you having a problem with the implementation details of your override of Object :: equals.
Record
Another solution is to avoid even needing to write your own equals and hashCode. If your PieceKey class is meant primarily to transparently and immutable carry data, define the class as a record.
Your entire class reduces to this simple short line.
public record PieceKey ( PieceType type , Team color ) {}
As a record, the compiler implicitly creates the constructor, getters, equals & hashCode, and toString.
You make an instance in the same way as with a conventional class.
new PieceKey( PieceType.pawn , Team.white )
Bonus tip: In Java 16 and later, as part of the work done to create the records feature, we can now declare records, enums, and interfaces locally.

You should use your IDE to generate your hashCode and equals implementation.
The most default implementation you should have should be something like:
#Override
public int hashCode() {
return Objects.hash(type, color); // java.util.Objects
}
#Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof PieceKey) return false;
PieceKey other = (PieceKey) o;
return Objects.equals(type, other.type)
&& Objects.equals(color, other.color);
}
Note that you don't need this at all with Java 17 records:
public record PriceKey(PieceType type, Team color) {}
hashCode() and equals() are by generated using type/color.
type and color are final by default.

Related

When trying to overwrite a equals method in Java, it won't compare the values only the object itself?

In this exercise, I need to create a equals() method for a Drink class. Two drinks are the same if they have the same name and same size. I am receiving false from testing the method, even though I'm certain it should be true.
The main code:
public class Drink {
private String name;
private double size;
public Drink(String name, double size)
{
this.name = name;
this.size = size;
}
public String getName()
{
return name;
}
public double getSize()
{
return size;
}
//I tried to stringify the double values
public boolean equals(Drink a, Drink b){
String q = String.valueOf(a.getSize());
String w = String.valueOf(b.getSize());
if(q.equals(w) && a.getName().equals(b.getName())){
return true;
}
else{
return false;
}
}
}
The tester Code:
public class DrinkTester
{
public static void main(String[] args)
{
Drink one = new Drink("Soda", 12);
Drink two = new Drink("Soda", 12);
Drink three = new Drink("Soda", 20);
System.out.println(one.equals(two));
System.out.println(one.equals(three));
}
}
You need to override the equals method, if you use the
#Override annotation you'll see if you're doing it right.
public boolean equals(Object obj) {
return (this == obj);
}
That is the Object one, so yours might for example look like:
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Drink drink = (Drink) obj;
return this.size.equals(drink.size)
&& this.name.equals(drink.name);
}
you'll also have to override your hashCode if you want your code to work optimally.
(And i've only recently noticed that if you use Objects.hash in your overridden hashCode method, your overridden equals method won't get used, the Objects one will get used instead)

Optimize two lists with shared objects

I have the following two lists:
List<Animal> AllAnimals;
List<Animal> AnimalsWithEyes;
Since there are a lot of animals in the world and there are a lot of the same animals, objects, in both lists, as many have eyes, it would be kind of cool if there were a way to optimize the memory efficiency by not having duplicate objects cluttering up the RAM.
As an additional problem, the Animals in AllAnimals are ordered alphabetically, meaning that we can't just say that the first block of indexes is animals with eyes.
Any ideas on how Java can support such behavior?
Perhaps you should consider using java.util.Set and java.util.TreeSet for natural ordering(if needed be). The Set interface specification ensures, that no two equal objects exist in a Set.
Override Animal#equals, Animal#hashcode and implements Comparable interface. For example:-
public class Animal implements Comparable<Animal>{
private final String name;
private final boolean hasEyes;
public Animal(String name, boolean eyes){
this.name = name;
this.hasEyes = eyes;
}
public String getName() {
return name;
}
public boolean isHasEyes() {
return hasEyes;
}
#Override
public int hashCode() {
int hash = 5;
hash = 29 * hash + Objects.hashCode(this.name);
hash = 29 * hash + (this.hasEyes ? 1 : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Animal other = (Animal) obj;
if (this.hasEyes != other.hasEyes) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
}
#Override
public int compareTo(Animal o) {
//....compareTo implementation.
}
}
Finally "intersections" between 2 List<Animal> consolidated into a Set<Animal>.
Set<Animal> s = new TreeSet<>();
s.addAll(allAnimals);
s.addAll(animalWithEyes);
The Set#addAll implementation ensure no duplicate Animal exist.
*** Or you could use project Lombok annotations to generate equals, hashcode and Comparable implementations.

my deterministic turing machine won't work, because my equals and indexof method throw no source error

I have the problem, that my equals method doesnt work as i want it to. I want to implement a deterministic turing machine, so I want to add the method findCommand(), which searchs through a arraylist of commands. So I decided to create a searchDummy to find all Transitions that are available for the Configuration I have.
Class States:
public class States {
private int stateId;
private boolean rejState;
private boolean accState;
private boolean stopState;
private List<Commands> commands = new ArrayList<Commands>();
equals in class States:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof States) {
States otherState = (States) other;
return (stateId == otherState.stateId);
} else {
return false;
}
}
hashCode:
#Override public int hashCode() {
StringBuilder b = new StringBuilder(stateId);
return b.toString().hashCode();
}
this is the findCommand method in States:
public Commands findCommand(States state, char inputTapeChar,
char[] tapeChars) {
Commands searchDummy = new Commands(state, inputTapeChar, tapeChars,
null, null, null, null);
int pos = commands.indexOf(searchDummy);
return pos >= 0 ? commands.get(pos) : null;
}
commands is my arraylist, so I want to find the searchDummy with indexOf().
I have the class Commands, which holds the attribute Configuration configuration, the class Configuration, which holds the attributes of a Configuration and the attribute Transition transition and the class transition that holds the attributes for itself.
Class Commands:
public class Commands implements Comparable<Commands> {
private Configuration configuration;
Class Configuration:
public class Configuration {
private Transition transition;
private States state;
private char inputTapeChar;
private char[] tapeChars;
Class Transition:
public class Transition {
private States targetState;
private Direction inputTapeHeadMove;
private char[] newTapeChars;
private Direction[] tapeHeadMoves;
i have this equals method in Commands:
#Override public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof Commands) {
Commands otherCmd = (Commands) other;
return (configuration.equals(otherCmd.configuration));
} else {
return false;
}
}
and this hashcode
#Override
public int hashCode() {
StringBuilder b = new StringBuilder(configuration.getState() + ","
+ configuration.getInputTapeChar());
for (char c : configuration.getTapeChars()) {
b.append("," + c);
}
return b.toString().hashCode();
}
then almost the same in Configuration:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof Configuration) {
Configuration otherConfi = (Configuration) other;
return (state.equals(otherConfi.state))
&& (inputTapeChar == otherConfi.inputTapeChar)
&& (Arrays.equals(tapeChars, otherConfi.tapeChars));
} else {
return false;
}
}
hashcode:
#Override
public int hashCode() {
StringBuilder b = new StringBuilder(state + "," + inputTapeChar);
for (char c : tapeChars) {
b.append("," + c);
}
return b.toString().hashCode();
}
equales in class State:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof States) {
States otherState = (States) other;
return (stateId == otherState.stateId);
} else {
return false;
}
}
so my question:
when I debug this it goes through until it's finished with the checks but when it should return the value it stucks at Configuration.equals(...) and shows the error no source found!
what is the problem? Are the hashcodes wrong? Or are the equals wrong?
I never used equals before so I dont know when i need to use it or how i need to fix this. thanks for your help.
Your hashCode implementation looks suspect - all that String stuff is not standard.
For example for your Transition class should be something like this:
#Override
public int hashCode() {
int result = 17;
result = 31 * result + targetState.hashCode();
result = 31 * result + inputTapeHeadMove.hashCode();
result = 31 * result + newTapeChars.hashCode();
result = 31 * tapeHeadMoves.hashCode();
return result;
}
Most IDEs will offer autogen of hashCode and equals methods.

How to remove duplicates in the Java HashSet

I have a set of this structure. How to remove duplicates of equal object of that class? Equals means field File plik is the same.
EDIT:
But the problem gut bigger I don't have duplicates but I would like to replace old SET member by new.
Withoud 3rd party libraries.
import java.io.*;
public class WordInfo implements Serializable {
File plik;
Integer wystapienia;
public WordInfo(File plik, Integer wystapienia) {
this.plik = plik;
this.wystapienia = wystapienia;
}
public String toString() {
// if (plik.getAbsolutePath().contains("src") && wystapienia != 0)
return plik.getAbsolutePath() + "\tWYSTAPIEN " + wystapienia;
// return "";
}
}
EDIT
I don't have this HashCodeBuilder I want to use Java standard libraries
public int hashCode() {
return new HashCodeBuilder(17, 31).append(plik).append(wystapienia).toHashCode();
}
public boolean equals(Object obj) {
File f = (File) obj;
return(plik.getAbsoluteFile().equals(f.getAbsolutePath()));
}
As discussed here, override equals.
public class Person {
private String name;
private int age;
// ...
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
// if deriving: appendSuper(super.hashCode()).
append(name).
append(age).
toHashCode();
}
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (obj.getClass() != getClass())
return false;
Person rhs = (Person) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
append(age, rhs.age).
isEquals();
}
}
public class WordInfo implements Serializable {
File plik;
Considering that following is how you can override the equals and hashCode method as per your requirement:
#Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof WordInfo)) return false;
return this.plik.equals(((WordInfo) obj).plik);
}
#Override
public int hashCode() {
return this.plik.hashCode();
}

How to implement hashCode and equals method

How should I implement hashCode() and equals() for the following class in Java?
class Emp
{
int empid ; // unique across all the departments
String name;
String dept_name ;
String code ; // unique for the department
}
in Eclipse right mouse click-> source -> generate hashCode() and equals() gives this:
/* (non-Javadoc)
* #see java.lang.Object#hashCode()
*/
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (code == null ? 0 : code.hashCode());
return result;
}
/* (non-Javadoc)
* #see java.lang.Object#equals(java.lang.Object)
*/
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Emp))
return false;
Emp other = (Emp) obj;
return code == null ? other.code == null : code.equals(other.code);
}
I've selected code as a unique field
try this code, use org.apache.commons.lang3.builder
public int hashCode() {
return new HashCodeBuilder(17, 31). // two randomly chosen prime numbers
append(empid).
append(name).
append(dept_name ).
append(code ).
toHashCode();
}
public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
Emp rhs = (Emp) obj;
return new EqualsBuilder().
// if deriving: appendSuper(super.equals(obj)).
append(name, rhs.name).
isEquals();
}
Guava has helper methods for creating them. You tell it which fields to take in consideration and it will handle nulls for you and do the prime number calculation for hashcode.
IDEs can also generate them based on the fields you choose.
The advantage of delegating it to a tool like that is you get a standard solution and will worry less about bugs and maintenance of varied implementations spread all over your project.
Here's an example of using Guava and generated by an IntelliJ plugin: https://plugins.jetbrains.com/plugin/7244?pr=
If code is unique (i.e. your business key), it's best to only use the code for equals and hashCode - it's good practice to seperate business key (code) from object id (id).
Here's a nice read: Hibernate Documentation: Equals and HashCode (valid not only for Hibernate itself)
what ever values you use in equals to determine if two objects are the same, are the the values that you need to use to create a hash code.
public boolean equals(Object o) {
boolean result = false;
if(o instanceof CategoryEnum) {
CategoryEnum ce = (CategoryEnum) o;
result = ce.toString().equals(name);
}
return result;
}
public int hashCode()
{
int hash = 6;
hash += 32 * name.hashCode();
return hash;
}
equals()and hashcode(),They have a lot of different places.
equals(),if we don't Override it from Object,it represent that whether two variables are pointing to the same object heap?
public Class Student(){
private int id;
private name;
public Student(int id,String name){
this.name=name;
this.id=id;
}
public void main(String[] args){
Student A=new Student(20,'Lily');
Student B=new Student(20,'Lily');
boolean flag=A.equals(B)//flag=flase;
/*
*Although they attribute the same, but they are two different objects, they point to different memory
*/
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (this.getClass() != obj.getClass()) {
return false;
}
Student s=(Student)obj;
return new Integer(this.id).equals(new Integer(s.id))&&this.name.equals(s.name);
}
/**
*Sometimes even though we Override the equals, but we still can not determine whether the *two objects the same,
*In the collection object, such as HashSet, this time we have to Override the hashoCode ()
*/
public int hashCode(){
return id + name.hashCode() ;
}

Categories