overide the equal, toString, hashcode methods in Enum - java

I have one Enum like Below
public enum Game {
CRICKET("cricket"),
FOOTBALL("football"),
VOLLEYBALL("volleyball")'
private String val;
private Game(String val) {
this.val = val;
}
public String getValue() {
return this.val;
}
}
In here, Do I want to overide the equal(),hashCode(),toString() methods
based on this What issues should be considered when overriding equals and hashCode in Java?

Question is meaningless, because you cannot override equal() and hashCode() of an enum.
That is because they are defined as final in the Enum class, which implicitly is the base class of all enum types.

No, enum is not a regular class (and as Andreas pointed out, they're final methods). For example, you don't need to use equals() to compare them, as there is a single instance of each enum value. This allows you to use == instead.
if(gameType == Game.CRICKET)
You can override toString(), as by default it prints the same as name(), which is just the name of the enum (e.g. FOOTBALL).

My first question is why you would need the enum to contain a String in the first place. The point of your enum already looks like it is to differentiate each type of game within a certain list of possible games. So the enum itself here functions as a constant value. For example you could do:
public void playGame( Game myGame ){
switch(myGame){
case FOOTBALL:
playFootball();
break;
case CRICKET:
playCricket();
break;
// and so on but you get the point
}

Related

Creating a method that can only input a certain types of strings that are predetermined

I have the following type of Strings
"Move 1 place forwards";
"Move 1 place backwards;
Can I create a type called 2dMotion, where a method can only take in these two strings as arguments in Java.
public 2dMotion message(){ return "Move 1 place forwards"; }
For example if a method was classed that had 2dMotion as an input then it wouldn't be able to input anything but those 2 sentences
You can declare them as constants in a class, and provide direct access to them by making them public:
public MyClass {
public static final MOTION_FORWARD = "Move 1 place forward";
public static final MOTION_BACKWARDS = "Move 1 place backwards";
// Rest of the class omitted
}
Or, a better solution is to use an Enum.
public enum MOTION {
FORWARD("Move 1 place forward"),BACKWARDS("Move 1 place backwards");
private final String val;
private MOTION(String val) {
this.val = val;
}
public String getVal() {
return val;
}
}
To use the constant, simply use MyClass.MOTION_FORWARD. To use the enum, you could do MOTION.FORWARD.getVal();
Lastly, as good practice, you should override toString() method:
#Override
public String toString() {
return val;
}
Even though this method does the same as getVal(), it is consider good practice to do so. If you would like to remove one of those methods, it should be the getVal() method. Also, even though the enum solution involves more code, it is also considered to be a better solution. Also, when you override toString(), it allows to return the value of the enum without invoking toString() or getVal() directly. For example, System.out.println(MOTION.BACKWARDS); prints out "Move 1 place backwards".

Is there a way to require a particular value as a parameter in an abstract Interface method in Java?

I'm writing a little functional Interface and the method that it contains, takes an int as parameter. I was wondering if there's any way to check that when this method will be called, the value passed to the method, will not exceed a certain value and if it does, throw an error. Is there maybe an annotation I can add?
This is what my interface looks like
public interface DrawCardHandler{
void onDrawCard(int slot);
}
Define a class
Rather than pass around a mere int primitive, define a class to represent your specific meaning.
public final class Slot {
private int value;
public Slot(int value) { // Constructor.
if(/** your check goes here **/) {
throw new IllegalArgumentException("...");
}
this.value = value;
}
// getter etc. goes here.
}
In Java 16 and later, use the records feature. A record is a brief way to write a class whose main purpose is to communicate data transparently and immutably. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString. We can choose to write an explicit constructor to validate the input.
public record Slot (int value) {
public Slot(int value) { // Constructor.
if(/** your check goes here **/) {
throw new IllegalArgumentException("...");
}
this.value = value;
}
// The getters, equals & hashCode, and toString are implicitly created by compiler.
}
Then your interface could look like:
public interface DrawCardHandler{
void onDrawCard(Slot slot);
}
Define an enum
In general, if you know all possible slots in advance, you can create an enum for Slot instead of a class like I've shown - it will be even more expressive.

Is it necessary to have toString() in an enum in Java?

I don't think we can instantiate an Enum. So do we need to have toString(), equals() and hashCode() method for an enum? Is this statement true?
Also as a follow up question
What does "this" keyword refers to in the following enum class?
public enum DocuType {
text, print, html, pdf; //Why aren't these in caps?
public boolean isPrint() {return this == print; } //What does this refers to?
public boolean isText() {return this == text; }
public boolean isTextOrPrint() { return isText() || isPrint(); }
}
How do I call any of the boolean methods of this enum as they are not static?
Also when I call, what does the keyword "this" refers to ?
I don't think we can instantiate an Enum.
Enum is one of type as we have class type. The way we can create instance (i.e. create variable) of a class, similarly we can create variables of Enum but that's only during during its definition which eventually makes them a Constant.
So do we need to have toString(), equals() and hashCode() method for an enum?
equals() & hashcode() are used to compare two instances. In case of class instances, the instances are created dynamically. So this means we don't have knowledge about instances beforehand and hence we need to compare them to know if they are equal. However, in case of Enum we know the instances when we define the Enum. So, we know beforehand whether they are equal or not. If the enum instances mean to be equal why on the earth we need two separate equal enum instances. So, in case of enum we generally don't override these methods.
What does "this" keyword refers to in the following enum class?
&
How do I call any of the boolean methods of this enum as they are not static?
&
Also when I call, what does the keyword "this" refers to ?
this means an instance currently in access. In your example, you have DocuType instances as text, pdf, print, html. When you invoke a method on any of the instance, ex: DocuType.text.isPrint(), this keyword inside the isPrint method will point to text. So, for instance pdf, all the methods will return false except isPdf().
So do we need to have toString(), equals() and hashCode() method for an enum? Is this statement true?
You don't need any of these methods in the enum.
Also as a follow up question What does "this" keyword refers to in the following enum class?
Imagine you have this code:
DocuType myType = DocuType.print;
If you want to check if the document is a PRINT document, you can do this:
boolean isPrint = myType.isPrint();
In this case, this is the myType, which means that it's the print enum. In the end, the result is true, because print == print;
I would also suggest to read the Tutorial to Enums
It seems you lack the knowledge of the concept of an enum.
And to your last question, an enum is static, but each "type" of it is an object, meaning you can do
DocuType.html.isText(); // false
DocuType.print.isPrint(); // true
To initalize your own Enum you have to
DocuType TextDocu = DocuType.text;
And you can write them in CAPS, but you don't have to, but it's recommened.
To explain it more in detail:
enum DocuType //this is an enum and not instantiatable
text,print,html,pdf // these are Objects with the functions of the enum and are an instance
As preparation for an explanation, a quick glance back in history.
Before enums were available in Java, a possible replacement could have been constructed like that:
public class DocuType {
public final static DocuType text=new DocuType();
public final static DocuType print=new DocuType();
public final static DocuType html=new DocuType();
public final static DocuType pdf=new DocuType();
private DocuType(){}; // hide constructor
public boolean isPrint() {return this == print; }
public boolean isText() {return this == text; }
public boolean isTextOrPrint() { return isText() || isPrint(); }
}
As you can see, while you cannot create new instances of DocuType, 4 static instances of them are already prepared for you in the Class.
Javas enum work very similar to that example (less writing involved, obviously); therefore, this refers to the instance you execute the method on. Regarding toString, it's up to you; the default implementation can be good enough or not. There is no need to implement neither equals nor hashCode.

Comparing two comparator objects in Java

If I do the following
myObject.myMethod(myClass.getComparator());
with
public void myMethod(Comparator<? super myOtherObject> comparator) {
if (comparator.equals(myClass.getComparator()) {
//do sth
}
}
and in myClass
static Comparator<ListItem> getComparator() {
return new Comparator<myOtherObject>() {
public int compare(myOtherObjectitem1, myOtherObjectitem2) {
return (Integer.valueOf(myOtherObject.getRating()).compareTo(Integer.valueOf(myOtherObject.getRating())));
}
};
}
then "//do sth" is not gonna be executed. So the objects I get from getComparator the two times are different. How can that be? Is there a chance to see, which comparator "myMethod" gets?
You're calling the equals method on this line:
if (comparator.equals(myClass.getComparator())
Since you haven't defined this method explicitly on your Comparator class (which is an anonymous inner class), this defaults to the version inherited from Object - which considers two references equal only if they are the exact same object.
And your getComparator() method states return new Comparator() { ... }, so it's calling the constructor and creating a new object each time it's called. Thus the result of one call to getComparator will be a distinct object, and hence will not be considered equal to, the result of another call.
I can think of two possible ways to change your code so that the equality test returns true:
Create the comparator only once, and return this same object from
getComparator. This would involve a change somewhat like the
following in myClass:
private static Comparator<ListItem> cmp = new Comparator<myOtherObject>() {
public int compare(myOtherObjectitem1, myOtherObjectitem2) {
return (Integer.valueOf(myOtherObject.getRating()).compareTo(Integer.valueOf(myOtherObject.getRating())));
}
};
static Comparator<ListItem> getComparator() {
return cmp;
}
Provide an explicit equals() implementation (and thus a hashCode() one too, ideally). You can then control exactly which objects are considered equal to one of your comparators. This might be much easier if you define a concrete class for your comparator rather than it being an anonymous inner class.
At the end of the day, though, I fear your approach might not be right. What does it mean for two comparators to be equal to one another? I feel this is an ambiguous concept for anything other than data classes, and I would be hesitant to use the Object.equals method for this.
(For example, if by equality you mean "they will sort lists in the same order", then I'd add a method to your comparator class called isEquivalentSortOrder or something similar. This way you can specify exactly what you mean without having to rely on the woolly definition of "being the same".)
Why not to create inside myClass static variable of Comparator like:
class myClass{
public static Comparator<ListItem> = new Comparator<myOtherObject>() {
public int compare(myOtherObjectitem1, myOtherObjectitem2) {
...
}
};
}

HashMap.containsKey() - how to search for a class?

Hello
if you search in an HashMap<String,String> for a specific value of a key-value-pair, you can write the following:
myHashMap.containsKey(myString);
But how can I manage it if the key is not a string? I have a class which looks like this:
public class Kategorie implements Comparable {
private String name;
public Kategorie() {
super();
}
public Kategorie(String name) {
setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public int compareTo(Object o) {
if (!(o instanceof Kategorie))
throw new ClassCastException();
Kategorie k = (Kategorie)o;
String name = k.getName();
return this.getName().compareTo(name);
}
}
In a map I saved keys and values of this type "Kategorie".
mapKategorieDEundEN.put(new Kategorie(strName_de), new Kategorie(strName_en));
Later in the code, I want to check if there is a key with a specific string.
if (mapKategorieDEundEN.containsKey(searchString)) {
...doesn't work, because the key is not a string but a "Kategorie", that's clear.
Then I tried something like this:
if (mapKategorieDEundEN.containsKey(new Kategorie(searchString))) {
...doesn't work too. I assume that it doesn't find anything because the object is not the "original" object but a new one.
In this case, can I use containsKey at all or do I have to use a loop over the HashMap?
You class should override equals and hashCode, it will work after that.
The HashMap/Hashtable puts the items in "buckets" by using the hashCode of the key, so a new object that represents the same value as another object, and which should be considered as the same object must return the same hashCode. All keys that return the same hashCode will then be considered as candidates, and equals will be invoked on them. It's considered a match if equals returns true.
HashMap uses hashCode() and equals(). You have to implement them. If you don't know how. Check your IDE (eclipse) usually can generate them for you.
If you want to access your objects using your compareTo method, you should not use a hashCode/equals based Map, but a SortedMap, like TreeMap (or ConcurrentSkipListMap).
This has the added benefit that it enables range-based queries (e.g. "give me all categories larger than this one"), but is a bit slower (O(log n) instead of O(1)) for simple get accesses compared to hash-based access (with a good hash code, not a constant one).
For a general use class, defining both hashCode/equals and compareTo would be sensible, then the user of the class can decide which type of map to use. (If there are different ways to sort your objects, better provide different Comparator objects.)
As a side remark, you should not implement Comparable, but Comparable<Kategorie>. Then your compareTo method would look like this:
public int compareTo(Kategorie k) {
String name = k.getName();
return this.getName().compareTo(name);
}

Categories