Java enums: Gathering info from another enums - java

I made a similar question a few days ago, but now I have new requirements, and new challenges =). As usual, I'm using the animal enums for didactic purposes, once I don't want to explain domain-specific stuff
I have a basic enum of animals, which is used by the whole zoo (I can add stuff to it, but must keep compatibility):
public enum Animal {
DOG,
ELEPHANT,
WHALE,
SHRIMP,
BIRD,
GIRAFFE;
}
I need to categorize them in a few, non-related categories, like gray animals (whale (my whale is gray) and elephant), small animals (bird, shrimp and dog), sea animals (whale and shrimp).
I could, as suggested in my previous questions, add a lot of booleans, like isGray, isSmall and isFromSea, but I'd like an approach where I could keep this somewhere else (so my enum doesn't need to know much). Something like:
public enum Animal {
DOG,
ELEPHANT,
WHALE,
SHRIMP,
BIRD,
GIRAFFE;
public boolean isGray() {
// What comes here?
}
}
Somewhere else
public enum GrayAnimal {
WHALE,
ELEPHANT;
}
How is this possible? Am I requesting too much from Java?

Did you try EnumSet or EnumMap?
You can create a method
Set<Animal> grayAnimals(){
return EnumSet.of(Animal.WHALE, Animal.ELEPHANT);
}

I think it would be best to store such properties in the enum instances themselves, i.e.
public enum Animal {
DOG(NOT_GRAY),
ELEPHANT(GRAY),
WHALE(GRAY),
SHRIMP(NOT_GRAY),
BIRD(NOT_GRAY),
GIRAFFE(NOT_GRAY);
private static boolean GRAY = true;
private static boolean NOT_GRAY = !GRAY;
private Animal(boolean isGray) {
// snip
}
}
You could even encode several boolean properties into one byte (or use BitSet instead);
public enum Animal {
DOG(),
ELEPHANT(GRAY | BIG),
WHALE(GRAY | BIG),
SHRIMP(),
BIRD(),
GIRAFFE(BIG);
private static byte GRAY = 0x01;
private static byte BIG = GRAY << 1;
private final byte _value;
private Animal() {
this(0x00);
}
private Animal(byte value) {
_value = value;
}
public boolean isGray() {
return _value & GRAY != 0x00;
}
public boolean isBig() {
return _value & BIG != 0x00;
}
}
Nevertheless, what about simply doing this:
public class GrayAnimal {
public static final Animal ELEPHANT = Animal.ELEPHANT;
public static final Animal WHALE = Animal.WHALE;
}
or something like this
public enum Animal {
DOG,
ELEPHANT,
WHALE,
SHRIMP,
BIRD,
GIRAFFE;
// thanks to Mihir, I would have used a regular HashSet instead
public static final Set<Animal> GRAY = Collections.unmodifiableSet(EnumSet.of(ELEPHANT, WHALE));
}

Remember that enums are only useful when you need to differentiate objects in your code--they are useless except that they can be typed in as code.
This is relevant because you are introducing elements into your software that will turn out to be bad code smells in the long run.
For instance, how do you use these except in statements like:
if(critter.type == WHALE)
critter.movement=WATER;
else if(critter.type == ELEPHANT)
This should instantly alert any OO programmer--switches are a bad code smell since they almost always indicate bad OO design).
The alternative is to create a finite set of objects, initialized by data, preferably not code.
You might have an instance of critter with the attributes of a whale--perhaps whale.move() would use an instance of WaterMovement whereas the elephant contains and uses an instance of LandMovement.
In general, programming in OO instead of using switches and enums will collapse an amazing amount of code.
Every time you write a method, remember the mantra "Don't ask an object for data and then operate upon the object, instead ask the object to do an operation for you".

I don't know why you want to put it in another enum, when you could put it in that function:
public boolean isGray() {
return this == WHALE || this == ELEPHANT;
}

