Using Enum to hold object constants - java

So I've learned a bunch recently so I'm going back and sort of refactoring the homeworks from a previous course that I took to implement them using good practices. One homework had us implement a Planner object that contained an array of Course objects. I'm trying to create some Course constants so that I can access some popular Courses without having to create brand new Objects every time and so I can easily access them without going through the Course building process. I don't have much experience with enums and I can't seem to find anything on how I can actually use an Enum to store constants that are Objects. I originally wanted to make them constants in the Course class but Effective Java insists enumns should be used in such a situation. Does my implementation make sense at all? How should I go about making this enum that contains Course constants so I can actually retrieve them? I use the Builder method for creating a Course.
public enum Courses {
CSE_114, CSE_214, CSE_219, CSE_215;
private final static Course CSE_114_COURSE = new Course
.Builder("Computer Science 1", "Paul Fodor", 114)
.section((byte)1).department("CSE").build();
private static final Course CSE_214_COURSE = new Course
.Builder("Data Structures", "Ahmad Esmaili", 214)
.section((byte)1).department("CSE").build();
private static final Course CSE_219_COURSE = new Course
.Builder("Software Development", "Richard McKenna", 219)
.section((byte)1).department("CSE").build();
private static final Course CSE_215_COURSE = new Course
.Builder("Foundations of CS", "Paul Fodor", 215)
.section((byte)1).department("CSE").build();
public static Course get(Courses c) {
switch(c) {
case CSE_114: return CSE_114_COURSE;
case CSE_214: return CSE_214_COURSE;
case CSE_219: return CSE_219_COURSE;
case CSE_215: return CSE_215_COURSE;
default: throw new IllegalArgumentException("Course does not exist.");
}
}
}

You can actually treat an enum like an object:
public enum Course {
CSE_114("Computer Science 1", "Paul Fodor");
public final String room;
public final String lecturer;
private Course(room, lecturer) {
this.room = room;
this.lecturer = lecturer;
}
}
Because it is an enum, all values must be known at compile time. This is enforced by the Java language, which requires that the enum constructor is private.
While this would work for your situation, I don't recommend it - in fact, I don't recommend using an enum at all. An enum represents a fixed, known set of values. If you want to create more courses at runtime, then the enum is incomplete, and that contradicts the definition of an enum.
Instead, I suggest you use a CourseManager. Create one class, which holds the collection of all known courses. Then, when you need a course, you request it by name.
Course cs114 = courses.get("CS 114");
You could also take it one step further, by instantiating the CourseManager from a file, which contains a list of courses in a basic format like JSON.

That's not a bad implementation but I think a have a bit better solution: add an abstract method to your enum definition.
public enum Courses {
CSE_114 {
public Course getCourse() {
return CSE_114_COURSE;
}
}
...
private final static Course CSE_114_COURSE = new Course
.Builder("Computer Science 1", "Paul Fodor", 114)
.section((byte)1).department("CSE").build();
...
public abstract Course getCourse();
}
That way you can access to any course object vía Courses.CSE_114.getCourse() and you are also forcing that every enum has a course (imagine that you add an enum constant but forgot to add it in the get method. The way I proposed makes that scenario non sense)

You are mixing enum constants with static constants. Get these courses and selection of courses out of the enum class. Or you can use something like Andrew Williamson showed. Just don't mix the static constants with the enums. Static constants don't belong to the enum class. Enum class has a fixed set of values and that is where its role ends. All the other logic using these enums should be done somewhere else

Related

Constructing the instances in an Enum without modifying the Enum class

