Here is the normal way I would do things in C++:
class object
{
public:
enum
{
STATE_ACTIVE = 0,
STATE_INACTIVE,
OBJ_NUM_STATES,
}
int m_State;
virtual void UpdateState ()
{
switch(this->m_state)
{
case STATE_ACTIVE: /* do stuff*/ break;
case STATE_INACTIVE: /* do stuff*/ break;
}
}
}
class SpecialGameObject : public Object
{
public:
enum
{
STATE_SPECIAL_A = OBJ_NUM_STATES + 1,
STATE_SPECIAL_B,
SPECIAL_NUM_STATES,
}
virtual void UpdateState ()
{
Object::UpdateState();
switch(this->m_State)
{
case STATE_ACTIVE: /* do extra stuff */ break;
case STATE_SPECIAL_A: /* do special stuff*/ break;
case STATE_SPECIAL_B: /* do special stuff*/ break;
}
}
}
I am trying to figure out to get all of this functionality to work in java. Specifically I need working:
1) Ability for derived classes to have state values that automatically line up after the derived state values. That way I can add new state values to the base class without worrying about them overlapping the rage of state values used in any of the derived classes.
2) Ability to use the state values as cases in switch statements.
I looked into using static final ints to implement my state values. But those can't be used as case statements. Then I looked into extending enums, but that isn't allowed.
Does anyone have any suggestions for me?
Thank you
You need to implement the state pattern in Java. This might help you. Wikipedia also has a simple and easy to understand example in Java.
Is this enough to get you going?
final class GameObject {
enum State { ACTIVE, INACTIVE };
State state;
void updateState()
{
switch(state) {
case ACTIVE :
// update state
break;
case INACTIVE:
// update STATE
break;
default:
assert false : "never get here";
}
}
}
Note that in Java, enums are final so you can't extend an enum directly. (Reference this SO question.) If you really need to extend the notion of state into specialized subclasses, things are probably complicated enough that you should consider using polymorphism rather than switch statements (see also here) to get what you want. Alternatively, you could bundle the "super" state with specialized substates in a wrapper super- and sub-classes, perhaps with defined interfaces.
And, if you want to get seriously warped, you could do something like this. It's very cool that Java enums can implement interfaces, but I think this counts as a particularly ugly way of using that feature for your question...
final class GameObject {
ActiveStateful state;
interface ActiveStateful {
State activeState();
}
enum State implements ActiveStateful {
ACTIVE, INACTIVE;
public State activeState() {
return this;
}
};
enum SubState implements ActiveStateful {
SPECIAL_A(State.ACTIVE), SPECIAL_B(State.ACTIVE);
SubState(final State activeState) {
this.activeState = activeState;
}
final State activeState;
public State activeState() {
return activeState;
}
}
}
But those can't be used as case statements.
If I told you this was incorrect, that would solve your problems, yes? This is incorrect: you can switch on static final int constants.
I'd recommend using an enum and its ordinal values for switch statements. That's what enum was born for.
Please consider getting rid of switch altogether. It is a horrible abomination that should have ceased decades ago but didn’t. Read the excellent “Abandoning switch In Three (And A Bit) Steps” article for more information.
Related
This question already has answers here:
Is custom enum Serializable too?
(3 answers)
Closed 2 years ago.
I have recently started to use Java after a long period of using C,C++ and C#. I can't get my head around how Java enums are supposed to work.
After some research I have created the following:
public class RedRoad implements Serializable, Parcelable
{
// ... other parts removed for clarity
public enum State
{
NOT_STARTED(0),
PART_DONE(1),
COMPLETED(2);
private int value;
private State(int value) {
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
}
I am storing these State values in an sqlite database as ints using getValue(), retrieving them using setValue(), then sending the resulting ''Road' objects via a broadcast. Then I am doing this:
switch (road.state) {
case COMPLETED:
pline.getOutlinePaint().setColor(Color.GREEN); break;
case PART_DONE:
pline.getOutlinePaint().setColor(Color.argb(0xFF,0xFF,0xA5,0x00)); break;
case NOT_STARTED:
default: pline.getOutlinePaint().setColor(Color.RED);
}
but the first two cases are never called, even though I have checked that road.state.getValue() is sometimes 1 , not zero.
Furthermore, if I change the switch code to this:
switch (road.state.getValue()) {
case 2:
pline.getOutlinePaint().setColor(Color.GREEN); break;
case 1:
Log.d("*** road state ", String.valueOf(road.state.getValue()));
Log.e("*** road state ", String.valueOf(road.state));
pline.getOutlinePaint().setColor(Color.argb(0xFF,0xFF,0xA5,0x00));
break;
case 0:
default:
pline.getOutlinePaint().setColor(Color.RED);
}
then the colour gets set as requested. And I get an extraordinary ouput in the log:
D/*** road state: 1
E/*** road state: NOT_STARTED
How can this be? NOT_STARTED is defined as zero!
[Edit]
Later discovered that , apart from the above, (which I can find a workaround for), the values are incorrect after being sent from the async task to the main activity (the 'Road' class is parcelable). If I log state.getValue() before sending , then again after receipt, any non-zero values have changed to zero.
You're calling String.valueOf on an enum constant in the second instance, which calls the toString method of the enum. The default toString implementation of enums returns the name field, which makes NOT_STARTED the valid return value.
Enums are essentially abstract classes with a finite number of implementations, with each implementation guaranteed to only exist once per JVM.
#AndyTurner is correct about not using a setter. I have now done some more tests, in a new app specially created, and the setter gives totally unpredictable results.
So the solution I have used (for setting the value from an 'int' in the db) is a somewhat boring
protected void setState(int i) {
switch (i)
{
case 2: state = State.COMPLETED; break;
case 1: state = State.PART_DONE; break;
default: state = State.NOT_STARTED;
}
}
Although this works , it seems to me to partly defeat the reason for using an Enum (instead of an int) to start with.
And, since creating the setter (that I had originally) gives incorrect results, I wonder why Android Studio (4.1) didn't give me a warning about it? It's very happy to give me warnings about so many other (less important) things.
I've looked at various Q&As on SO similar to this question but haven't found a solution.
What I have is an enum which represents different ways to view a TV Guide...
In the NDroid Application class
static enum guideView {
GUIDE_VIEW_SEVEN_DAY,
GUIDE_VIEW_NOW_SHOWING,
GUIDE_VIEW_ALL_TIMESLOTS
}
...when the user changes the view an event handler receives an int from 0-2 and I'd like to do something like this...
In an Android Activity onClick(DialogInterface dialog, int which) event handler
// 'which' is an int from 0-2
switch (which) {
case NDroid.guideView.GUIDE_VIEW_SEVEN_DAY:
...
break;
}
I'm used to C# enums and select/case statements which would allow something like the above and I know Java does things differently but I just can't make sense of what I need to do.
Am I going to have to resort to if statements? There will likely only ever be 3 choices so I could do it but I wondered how it could be done with switch-case in Java.
EDIT Sorry I didn't completely expand on the issue as I was looking at it as being a generic Java issue. I've added to the question to explain a bit further.
There isn't anything that's Android specific which is why I didn't tag it as Android but the enum is defined in the Application class and the code where I wan't the switch is in an Activity. The enum is static as I need to access it from multiple Activities.
The part you're missing is converting from the integer to the type-safe enum. Java will not do it automatically. There's a couple of ways you can go about this:
Use a list of static final ints rather than a type-safe enum and switch on the int value you receive (this is the pre-Java 5 approach)
Switch on either a specified id value (as described by heneryville) or the ordinal value of the enum values; i.e. guideView.GUIDE_VIEW_SEVEN_DAY.ordinal()
Determine the enum value represented by the int value and then switch on the enum value.
enum GuideView {
SEVEN_DAY,
NOW_SHOWING,
ALL_TIMESLOTS
}
// Working on the assumption that your int value is
// the ordinal value of the items in your enum
public void onClick(DialogInterface dialog, int which) {
// do your own bounds checking
GuideView whichView = GuideView.values()[which];
switch (whichView) {
case SEVEN_DAY:
...
break;
case NOW_SHOWING:
...
break;
}
}
You may find it more helpful / less error prone to write a custom valueOf implementation that takes your integer values as an argument to resolve the appropriate enum value and lets you centralize your bounds checking.
If whichView is an object of the GuideView Enum, following works well. Please note that there is no qualifier for the constant after case.
switch (whichView) {
case SEVEN_DAY:
...
break;
case NOW_SHOWING:
...
break;
}
The enums should not be qualified within the case label like what you have NDroid.guideView.GUIDE_VIEW_SEVEN_DAY, instead you should remove the qualification and use GUIDE_VIEW_SEVEN_DAY
I like a few usages of Java enum:
.name() allows you to fetch the enum name in String.
.ordinal() allow you to get the integer value, 0-based.
You can attach other value parameters with each enum.
and, of course, switch enabled.
enum with value parameters:
enum StateEnum {
UNDEFINED_POLL ( 1 * 1000L, 4 * 1000L),
SUPPORT_POLL ( 1 * 1000L, 5 * 1000L),
FAST_POLL ( 2 * 1000L, 4 * 60 * 1000L),
NO_POLL ( 1 * 1000L, 6 * 1000L);
...
}
switch example:
private void queuePoll(StateEnum se) {
// debug print se.name() if needed
switch (se) {
case UNDEFINED_POLL:
...
break;
case SUPPORT_POLL:
...
break;
This should work in the way that you describe. What error are you getting? If you could pastebin your code that would help.
http://download.oracle.com/javase/tutorial/java/javaOO/enum.html
EDIT: Are you sure you want to define a static enum? That doesn't sound right to me. An enum is much like any other object. If your code compiles and runs but gives incorrect results, this would probably be why.
Short associative function example:
public String getIcon(TipoNotificacao tipo)
{
switch (tipo){
case Comentou : return "fa fa-comments";
case ConviteEnviou : return "icon-envelope";
case ConviteAceitou : return "fa fa-bolt";
default: return "";
}
}
Like #Dhanushka said, omit the qualifier inside "switch" is the key.
enumerations accessing is very simple in switch case
private TYPE currentView;
//declaration of enum
public enum TYPE {
FIRST, SECOND, THIRD
};
//handling in switch case
switch (getCurrentView())
{
case FIRST:
break;
case SECOND:
break;
case THIRD:
break;
}
//getter and setter of the enum
public void setCurrentView(TYPE currentView) {
this.currentView = currentView;
}
public TYPE getCurrentView() {
return currentView;
}
//usage of setting the enum
setCurrentView(TYPE.FIRST);
avoid the accessing of TYPE.FIRST.ordinal() it is not recommended always
I am doing it like
public enum State
{
// Retrieving, // the MediaRetriever is retrieving music //
Stopped, // media player is stopped and not prepared to play
Preparing, // media player is preparing...
Playing, // playback active (media player ready!). (but the media player
// may actually be
// paused in this state if we don't have audio focus. But we
// stay in this state
// so that we know we have to resume playback once we get
// focus back)
Paused; // playback paused (media player ready!)
//public final static State[] vals = State.values();//copy the values(), calling values() clones the array
};
public State getState()
{
return mState;
}
And use in Switch Statement
switch (mService.getState())
{
case Stopped:
case Paused:
playPause.setBackgroundResource(R.drawable.selplay);
break;
case Preparing:
case Playing:
playPause.setBackgroundResource(R.drawable.selpause);
break;
}
I have an enum as follows:
public enum ServerTask {
HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
}
I also have a string (lets say string = "Execute") which I would like to make into an instance of the ServerTask enum based on which string in the enum that it matches with. Is there a better way to do this than doing equality checks between the string I want to match and every item in the enum? seems like this would be a lot of if statements since my enum is fairly large
At some level you're going to have to iterate over the entire set of enumerations that you have, and you'll have to compare them to equal - either via a mapping structure (initial population) or through a rudimentary loop.
It's fairly easy to accomplish with a rudimentary loop, so I don't see any reason why you wouldn't want to go this route. The code snippet below assumes the field is named friendlyTask.
public static ServerTask forTaskName(String friendlyTask) {
for (ServerTask serverTask : ServerTask.values()) {
if(serverTask.friendlyTask.equals(friendlyTask)) {
return serverTask;
}
}
return null;
}
The caveat to this approach is that the data won't be stored internally, and depending on how many enums you actually have and how many times you want to invoke this method, it would perform slightly worse than initializing with a map.
However, this approach is the most straightforward. If you find yourself in a position where you have several hundred enums (even more than 20 is a smell to me), consider what it is those enumerations represent and what one should do to break it out a bit more.
Create static reverse lookup map.
public enum ServerTask {
HOOK_BEFORE_ALL_TASKS("Execute"),
COPY_MASTER_AND_SNAPSHOT_TO_HISTORY("Copy master db"),
PROCESS_CHECKIN_QUEUE("Process Check-In Queue"),
...
FINAL_ITEM("Final item");
// For static data always prefer to use Guava's Immutable library
// http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html
static ImmutableMap< String, ServerTask > REVERSE_MAP;
static
{
ImmutableMap.Builder< String, ServerTask > reverseMapBuilder =
ImmutableMap.builder( );
// Build the reverse map by iterating all the values of your enum
for ( ServerTask cur : values() )
{
reverseMapBuilder.put( cur.taskName, cur );
}
REVERSE_MAP = reverseMapBuilder.build( );
}
// Now is the lookup method
public static ServerTask fromTaskName( String friendlyName )
{
// Will return ENUM if friendlyName matches what you stored
// with enum
return REVERSE_MAP.get( friendlyName );
}
}
If you have to get the enum from the String often, then creating a reverse map like Alexander suggests might be worth it.
If you only have to do it once or twice, looping over the values with a single if statement might be your best bet (like Nizil's comment insinuates)
for (ServerTask task : ServerTask.values())
{
//Check here if strings match
}
However there is a way to not iterate over the values at all. If you can ensure that the name of the enum instance and its String value are identical, then you can use:
ServerTask.valueOf("EXECUTE")
which will give you ServerTask.EXECUTE.
Refer this answer for more info.
Having said that, I would not recommend this approach unless you're OK with having instances have the same String representations as their identifiers and yours is a performance critical application which is most often not the case.
You could write a method like this:
static ServerTask getServerTask(String name)
{
switch(name)
{
case "Execute": return HOOK_BEFORE_ALL_TASKS;
case "Copy master db": return COPY_MASTER_AND_SNAPSHOT_TO_HISTORY;
case "Process Check-In Queue": return PROCESS_CHECKIN_QUEUE;
}
}
It's smaller, but not automatic like #Alexander_Pogrebnyak's solution. If the enum changes, you would have to update the switch.
basically what needs to happen is that it needs to check what the type of Champion is, and compare it to challenges to see if it can actually do that challenge, its quite hard to explain...
a wizard can fight "magic" and "mystery"
a warrior can fight "fight" and "mystery"
a dragon can fight "fight" and "mystery(only if the dragon talks)"
what I have come up with is this...
public boolean canFight(String nme, int id)
{
Challenge chal = getChallengeObj(id);
Champion champ = getChampionObj(nme.toLowerCase());
if(champ.getType().equals("wizard") && (chal.getTypeAsString().equals("magic") || chal.getTypeAsString().equals("fight"))) {
return true;
} else if(champ.getType().equals("warrior") && (chal.getTypeAsString().equals("fight") || chal.getTypeAsString().equals("mystery"))) {
return true;
} else if((champ.getType().equals("dragon") || champ.getType().equals("dragon") && champ.isMystery()) && (chal.getTypeAsString().equals("fight") || chal.getTypeAsString().equals("magic"))) {
return true;
} else {
return false;
}
}
I thank anyone who has a go at helping me, I am open to any response, even complaints on how complicated the code is!!
(It is checking everything toLowerCase() btw, just in case this isnt clear in the code, as it is in the methods that are called in different classes.
THANKS!!
EDIT
The problem is is that it keeps returning false, and I am a second year university student, so if you could give examples of what you mean by your answers, that would be greatly appreciated :)
Thanks again
The best way to get different behaviour from different types in Java is using polymorphism - basically, put a virtual method into your Champion type with different implementations in Wizard, Warrior, Dragon etc subtypes
A chain of if-else's based on the type of an object is a bit of an anti-pattern in Java - crying out to be refactored into a single call to a virtual method.
Why not use a 2D array to map FightCompatilibity between Challenge and Champ. Model each Champ and Challenge as enum. Maybe, take a look at Visitor Pattern. It might be useful.
This is exactly something, which should be done by class hiearchy. Like if you know, someone is Wizard, you should already known what he can attack or not, therefore you should move responsibility into that Wizard class instead of testing it externally.
I did an example with 4 classes :
In this enum are listed all attack types
public enum AttackTypes {
Magic, Meele, Ranged;
}
This is abstract class, it only helps you define behaviour that is same for all classes. I supposed that every class has some subset of "attack types" (or something similar). In my example, I just suppose, that each class can fight only against some types of attack. In constructor, I get all the attack I can fight and then I can chack it with this canAttack.
public abstract class Champion {
private List<AttackTypes> attackTo;
public Champion(AttackTypes... attack) {
this.attackTo = new ArrayList<>();
this.attackTo.addAll(Arrays.asList(attack));
}
public boolean canAttack(AttackTypes attackType){
for (AttackTypes attack : attackTo){
if (attack == attackType){
return true;
}
}
return false;
}
}
This is simple Warrior class, in my example, it can fight only Magic and Meele :
public class Warrior extends Champion{
public Warrior(){
super(AttackTypes.Magic, AttackTypes.Meele);
}
}
And similar to Warrior, here is Wizard :
public class Wizard extends Champion{
public Wizard(){
super(AttackTypes.Ranged, AttackTypes.Magic);
}
}
This approach is important, because it is extremely easy to add new class (like Ranger for example). You just add him and thats all, you dont have to anything in your already finished code.
Then you can use it as following :
Champion wizard = new Wizard();
Champion warrior = new Warrior();
AttackTypes attackType = AttackTypes.Ranged;
System.out.println("can wizard attack? : " + wizard.canAttack(attackType));
System.out.println("can warrior attack? : " + warrior.canAttack(attackType));
This having this output :
can wizard attack? : true
can warrior attack? : false
A much more flexible approach would be to use a pair of enums. Something like this would be a good start. I haven't exactly implemented your logic because there is a flaw in it:
enum Champion {
Wizard(EnumSet.of(Challenge.Fight, Challenge.Magic)),
Warrior(EnumSet.of(Challenge.Fight, Challenge.Mystery)),
Dragon(EnumSet.of(Challenge.Fight, Challenge.Magic)) {
#Override
public boolean canFight(Champion enemy, Challenge attack) {
// For demonstration.
return susceptible.contains(attack) && enemy == Champion.Dragon;
}
};
protected final Set<Challenge> susceptible;
Champion(Set<Challenge> susceptible) {
this.susceptible = susceptible;
}
public boolean canFight(Champion enemy, Challenge attack) {
return susceptible.contains(attack);
}
}
enum Challenge {
Magic,
Fight,
Mystery;
}
You flaw is in (champ.getType().equals("dragon") || champ.getType().equals("dragon") && champ.isMystery()) which doesn't make sense.
Hi Im a begginer with Java so no complex code etc
Basically to avoid my code from getting too long i want my user to input a choice and then i have a bunch of for and elese's for what happens if they enter a certain phrase, e.g.
if(choice.equals("Fight")) {
//Grab code from fight.java/fight.class
}
else
{
if(choice.equals("Train")) {
//Grab code from train.java/train.class
}
else
so on and so forth for two other possible inputs. I just need to know how to call external code so it doesn't get too cluttered.
You should create objects of these classes.
For example:
if(choice.equals("Fight")) {
//Grab code from fight.java/fight.class
fight f = new fight();
f.foo(); // A method
}else{
if(choice.equals("Train")) {
//Grab code from train.java/train.class
train t = new train();
t.foo(); // A method
}
//...
}
Or you can try static methods like that:
public class train{
public static void foo(){
//...
}
}
Then you can use it.
if(bool_expression){
train.foo(); // foo is a static method
}
Instead of using the for else structure I would suggest using a switch statement. This will look like:
switch(choice){
case"fight":
Fight.kickHard();
break;
case"train":
Train.run();
break;
default:
Program.learn();
}
Don't forget about the break statements when using a switch. In my example I used static methods from the classes. You would probably be well served by looking further into object oriented design to see if you can come up with a more streamlined answer to your particular problem. The additional classes will need to be imported with an import statement. You will want to look into the shortcut for your IDE to do that for you, but it is a fairly elementary statement e.g import my.package.Train; etc.
If you are trying to call static methods, it would be as simple doing the following.
train.doStuff();
If the methods belong to an object you would first have to instantiate an object to access any methods on it.
Train train = new Train();
train.doStuff();
NOTE: an IDE will automatically link up the classes for you. Otherwise you have to manually import these classes first by adding "import somepackage.someclass".
First focus on different things you program can do. Place that code in a method with a name indicating its intent:
private static void doWork(){
System.out.println("Working");
}
private static void play(){
System.out.println("Playing");
}
private static void sing(){
System.out.println("Singing");
}
Now, you need to bind these to user's phrases (assuming Java 7):
switch(choice){
case: "work"
doWork();
break;
case: "play"
play();
break;
case: "sing"
sing();
break;
default:
System.out.println("Unknown choice");
}