maybe something like this:
package p;
import java.util.*;
enum Type {
small,big,grey;
}
enum Animal {
bird(EnumSet.of(Type.small)),whale(EnumSet.of(Type.big, Type.grey)),elephant(EnumSet.of(Type.big, Type.grey));
Animal(final EnumSet<Type> types) { this.types=types; }
EnumSet<Type> types=EnumSet.noneOf(Type.class);
boolean is(final Type type) { return types!=null?types.contains(type):false; }
public static void main(String[] arguments) {
for(Animal a:values()) {
System.out.println(a+" "+a.types);
}
}
}

I think that it is best not to pollute your enum with this sort of categorization. It is best to decouple the categories from the enum so you can add more later without affecting your enum. This follows the seperation of concerns and single responsibility principle for class design.
To do this, just use an EnumSet to hold the instances, viz:
public enum Animal {
DOG,
ELEPHANT,
WHALE,
SHRIMP,
BIRD,
GIRAFFE;
}
public static final EnumSet<Animal> GRAY_ANIMALS = EnumSet.of(ELEPHANT, WHALE);
If you want to add functionality above simple membership, or you want a bit more syntactic sugar extend EnumSet
public class GrayAnimals extends EnumSet<Animal> {
public static final GrayAnimals INSTANCE = new GrayAnimals(ELEPHANT, WHALE);
private GrayAnimals(Animal...animals) {
Collections.addAll(this, animals);
}
public boolean isGray(Animal animal) { return contains(animal); }
// ... other methods
}

Related

Generic array with Polymorphism