I apologize if my question lacks clarity,
I'm currently working on a school assignement where I have to use the following Enum class:
public enum Seeds {
TOMATE,
CONCOMBRE,
SALADE,
PATATE,
BETTERAVE;
}
Rather then making a whole bunch of constants for the buy price, sell price and maturation time of each seed and having to type them out each time, I wanted to assign attributes to each enum directly in the class like so:
public enum Seeds {
TOMATE(2.00, 3.50, 5),
CONCOMBRE(1.00, 2.50, 6),
SALADE(1.50, 4.50, 8),
PATATE(2.50, 3.50, 4),
BETTERAVE(2.00, 4.00, 10);
private final double
buy_price,
sell_price;
private final int
maturation_time;
public Seeds(double buy_price, sell_price, int maturation_time) {
this.buy_price = buy_price;
this.sell_price = sell_price;
this.maturation_time = maturation_time;
}...
and return their attributes with getters.
However, my teacher told me that I cannot modify the provided Enum class... so I was wondering if it was possible to construct the seeds in another class.
If you can't modify the Seeds enum, you could create a POJO to hold all the info you need like this:
public class Seed {
private Seeds seedType;
private double buyPrice;
private double sellPrice;
private int maturationTime;
// constructor, getters and setters here
}
It would be better to add the properties and a constructor to the Seeds enum though.
You can create a custom class that encapsulates the different price types, and keep a Map<Seed, YourCustomPricesClass> to store the relations.
See: the Map interface in the Java Tutorial
Yes it is possible, but you are eroding the main intent behind creating an enum. If you are going to create a modifiable state of a class, technically you are creating a new object. If that is the case, You don't even need an enum at first place, just stick with class.

How do you use the variables from an enum in another class?

I'm very new to enums and only have an elementary understanding of programming. I recently found out about enums and believe them to be the perfect solution to some of my problems but need some help on how to incorporate them into my code.
I started by creating an enum class. For now I'm working with 7 constants for my enum, and each constant has 1 String variable describing(?) it. How do i code this? And more importantly how do I access this from another class? For instance I want to print the string relating to the constant that is the current value of my enum. Please help. This was really hard for me to describe so hopefully you guys know what I'm trying to ask for.
This is already covered in the official tutorial
public enum Animal {
COW("moo"), // <== calls constructor with any enum specific data
HORSE("neigh"),
SHEEP("ba ba");
private final String noise; // stores the data
private Animal(String noise) { // <== private constuctor
this.noise = noise;
}
public String getNoise() { // <== allow access to the data
return noise;
}
}
Access from another class
Animal animal = Animal.COW;
System.out.println(animal.getNoise());
Enum constants override the toString method so by default it returns the constant name as a string. You can even override it further.
The Javadocs are your friend: http://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#toString--.
You can also often use the enum constant itself directly.
public enum Rainbow {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET;
}
Used one way:
Rainbow rainbow = findRainbow();
switch (rainbow) {
case RED:
rosso();
break;
case YELLOW:
giallo();
break;
. . .
case VIOLET:
viola();
break;
}
etc.
Also, enums are classes and you can give them more methods, even override a method differently for each enum constant. Like Java already does with toString.
#shmosel already gave the link to the enum Tutorial.
To declare an enum, follow this synatx Colors("RED", "BLUE")
To access the enum class, declare it as a public class. If the class is in another package, import the class in to the class which is referencing those enums.
sorry my bad for saying to make it static
make it public . so that it can be accessed from any class that the class is imported to .
make somethingn like this from a different class
public class DifferentClass
{
public enum reportType
{
firstReport = 1,
secondReport = 2
}
}
import that class and access it like System.out.println("Report type : " + reportType.firstReport);

How can I simulate Enums that can be expanded at Runtime in Java?

I am writing a program to simulate cities from a game called Civilization 4. In order to do this I have several Enums to represent types of terrain, resources, improvements etc for each plot owned by said city.
The problem is I want to program to be compatible with Fan made mods which may add things to the Game that need to be accepted into my independant utility. So I thought of creating a Enum style class to hold the new types defined by the loaded mods (as Enums cannot be changed at runtime) which is created during runtime when the user enters in a mod to be loaded (which is a txt file that is parsed to read the new additions)
So is there a way to simulate Enums that are created and added to at runtime? I take it static member variables cannot be used as they are done before runtime...
You can make a enum implement an interface.
This way you can have your defined values in the enum, but new values can be any class which implements the interface.
An alternative is that you generate or load the enum at runtime using a byte code generator or the Compiler API. I wrote a library to make it easier to take a String and compile&load it.
http://vanillajava.blogspot.co.uk/2010_11_01_archive.html
Well, enums in Java are simply classes where the language guarantees that the set of known objects is known and limited at compile-time. If you want to add new enum literals at runtime, you end up with regular classes.
The beauty of enums is that you can write human readable names in code that are compiled as numbers behind the scenes, because computers like numbers better. Take for example this enum:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
Behind the scenes WINTER might be 0 (zero), SPRING is 1 etc.
To replicate this behaviour in runtime code you could create a list of strings, like this:
List<String> seasons;
seasons = new ArrayList<String>();
seasons.add("Winter");
seasons.add("Spring");
...
That way you can reference the items as numbers, such as seasons[1] would equal "Spring".
This answer is just one of many ways to approach this question.
By default, enum types have only a set number of values. The values in an enum type are actually declared as static final, and there's no way to add more on runtime.
That being said, there are other patterns you can use to implement what you want. Let's take a look at using an interface and a registration system. We'll start with the Terrain interface:
public interface Terrain {
int getId();
String getName();
int getSightBonus();
}
Now an enum, DefaultTerrain:
public enum DefaultTerrain implements Terrain {
PLAINS(0, "Plains", 1),
HILLS(1, "Hills", -1),
MOUNTAINS(2, "Mountains", -2);
private int id;
private String name;
private int sightBonus;
private DefaultTerrain(int id, String name, int sightBonus) {
this.id = id;
this.name = name;
this.sightBonus = sightBonus;
}
public int getId() {return id;}
public String getName() {return name;}
public int getSightBonus() {return sightBonus;}
}
And a registration class, which can be either a static utility class or a singleton.
public class TerrainManager {
private static Map<Integer, Terrain> terrainsById = new HashMap<>();
static {
for (DefaultTerrain terrain : DefaultTerrain.values())
register(terrain);
}
public static void register(Terrain terrain) {
Integer id = terrain.getId();
if (terrainsById.contains(terrain.getId()))
throw new IllegalArgumentException("Terrain with id already exists: " + id);
terrainsById.put(id, terrain);
}
public static Terrain getTerrainById(int id) {
return terrainsById.get(id);
}
public static Set<Terrain> getAllTerrains() {
return new HashSet<Terrain>(terrainsById.values());
}
}
This last class is where the magic happens. Presumably the modders will have some kind of identifier in the game's world definition to say "use this tile," right? In this case, I've called it an integer, id, but really it could be any type, just modify the Map accordingly. In the map-loading code, just use the ID in the world definition to look up the Terrain. When a modder adds a new Terrain, they just need to implement Terrain and register it with TerrainManager.
The static initializer makes sure that your DefaultTerrain objects are added before anything else is added. If you use a singleton, this could be put into the class constructor instead.
Use this pattern for your different enum types that you want users to add to. You could also use it for pretty much any other type as well besides enum.
You will need CGLIB, http://cglib.sourceforge.net/

Need help in tweaking enum lists

I have public enum like below:
public enum stringList1 {
string1,
string2,
string3,
string4,
string5,
}
This enum "stringList1" is referred in all over the code more than 100 places. Currently I have requirement to support below list as well.
enum stringList2 {
string1,
string2,
string6,
}
Actually code should pick either stringList1 or stringList2 depending on a condition.
I know enums can not be changed, also changing all over the code to put condition to pick right enum list is very difficult.
Here refactoring will not help, I need to pick either stringList1 or stringList2 at runtime, but currently stringList1 is referred all over the code. One option is putting the condition in all the places stringList1 is referred to pick stringList1 or stringList2, but this is very difficult.
UseCase: This is for backward compatibility, stringList1 for current version, say v2, stringList2 for v1. Data can be operated by V1 binary and V2 binary. Currenty if user tries to create data using V2 binary, it will create data, which is not understood by V1. So in version 2 binary I need to check, if version is 1, I need to used stringList2 else stringList 1
Lets say method method1(), which will create some predefined values with the help of stringList1, here user has access to method1() don't have access to enum values.
so user just simply call method1, I need to find the version, depending on the version, I have to use stringList1 or stringList2 but the problem is stringList1 is used all over the code :( as Classname.stringList1.values() or Classname.stringList1 in all over the code, for some internal processing
Please advise me how can I proceed in this case.
Thanks in Advance,
Ashok
maybe using the refactor function (from eclipse - i guess netbeans and others have something like that too) and renaming could help
public enum stringList {
stringList_string1,
stringList_string2,
stringList_string3,
stringList_string4,
stringList_string5,
}
public enum stringList2 {
stringList2_string1,
stringList2_string2,
stringList2_ string6,
}
hope this helps you :)
In your IDE you should be able to use refactoring to rename one instance and only rename just that instance (without change other enums)
If you need to keep the enums separate, i.e. not just add all the values together, you could make them implement an interface, e.g.
public interface stringListCommon {
}
public enum stringList implements stringListCommon {
..
}
public enum stringList2 implements stringListCommon {
..
}
This will allow you to pass these enums around with the same methods.
The better and modern way(I think you know enum is comming from C) is to structure special class for this operation. I will wrote you an example with playing card suits.
public class Suit {
private final String name;
private Suit(String name);
public static final Suit CLUBS = new Suit("clubs");
public static final Suit DIAMONDS = new Suit("diamonds");
public static final Suit HEARTS = new Suit("hearts");
public static final Suit SPADES = new Suit("spades");
/*other code is what you need you need(either final Suit[]
or final unmodifiableList to store values*/

Is there any mistake in this Java code?

class Creature {
private int yearOfBirth=10;
public void setYearOfBirth(int year) {
yearOfBirth = year;
}
void setYearOfBirth(Creature other) {
yearOfBirth = other.yearOfBirth; // is this correct it compiles fine
}
int getYearOfBirth() {
return yearOfBirth;
}
public static void main(String args[])
{
Creature c = new Creature();
c.setYearOfBirth(89);
Creature d = new Creature();
c.setYearOfBirth(d);
System.out.println(c.yearOfBirth);
}
}
Is there any mistake in this code?
Is "other.yearOfBirth" wrong? My faculty says it is wrong but it works fine for me.
As written, it will work, as you discovered. I suspect that there's a fundamental misunderstanding at play, though.
My psychic powers tell me that your instructor expected code more like the following:
class Creature {
private int yearOfBirth=10;
public void setYearOfBirth(int year) {
yearOfBirth = year;
}
public void setYearOfBirth(Creature other) {
yearOfBirth = other.yearOfBirth;
}
public int getYearOfBirth() {
return yearOfBirth;
}
}
class Program {
public static void main(String args[]) {
Creature c = new Creature();
c.setYearOfBirth(89);
Creature d = new Creature();
c.setYearOfBirth(d);
System.out.println(c.yearOfBirth); // This will not compile
}
}
The misunderstanding is that you've only created one class-- your main application class. This effectively makes yearOfBirth a sort of hybrid global value that you can access from your main method. In more typical designs, Creature is a class that is completely independent of your main method. In that case, you must only access Creature through its public interface. You would not be able to access its private field directly.
(Note to any pedants out there: Yes, I know I'm simplifying.)
You have to ask your faculty to explain why they think it's wrong (its perhaps a question of style, or even a misunderstanding), so you can learn from it.
Ultimately this person is going to impact your grades. This is an excellent opportunity to have a positive interaction with them. The more involved your teachers are with teaching you personally, the better your opportunity for mastering your subject will be.
If on the other hand when you're told something is wrong you go away privately and ask the general internet community, there is a risk that you'll be told you're right and you'll end up a false sense of superiority over your teachers which will be very counterproductive.
i detect nothing wrong.
the code works, because an instance or class can access private members of other instances of the same class. this is by design.
No, there is no problem at all with it.
Look, it depends on the viewer opinion. But for a given context this code may be just perfect.
For some other context this may not be correct. So it depends of how is going to be used.
Accessing a private member directly from another instance, is correct ( not always desirable though, for instance when you're subclassing ) that's why it is private in first place. You are saying "Hey, this is mine and I know how to use it"
Using the default access modifier for the other two methods, says that your intention is they should not be used by other classes outside the package.
Probably the only thing I would add is to make the class final.
final class Creature
If you want to make it inheritable you probably have to review the get/set for the yearOfBirth attribute, but they way it is is perfect to me.
NOW The most important thing here, is that you understand what each part of your code does, and how it affects its behavior.
You should no code just by luck ( sorry I don't know what's the correct expression for this ) but you should know what you're doing each time you type something, and how do you intend to be used.
I see two "issues," though I hesitate to call them mistakes:
You're explicitly setting Creature c's age as 89, and then rewriting that age with the uninitialized default (!) of Creature d. If this is what you intend to do, then fine, but at the very least you're wasting a few cycles to set a value that you intend to throw out later.
You're possibly violating the JavaBeans naming conventions.
To explain the latter point: a lot of Java libraries and frameworks (notably JSP) rely on JavaBeans to treat the object as a component. I haven't dived deeply into the actual mechanisms used, but from what I've read it relies on Introspection of the JavaBeans class to infer properties and the types of those properties. By overloading your setter setYearOfBirth() to accept both an int and a Creature, you could throw off the Introspection. (See here for a decent introduction to JavaBeans.)
This is not a big deal -- its entirely possible that you won't use this class as a JavaBean, and if you do it's trivial to refactor it so it works. But your teachers would probably prefer something a little cleaner, like the following:
class Creature {
private int yearOfBirth=10;
public void setYearOfBirth(int year) {
yearOfBirth = year;
}
int getYearOfBirth() {
return yearOfBirth;
}
public static void main(String args[])
{
Creature c = new Creature();
c.setYearOfBirth(89);
Creature d = new Creature();
c.setYearOfBirth(d.getYearOfBirth());
System.out.println(c.getYearOfBirth());
}
}
Now all of your access to yearOfBirth comes via the public getter methods, which helps encapsulation, and will prevent the code from breaking if your main method moves to another class. (As Greg D correctly pointed out.)
Also, this has the added benefit of making the intent of your code clear, which becomes more and more important when you start writing code for others to maintain and modify.
It's wrong because you're accessing a private member (you declared private int yearOfBirth) of another object although the class type is the same. You should use the public getter you defined instead: yearOfBirth = other.getYearOfBirth()
yearofBirth is a private int. Therefore the call to other.yearOfBirth would presumably fail...

Categories