This question already has answers here:
Why different class files are created for each enum type if they have constant-specific method?
(2 answers)
Closed 4 years ago.
I am learning the various options that an enum can provide to us. I have learnt about constructors, methods and overriding methods in it.
The code samples are below.
I have one question though.
In this case, getClass() returns class enumData.WeekEnumElaborate$1, enumData.WeekEnumElaborate$2 and so on until enumData.WeekEnumElaborate$8
But, when the enum is a simple one, with just constants declared, getClass() returns enumData.WeekEnumElaborate.
Kindly explain me this binary notation.
Here is a enum that I have defined.
package enumData;
public enum WeekEnumElaborate {
SUNDAY("SUN") {
public String getDescription() {
return this.getShortForm().concat(" Funday");
}
},
MONDAY("MON") {
public String getDescription() {
return this.getShortForm().concat(" Moot");
}
};
private final String shortForm;
private WeekEnumElaborate(String shortForm) {
this.shortForm = shortForm;
}
public String getShortForm(){
eturn this.shortForm.toLowerCase();
}
public abstract String getDescription();
}
And here is a class that I am testing.
package enumData;
public class TestWeekEnumElaborate {
public static void main(String[] args) {
WeekEnumElaborate[] days = WeekEnumElaborate.values();
for (WeekEnumElaborate day : days) {
System.out.println(day.name());
System.out.println(day.getClass());
System.out.println(day.getDeclaringClass());
}
}
}
When you give an enum different behaviour to the outer enum class, you are effectively defining an anonymous static inner class which is a subclass of the base enum class.
The names of these nested classes are named same way anonymous inner classes are named. Ie outer class + $ + counter.
This allows each enum to have different method implementations for the same signature.
You are currently defining anonymous inner classes in your enum definition, which is the part I was referring to when I asked you to not write code like this. To elaborate, the way I would implement your original enum would be something like
public enum WeekEnumElaborate {
SUNDAY("SUN", "Funday"), MONDAY("MON", "Moot"), TUESDAY("TUE", "Terrible"),
WEDNESDAY("WED", "Weed"), THURSDAY("THUR", "Terrific"), FRIDAY("FRI", "Fairy"),
SATURDAY("SAT", "Jollyday"), R$00("R$00", "RX100 Day");
private final String shortForm;
private final String description;
private WeekEnumElaborate(String shortForm, String description) {
this.shortForm = shortForm;
this.description = description;
}
public String getShortForm() {
return this.shortForm.toLowerCase();
}
public String getDescription() {
return new StringBuilder(getShortForm()).append(' ').append(this.description).toString();
}
public String getFurtherDescription(String desc) {
if (this == MONDAY) {
return "I do not want to work on this day!!!!";
}
return getDescription();
}
}
No anonymous classes required, and it is significantly shorter and easier to reason about.
Related
I have two enums:
Main Menu Options
public enum MainMenuOptions {
EXIT("Exit"),
VIEW_RESERVATIONS("View Reservations By Host"),
CREATE_RESERVATION("Create A Reservation"),
EDIT_RESERVATION("Edit A Reservation"),
CANCEL_RESERVATION("Cancel A Reservation");
private final String message;
MainMenuOptions(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public static List<String> asListString() {
return Arrays.stream(MainMenuOptions.values())
.map(MainMenuOptions::getMessage)
.collect(Collectors.toList());
}
}
Host Selection Method Options
public enum HostSelectionMethodOptions {
FIND_ALL("Find all"),
FIND_BY_LASTNAME_PREFIX("Find by last name prefix"),
FIND_BY_CITY_STATE("Find by city & state");
String message;
HostSelectionMethod(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public static List<String> asListString() {
return Arrays.stream(HostSelectionMethod.values())
.map(HostSelectionMethod::getMessage)
.collect(Collectors.toList());
}
}
Both enums share the same field
private final String message;
The same getter
public String getMessage() {
return message;
}
And the same asListString() method
public static List<String> asListString() {
return Arrays.stream(MainMenuOptions.values())
.map(MainMenuOptions::getMessage)
.collect(Collectors.toList());
}
How can I DRY out these enums?
I expect to have more enums with the same fields and methods, and it seems silly to write out the same thing over and over again for each one.
I tried making both of the enums extend a superclass, but enums cannot have extends clauses
I can create an interface that specifies the contract for the asListString() method, but that doesn't allow me to actually reuse any code.
The flavor I was hoping the code could have is something like this:
public class Utils {
public static List<String> enumAsListString(Enum e) {
return e.values().stream.map(e::getMessage).collect(Collectors.toList());
}
}
This is probably one of the cases where you need to pick one between being DRY and using enums.
Enums don't go very far as far as code reuse is concerned, in Java at least; and the main reason for this is that primary benefits of using enums are reaped in static code - I mean static as in "not dynamic"/"runtime", rather than static :). Although you can "reduce" code duplication, you can hardly do much of that without introducing dependency (yes, that applies to adding a common API/interface, extracting the implementation of asListString to a utility class). And that's still an undesirable trade-off.
Furthermore, if you must use an enum (for such reasons as built-in support for serialization, database mapping, JSON binding, or, well, because it's data enumeration, etc.), you have no choice but to duplicate method declarations to an extent, even if you can share the implementation: static methods just can't be inherited, and interface methods (of which getMessage would be one) shall need an implementation everywhere. I mean this way of being "DRY" will have many ways of being inelegant.
If I were you, I would simply make this data completely dynamic
final class MenuOption {
private final String category; //MAIN_MENU, HOT_SELECTION
private final String message; //Exit, View Reservation By Host, etc.
public static MenuOption of(String key, String message) {
return new MenuOption(key, message);
}
}
This is very scalable, although it introduces the need to validate data where enums would statically prevent bad options, and possibly custom code where an enum would offer built-in support.
It can be improved with a "category" enum, which gives static access to menu lists, and a single place for asListString():
enum MenuCategory {
MAIN_MENU(
MenuOption.of("Exit"),
MenuOption.of("View Reservations By Host")
),
HOT_SELECTION(
MenuOption.of("Find All")
);
private final List<MenuOption> menuOptions;
MenuCategory(MenuOption... options) {
this.menuOptions = List.of(options); //unmodifiable
}
public List<String>asListString() {
return this.menuOptions.stream()
.map(MenuOption::getMessage)
.collect(Collectors.toList());
}
}
It should be clear that you can replace class MenuOption with a bunch of enums implementing a common interface, which should change little to nothing in MenuCategory. I wouldn't do that, but it's an option.
I basically had the same idea as davidalayachew.
An enum can implement an interface. So if you create a common asListString which accepts an enum type, you could get the desired result.
First, create an Options interface and let both enums implement it:
interface Options {
String getMessage();
}
enum HostSelectionMethodOptions implements Options { ... }
enum MainMenuOptions implements Options { ... }
Now create a method like this:
public static <T extends Enum<T> & Options> List<String> asListString(Class<T> type) {
return Arrays.stream(type.getEnumConstants())
.map(T::getMessage)
.collect(Collectors.toList());
}
The method declares a type argument: <T extends Enum<T> & Options>. Here, T is an intersection type, so it extends both Enum and the Options interface. You can call it like this:
asListString(MainMenuOptions.class);
You can DRY it a little.
Utils.java
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public interface Utils<T>
{
public String getMessage();
public static <T extends Utils<T>> List<String> asListString(Class<T> clazz)
{
return Arrays.stream(clazz.getEnumConstants())
.map(T::getMessage)
.collect(Collectors.toList());
}
}
HostSelectionMethodOptions.java
public enum HostSelectionMethodOptions implements Utils<HostSelectionMethodOptions> {
FIND_ALL("Find all"),
FIND_BY_LASTNAME_PREFIX("Find by last name prefix"),
FIND_BY_CITY_STATE("Find by city & state");
private final String message;
HostSelectionMethodOptions(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
Then just do this - Utils.asListString(HostSelectionMethodOptions.class);
I have two similar classes, each with a single field of the same type.
class Fruit {
private final String name;
}
class Vegetable {
private final String name;
}
I'd like to implement hashCode() for each. My problem is that in my case, collisions between names are somewhat more possible than with "apple" and "carrot," and they both might be in the same Map/Set. I'm wondering what's the most clear way of implementing hashCode to handle this.
So far, I've considered Objects.hash(this.getClass(), name), Objects.hash(<some int unique to this class>, name). I like the first just because it's a bit more self-documenting and robust than the second, but it's not a pattern I've seen in the wild. I also considered <some prime int unique to this class> * Objects.hashCode(name), but that felt fragile, especially if a new field gets added.
Assuming the 2 classes extend a common parent class, I solved this by adding a second field that would tell the instances of two different classes apart. This may be regarded as just another way of using the class name suggested by David Ehrmann in his question. But in my case using an additional field looks more appropriate than using a class name. So here's my abstract parent class:
public abstract class NationalDish {
public String dishName;
public String country;
#Override
public int hashCode() {
return Objects.hash(country, dishName);
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof NationalDish)) {
return false;
}
NationalDish other = (NationalDish) obj;
return Objects.equals(dishName, other.dishName)
&& Objects.equals(country, other.country);
}
}
Note how having the fields in the parent class allows to define equals() and hash code() in that same class and keep child classes to the minimum:
public class EnglishDish extends NationalDish {
public EnglishDish(String dishName) {
this.dishName = dishName;
this.country = "England";
}
}
public class AmericanDish extends NationalDish {
public AmericanDish(String dishName) {
this.dishName = dishName;
this.country = "USA";
}
}
Now, with country names (or plant types like in the question) in place we can have same name instances which will look different to Java:
public static void main(String[] args) {
NationalDish englishChips = new EnglishDish("Chips");
NationalDish americanChips = new AmericanDish("Chips");
System.out.println(englishChips.equals(americanChips)); // false
}
This question already has answers here:
Can an abstract class have a constructor?
(22 answers)
Closed 8 years ago.
If you are never going to instantiate an object from that class, when are you going to ever use its constructor? Sorry if I come off as ignorant. I just started a class on Java at my high school.
you can initialize something in parent class , so maybe you need constructor in abstract class.
Because sub classes may use it. For example:
public abstract class Foo {
protected String name;
public Foo(String name) {
this.name = name;
}
}
public class Bar extends Foo {
public Bar(String name) {
super(name); //<-- necessary, otherwise it won't compile
}
public Bar() {
super("default name"); // <-- necessary, otherwise it won't compile
}
}
You have a constructor so subclasses can initialize the state of their parent properly.
public abstract class Parent {
private final String name;
public Parent(String n) { this.name = n; }
public String getName() { return this.name; }
}
public class Child extends Parent {
public Child(String name) { super(name); }
}
There would be no other way to initialize that private final String name attribute in the Parent without a constructor.
Well your parent class or the abstract class stores common variables throught all children classes or subclasses.
This makes it easier to store different objects (with the same parent) into collections such as and ArrayList.
It also allows you to easily manipulate and object without worrying about its details that is contained in the subclass.
You do instantiate the constructor by calling super() within the subclass.
Check this example:
public interface IConstants {
public enum Levels {
LOW("30 points"), MEDIUM("50 points")
};
public enum Cars {
PORSCHE("250 km/h"), FORD("180 km/h")
}
}
I'd like to have an interface like this, because I want to access my enums this way:
String level = IConstants.Levels.MEDIUM;
String car = IConstants.Cars.PORSCHE;
The compiler shows this message:
constructor IConstants."enum name" is undefined.
Solved this way :
public class Constants {
public static class Levels {
public static String LOW = "30 points";
public static String MEDIUM = "50 points";
};
//... other classes
}
-useful for me in (my case) to have a "tree" in my constants, every constant starting by keyword Constants then subcategory and then value -> Constants.Levels.LOW.
//critize it if it's very bad practise, i agree all comments
-another maybe good thing that there will be all constants in one class
Like Boris the spider told you in comment declaring constants in interfaces is an anti pattern. However your problem comes from the fact that you are passing a String to any instance of your enum but you are not declaring a constructor for this
public enum Levels {
LOW("30 points"), MEDIUM("50 points")
private final String pts;
private Levels(String pts) {
this.pts = pts;
}
public String getPoints() {
return pts;
}
};
This should work.
You are missing constructors in both enums. A private variable and the constructor is required, e.g.
public enum Levels {
private String name;
public Levels(String name) {
this.name = name;
}
}
Also it is considered bad practice to put inner classes, constants in interfaces.
To add to other answers, it will still not compile after an enum constructor is added, because you are assigning a String variable to a Levels or Cars. Please use:
String level = IConstants.Levels.MEDIUM.methodToAccessString();
String car = IConstants.Cars.PORSCHE.methodToAccessString();
Replacing methodToAccessString() with whatever you call it, of course.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Implement a final class without the “final” keyword
I want to create an immutable class in Java without using the final keyword.
I think smt like should work fine
class Immutable {
private int i;
public static Immutable create(int i){
return new Immutable(i);
}
private Immutable(int i){this.i = i;}
public int getI(){return i;}
}
But final is preferable.
The final keyword won't make your class inmutable. It will avoid your class to be extended from another class.
public final class Foo {
//....
}
public class Bar extends Foo {
//COMPILATION ERROR!
}
An adecuated class design is what will make you class inmutable, as you can see at duffymo answer.
Note that you can declare as final the fields that you will initialize at the constructor:
class Foo {
private final int state
public Foo(int v) {
this.state=v;
}
//....
}
The difference is that, while at duffymo example, the value ccould be changed from inner routines (i.e, a method adds one to the value, kind of a counter), at my example you wouldn't be able to do so.
Let's try to avoid absolutely the use of the final keyword:
public class Foo {
private int state;
private Foo(int v) {
this.state=v;
}
public static Foo getInstance(int value) {
return new Foo(value);
}
}
You only can get an instance of Foo accesing the Foo.getInstance method.
But anyway, you can extend the Foo class and make it mutable
I was wrong here. I won't compile, as you can acceess the Foo constructor.
public class Bar extends Foo {
private int ohNopes;
//COMPILATION ERROR!
public Bar(int v) {
this.ohNopes=v;
}
}
So, it seems it can be done, after all.
The problem with an immutable class not being final is that, subclasses may not be immutable.
Here is an example from the Java API, java.lang.String is immutable and final, if a string is passed to one of your methods you can be sure that it will remain in a consistent state.
the following will not compile because String is final:
public class MyString extends java.Lang.String {
public MyString(String original) {
Super(original);
}
#Override
public String toString() {
return String.valueOf(System.currentTimeMillis());
}
On the other hand, java.ma.BigDecimal itself is immutable, but it is not final and allowed to be subclassed. This opens up a range of issues. If a BigDecimal is passes to one of your methods you can't rely on the fact that no one has overridden BigDecimal like you can with String. subclasses of BigDecimal could potentially replace its methods with others which give unpredictable results.
The following will compile because BigDecimal is not immutable:
public class MyBigDecimal extends java.math.BigDecimal {
public MyBigDecimal(double val) {
super(val);
}
private int count = 0;
// override intValue which changes the state of this instance
#Override
public int intValue() {
return count++;
}
// rinse and repeat for the rest of the BigDecimal methods...
}
You cannot rely on he state of BigDecimal instances passed into your code, you should make Defensive copies of non final classes if you need to rely on their immutability.
I can't imagine why you object to using final, but here's a class that will get the job done. I know there are subtleties regarding serialization and reflection, but this can't be changed without special shenanigans:
public class Immutable
{
private int value;
public Immutable(int v)
{
this.value = v;
}
public int getValue() { return this.value; }
}
The class should set all its values in the constructor, and provide no setters (methods that modify class members).
You can create a class then create a .jar and use the jar as resource.