I have created a base interface which is implemented by some objects and I also have an array of interfaces which given a string return the objects mentioned. (a bit difficult to explain, better look the code :D) Then I want to pass this to the global object through some overloaded methods (at the beginning looked super clever, but it now seems technically impossible) Could I get any closer to what I want?
interface Stats { }
public class ObjectA implements Subscriber.Stats { // MORE THINGS }
public class ObjectB implements Subscriber.Stats { // MORE THINGS }
// MORE OBJECTS
This is the second interface which transforms a String into one of the classes from above
public interface Parser<T extends Stats> {
T parse(String data);
}
Now I have an array of implementations of the this interface I want to give me different results (ObjectA, ObjectB, ObjectC ..)
private final Parser<Stats>[] parsers = new Parser[] {
new Parser() {
#Override
public Stats parse(String data) {
return new ObjectA();
}
},
new Parser() {
#Override
public Stats parse(String data) {
return new ObjectB();
}
}
};
Now comes the "clever" part where I want to make something that may not be possible.
If I loop the array of parsers and each position gives me ObjectA, ObjectB due to Polymorphism I could call an overloaded method of a class with a signature like push(ObjectA) push(ObjectB), right??... Well this obviously doesn't work but is there any strategies I could use to accomplish this?
The loop would be:
for (int i = 0; i < operations.length; i++) {
dataHolder.push(parsers[i].parse(operations[i].getResult()));
}
EDITED
The problem is the method T parse (String value) is treated as if it returns Stats and not T extends Stats therefore when I call push it says there is no push(Stats) method
If I got it correctly, your dataHolder interface looks like this:
public interface DataHolder {
void push(ObjectA a);
void push(ObjectB b);
}
In that case really your loop cannot benefit from the overloaded methods, because at cimpile time, it only knows about parsers of Stats.
To achieve your goal you need to use the visitor pattern, and update your Stats hierarchy like this:
public interface Stats {
void accept(DataHolder holder);
}
public class ObjectA implements Stats {
void accept(DataHolder holder) {
holder.push(this); // this is ObjectA, so push(ObjectA) is used
}
}
public class ObjectB implements Stats {
void accept(DataHolder holder) {
holder.push(this); // this is ObjectB, so push(ObjectB) is used
}
}
Now if you do:
new Parser<Stat>().parse(input).accept(dataHandler);
It will use the propper overloaded push method (I didn't rewrite your loop, because I'm not sure if I unerstadt it properly, bu hopefully you can apply it yourself).
Sounds reasonable to me. Just try it.
String dataToParse = "wklhbglbwbgiwegbuwegbwe";
for(Parser p : parsers){
//The definition of each parser will be called and everything works.
System.out.println(p.parse(dataToParse));
}
Also you can just:
public void push(Object obj){
System.out.println(obj.getClass().getCardionalName());
//Or anything else you want to do with it.
}

Enums with inherited functionality

I have the following Enum constants for real life equipment:
HELMET,
CHESTPIECE,
BOOTS,
SWORD,
MACE,
HAMMER,
SHIELD,
BOW,
CROSSBOW,
STAFF
...;
I have another class called Battle which dictates what equipment can be used in that specific battle. For example:
new Battle(Equipment.HAMMER, Equipment.SHIELD, EQUIPMENT.BOW);
Which means that only Hammers, Shields, or Bows can be used.
Now I expanded on that and have the need for sub categories. For example:
new Battle(Equipment.SHIELD, Equipment.Weapons.values())
Which is equivalent to saying:
new Battle(Equipment.SHIELD, Equipment.SWORD, Equipment.MACE, Equipment.HAMMER, ...) etc
Which also means that new Battle(Equipment.values()) should yield every enum value
Since Enums are final, I tried the following:
public interface Equipment { }
public enum MeleeWeapon implements Equipment
{
SWORD,
MACE,
HAMMER,
STAFF, ...;
}
public enum RangedWeapon implements Equipment
{
BOW, CROSSBOW;
}
...
But with this, I'm unable to say Equipment.Weapon.values() // get all weapons, ranged and melee. There's no sense of inherited relationships between classes, and I also lose everything that is not defined in the interface. It doesn't feel like a good solution here.
I tried making regular classes:
public abstract class Equipment
{
private static Set<Equipment> instances = new HashSet<>();
public static Set<Equipment> values()
{
return instances;
}
public Equipment()
{
instances.add(this);
}
}
public abstract class Weapon extends Equipment
{
private static Set<Weapon> instances = new HashSet<>();
public static Set<Weapon> values()
{
return instances;
}
public Weapon()
{
super() // explicit call
instances.add(this);
}
}
public class MeleeWeapon extends Weapon
{
private static Set<MeleeWeapon> instances = new HashSet<>();
public static final MeleeWeapon SWORD = new MeleeWeapon();
public static final MeleeWeapon MACE = new MeleeWeapon();
...
public static Set<MeleeWeapon> values()
{
return instances;
}
public MeleeWeapon()
{
super() // explicit call
instances.add(this);
}
}
Unfortunately there is a ton of repeated code, heavy on memory, and also public static Set<Weapon> values() causes a compile error because it attempts to override values() in the superclass with a different return type. I was able to solve this with generics (<? extends Weapon>) but it's still an awful solution.
What is the right approach here? I need inheritance with my enum values but I cannot find a way how to do so.
Still keeping the enum usage, it is possible to associate each element of the enumeration with the groups to which it belongs and then return filtered groups of elements in dedicated methods.
We'll need another - smaller - enum which enumerates the properties to filter on, for example:
public enum EquipmentType {
WEAPON, ARMOR, TOOL, CLOTHING;
}
The elements of the enumeration are associated with their respective groups:
public enum Equipment {
HELMET(ARMOR),
CHESTPIECE(ARMOR),
BOOTS(ARMOR, CLOTHING),
SWORD(WEAPON),
MACE(WEAPON),
HAMMER(WEAPON, TOOL),
SHIELD(ARMOR),
BOW(WEAPON),
CROSSBOW(WEAPON),
STAFF(WEAPON);
private final Set<EquipmentType> types;
Equipment(EquipmentType... eqTypes) {
this.types = Arrays.stream(eqTypes)
.collect(Collectors.toSet());
}
// common filtering method
private static List<Equipment> filterByType(EquipmentType type) {
return Arrays.stream(values())
.filter(eq -> eq.types.contains(type))
.collect(Collectors.toList());
}
// dedicated methods for each group of items
public static List<Equipment> getWeapons() {
return filterByType(WEAPON);
}
public static List<Equipment> getArmor() {
return filterByType(ARMOR);
}
}
There is still no inheritance or more evolved typing involved in this approach and I think it would be better to avoid using the enum at all if you want more flexibility.

Creating Objects According to an Input File

I have a task that needs to be done but I am really stuck.
Basically, I've some inheritance relations like this:
Animal
Pet WildAnimal
Bird Cat Dog Fish ||Snake Eagle
Animal is the parent of Pet and Wild Animal.
Pet is the parent of Bird, Cat, Dog, Fish.
WildAnimal is the parent of Snake and Eagle.
The task wants me to read inputs from a file which is "input.txt" and create Animal objects.
"input.txt" is like:
kiwi Bird
charlie Eagle
mango Fish
pepper Dog
angle Cat
tweety Bird
bob Dog
ziggy Snake
I can get all of the names but I couldn't figure out how to understand which kind of object every single name represent.
Here is the main method:
public static void main(String[] args) throws IOException {
String s ="";
int nameCounter = 0;
Animal[] animals = new Animal[100];
try{
Scanner input = new Scanner(Paths.get("input.txt"));
while (input.hasNext()) {
s = input.next();
Animal animal = new Animal(s);
animals[nameCounter] = animal;
nameCounter += 2;
}
}catch(Exception e){
e.printStackTrace();
}
}
Here is the animal class:
public class Animal {
private String name;
private int numberOfLegs;
private int numberOfWings;
public Animal(String name){
this.name = name;
numberOfLegs = 4;
numberOfWings = 0;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNumberOfLegs() {
return numberOfLegs;
}
public void setNumberOfLegs(int numberOfLegs) {
this.numberOfLegs = numberOfLegs;
}
public int getNumberOfWings() {
return numberOfWings;
}
public void setNumberOfWings(int numberOfWings) {
this.numberOfWings = numberOfWings;
}
public void talk(){
System.out.printf("<Silence>");
}
public void fly(){
System.out.printf("%s cannot fly", getName());
}
public void run(){
System.out.printf("%s is running", getName());
}
}
I can add all the other classes if you want but i don't think you're gonna need them.
You have to instantiate objects of your specific class; based on the incoming string.
Example: if the class name from the file is Bird ... then you have to call new Bird() somehow.
There are two ways to get there:
Using reflection (you can actually instantiate classes "by string"; without knowing anything about that class)
By using a switch statement
Reflection is more of an "advanced" topic (and very easy to use the wrong); so I really do recommend you to go for option 2, like:
private Animal createAnimalFor(String className, String animalName) {
switch (className) {
case "Bird": return new Bird(animalName);
...
default: throw new IllegalArgumentException("Dont know how to create object for unknown class: " + className);
}
}
(the above code is meant as "fyi" - I didn't run it through the compiler; it is meant to give you one idea how this could be done).
Some notes beyond that:
Consider using a final field for those properties of your objects that can't change. You don't need a setter for the name then; just give the name as parameter to the constructor. In other words: only make those fields "changeable" that make sense to be changed. Anything else should better be final.
Instead of using an array with 100 empty slots, you could use a java.util.ArrayList and just add as many new animals as you find in that file.
Consider adding equals/hashCode methods to your Animal class (not mandatory, but you should read why that makes sense very often).
Probably most importantly: consider not putting all those different methods directly into your base class. It might make more sense to create either abstract subclasses that add certain functions, or use interface, like interface FlyingAnymal { void fly() }; which your specific subclasses would then implement. It is not really good practice to put a lot of methods on your base class ... that simply dont make sense for all of the sub classes.
If you really want to use reflection to do so (which I would also discourage), here's sample code :
String name = input.next();
String className = input.next();
// apply transformations to className as needed
Class<Animal> c = (Class<Animal>) Class.forName(className);
Constructor<Animal> constr = c.getDeclaredConstructor(String.class); // retrieves the Animal(String name) constructor
Animal a = constr.newInstance(name);
I don't think the code is so complex, but few people have ever used reflection so they'll have problems maintaining it, and it is tightly coupled with your classes definitions so it will probably have to be maintained a lot.

more enum in interface

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.

How to specify enum constructor

At present I have a class called TestEnum. In my main method I can work with firstEnum and secondEnum without needing to specify that firstEnum belongs to GroupA and secondEnum belongs to GroupB - the code in TestEnum sorts this out.
Suppose that either firstEnum or secondEnum could be associated with any of the three SubGrouping enum. I want to be able to make this association from within my main method. It is clear I can't use the same approach as with Grouping since GroupA is allocated to firstEnum from within TestEnum.
public enum TestEnum {
firstEnum (Grouping.GroupA),
secondEnum (Grouping.GroupB);
private Grouping group;
TestEnum(Grouping group) {
this.group = group;
}
public enum Grouping {
GroupA, GroupB;
}
public enum SubGrouping {
SubGroup1, SubGroup2, SubGroup3;
}
}
How do I do this? To be more concrete, it would be good to construct an object such as:
TestEnum enumWithinMainMethod = TestEnum.firstEnum(SubGrouping.SubGroup1)
The desired behaviour of this instance is that it belongs to both SubGroup1 as well as GroupA. Then from such an instance it would be good to have the functionality, for example:
switch(enumWithinMainMethod) {
case firstEnum:
// Do something associated with firstEnum
case secondEnum:
// Do something associated with secondEnum
default:
// ...
}
Double think before going this approach. Enum is aimed to be static, constant and with finite set of values. What you are doing here is making Enum no longer constant (as you are changing/initializing it in runtime).
I believe there are other way to do, for example, review if it is actually required to have the relationship determined in runtime? Can't it be defined in compile-time? You may also having a TestEnum-to-SubGroup map, instead of dynamically construct the content of TestEnum.
Anyway, although it is not preferable, it is technically possible in Java.
Of course you cannot delay the "construction" of enum until your main() logic, but you can have enum constructed as normal, and change the internal state.
// Mind the naming convention
public enum TestEnum {
FIRST_ENUM(Grouping.GROUP_A),
SECOND_ENUM (Grouping.GROUP_B);
private Grouping group;
private SubGrouping subGrouping;
TestEnum(Grouping group) {
this.group = group;
}
public void setSubGrouping(SubGrouping subGrouping) {
this.subGrouping = subGrouping;
}
public enum Grouping {
GROUP_A, GROUP_B
}
public enum SubGrouping {
SUB_GROUP_1, SUB_GROUP_2, SUB_GROUP_3;
}
}
Then in your main(), do something like
TestEnum.FIRST_ENUM.setSubGrouping(TestEnum.SubGrouping.SUB_GROUP_1);
TestEnum.SECOND_ENUM.setSubGrouping(TestEnum.SubGrouping.SUB_GROUP_2);
By doing so, you can define the subgrouping of your enum in your main()
Once again, this is NOT PREFERABLE.
You cannot call enum constructors from outside of an enum. You could use a class to get this behaviour.
How about something like this? (The generics are not required, but it does open up the Groupable class to multiple types of groupings.)
public enum Grouping { GroupA, GroupB; }
public enum SubGrouping { SubGroup1, SubGroup2, SubGroup3; }
public class SubGroupable<G extends Enum<G>,S extends Enum<S>> {
private G mainGroup;
private S subGroup;
public Groupable(G group, S subGroup) {
this.mainGroup = group;
this.subGroup = subGroup;
}
public G getGroup() { return mainGroup; }
public S getSubGroup() { return subGroup; }
}
Usage
SubGroupable<Grouping, SubGrouping> g
= new SubGroupable<>(Grouping.GroupA, SubGrouping.SubGroup2);
switch (g.getGroup()) {
case Grouping.GroupA:
//
break;
case Grouping.GroupB:
//
break;
}
You could also create two final groupings:
public final Grouping FIRST_GROUP = Grouping.GroupA;
public final Grouping SECOND_GROUP = Grouping.GroupB;
This way you can use those constants in your case blocks.
switch (g.getGroup()) {
case FIRST_GROUPING: // etc
}

Categories