I've seen many code-parts in mostly old(java mostly) projects that look like
if(type == typeOne){
callFunctionOne();
}else if (type == typeTwo){
callFunctionTwo();
}else if (type == typeThree){
callFunctionThree();
}//i've seen over ~800 lines like this!
where "type" could be an enum or really anything and the whole thing could be written in switch/case style too.
My question is: is there a "better"(more stylish/shorter/more readable) way to achieve this?
I've seen constructs in PHP like:
//where $type = "one","two" etc.
$functionName = 'callFunction' . $type;
new $functionName();
But im not sure if this is realy the "better" way and if its even possible in other Languages.
The more interesting question imo is what exactly you want to achieve by this?
Java is an object-oriented language. Therefore i would solve this by one subclass per type:
abstract class Type{
abstract void method();
}
class Type1 extends Type{
void method(){
//do sth. specific for this type
}
}
If the methods are actually all in the same class you could still call them out of these classes by simply passing yourself (i see that this could get ugly).
class RandomClass(){
void method1(){
//do sth for type1
}
void method2(){
//do sth for type2
}
}
abstract class Type{
RandomClass randomClass;
Type(RandomClass randomClass){
this.randomClass = randomClass;
}
abstract void method();
}
class Type1 extends Type{
void method(){
randomClass.method1();
}
}
class Type2 extends Type{
void method(){
randomClass.method2();
}
}
Otherwise you could use reflection, like suggested by Sohaib (example taken from his suggested link):
Yyyy.class.getMethod("methodName").invoke(someArgs)
But using Reflection for somehting like this seems very unhandy as it is inperformant and a nice trap for later maintenance (just imagine someone starts renaming the methods).
So to answer the question itself (at least how i understand it):
Dynamically calling methods e.g. by determining their name dynamically at runtime, is something you only do in scripting languages.
The object-oriented approach might come with overhead, but at the end is the better style for this kind of language.
If both solutions do not work for you, a switch statement or if-else cascade is your best alternative.
As noted in a comment, there are ways to use java's reflection capabilities. See this question for how to do that. That said, reflection is pretty bad style in java and should only be used if you really have no other option. Java's really big on OO-style programming and static type checking and using reflection is skimping on both of those focuses. In doing so you'll likely make your code just as complicated and way harder to debug.
Without reflection, there's not much better you can do if the code block in question happens exactly once. You'd have to implement the logic somewhere, probably involving the same if-else/switch block. However, if you find yourself copy-pasting that same if-elseif-elseif-elseif.... block in multiple places, you can do a bit better.
If type is an enum, you can move the logic to the enum itself, which is really nice from an OO standpoint. Consider the following:
public enum Direction {
NORTH,
SOUTH,
EAST,
WEST
}
public class Foo {
public void bar(Direction d) {
//At some point we want some logic to depend on the vector dx,dy form of d
int dx = 0;
int dy = 0;
switch(d) {
case NORTH:
dy = -1;
break;
case SOUTH:
dy = 1;
break;
case EAST:
dx = 1;
break;
case WEST:
dx = -1;
break;
}
//Use the values in dx, dy
}
}
It's clearly a bad idea to copy-paste this block around your project. If you ever add a new direction, you'd have to return to every such block to add the correct addition. From an OO standpoint, the dx, dy fields are truly part of the enum value, and should be a part of it to begin with. Thus we can change the above to the following:
public enum Direction {
NORTH,
SOUTH,
EAST,
WEST;
public int getDX() {
switch(this) {
case WEST: return -1;
case EAST: return 1;
default: return 0;
}
}
public int getDY() {
switch(this) {
case NORTH: return -1;
case SOUTH: return 1;
default: return 0;
}
}
}
Or, (IMO) even better, represent them as a field
public enum Direction {
NORTH(0,-1),
SOUTH(0,1),
EAST(1,0),
WEST(-1,0);
private int dx;
private int dy;
private Direction(int dx, int dy) {
this.dx = dx;
this.dy = dy;
}
public int getDX() {
return dx;
}
public int getDY() {
return dy;
}
}
From there we can simply use these methods directly in Foo.bar() and don't need any logic:
public class Foo {
public void bar(Direction d) {
//can directly use d.getDX() and d.getDY()
}
}
Your question about function calling is the same, if one level removed. We can either add the switch straight to the enum:
public enum Type {
VALUE_ONE, VALUE_TWO, ...
public void callFunc() {
switch(this) {
case VALUE_ONE:
callFunctionOne();
return;
case VALUE_TWO:
callFunctionTwo();
return;
//....
}
}
}
And then just use it by directly referencing that function:
Type t = //....
t.callFunc();
You could even use some java-8 stuff to represent the function-to-call as a field
#FunctionalInterface
public interface Unit {
public void apply();
}
public enum Type {
VALUE_ONE(Foo::baz),
VALUE_TWO(Foo::baz2),
//...
private Unit funcToCall;
private Type(Unit u) {
this.funcToCall = u;
}
public void callFunc() {
funcToCall.apply();
}
}
If type is not an enum, you can use some (but not all) of the above options. You can still lump your switch logic into a helper method/class and pass control over to it instead of copy/pasting. The more that type is supposed to represent something, and the more you find yourself wanting to switch over it, the more likely an enum is the correct choice.
Related
I'm having trouble calling move.m_north from another function.
It is asking me to make the class move and the function m_north static, but if I do i can't reference y unless I make it static too.
I found that if y is static then any dot object I make will have the same value for y, and I need multiple dots
public class dot {
int y=0; //<-- 3. but if I make this static then it will stay the same for every object
public void step(int direction) {
switch (direction){
case 0:
move.m_north(); //<-- 1. is asking to make move.m_north static
}
}
public class move {
public int m_north() {
if (y > 0) {
y -= 1; //<-- 2. but I need to modify and read non static variables
return -1;
} else return -2;
}
}
}
I am able to call m_north if it is not in the move class but there are many similar functions which I believe need to be split up so I can use same names and it becomes easier to find different functions.
I would much appreciate any assistance.
You can make this work by declaring an instance of the move class. For example (with captialization changed to match Java naming conventions):
public class Dot {
int y=0;
Move move = new Move();
public void step(int direction) {
switch (direction){
case 0:
move.m_north();
}
}
public class Move {
public int m_north() {
if (y > 0) {
y -= 1;
return -1;
} else return -2;
}
}
}
Note that Move with an uppercase M is the class name, and move with a lowercase m is the name of an instance variable in the class Dot.
The reason this is required is that m_north requires an enclosing instance of Dot in order to access its y field. To put it another way, you need to call m_north on a specific dot's move instance. Making the method static doesn't provide an enclosing dot in scope.
I want to create a switch/case statement in Java and ensure that all the Strings are in the statement.
However, it is easy to create a enum in Java with simple Strings i.e. NORTH, SOUTH, EAST, WEST.
How would it be done for strings with dots and spaces? i.e. "This is the description", "com.stackoverflow.ClassName"
I think the main Problem of this question is, that your IDE is telling you that you are missing enum values within a switch statement. And asks you whether you would like to add them and not your compiler. This of course does not ensure a user of your enum class to have to use every value.
There is an approach mentioned by Joshua Bloch in his Effective Java book (Chapter Emulated extensible enum using an interface which can be changed to work with a switch shown here: Java Enum Switch. But I think the switch solution doesn't provide full security that all enums are used.
But since you wanted to know whether there is a solution using strings, we can also try using a functional approach as shown here: Enum Switch Functional Approach and make it work with string fields instead of enums.
This could look as follows:
public class Direction {
private static final String NORTH = "north";
private static final String SOUTH = "south";
private static final String EAST = "east";
private static final String WEST = "west";
public interface SwitchResult {
void NORTH();
void SOUTH();
void EAST();
void WEST();
}
public static void switchValue(String direction, SwitchResult result){
switch (direction){
case NORTH:
result.NORTH();
break;
case SOUTH:
result.SOUTH();
break;
case EAST:
result.EAST();
break;
case WEST:
result.WEST();
break;
}
}
public static void main(String[] args) {
String direction = "west";
Direction.switchValue(direction, new SwitchResult() {
#Override public void NORTH() {
System.out.println("this time north");
}
#Override public void SOUTH() {
System.out.println("this time south");
}
#Override public void EAST() {
System.out.println("this time east");
}
#Override public void WEST() {
System.out.println("this time west");
}
});
}
}
As you can see in the main method, if you want to call the switchValue function you have to pass your string and an implementation of your interface, which ensures you to override every possibility. In exchange for this the code is very redundant.
This approach could be used if you only have read access to a class which offers a bunch of String values and you want to build a switch statement around it. Anywhere else you should really stick to an approach using enums.
If you want to use third party tools to really ensure without having to write any redundant boilerplate code have a look at:
FindBugs SF_SWITCH_NO_DEFAULT: But this only covers default branch of switch statement.
#EnumMapper: Annotation processor which checks at compile-time that all enum constants are handled
If you are asking whether you can create an enum where the constants have spaces, then the answer is 'no'.
Enum constants are normal Java identifiers, like class or variable names so they can not have spaces or special characters in them.
However is it impossible to link an enum with a String? No.
If for some reason you want your switch case to use an enum for readability/brevity, but your inputs are Strings that can have spaces, dots, special characters..., then there is a way.
You need to extend your enum to have an extra field (let's call it label) to hold this String.
In your method with the switch case that uses the enum, you can call a findByLabel method
that returns the enum that corresponds to the provided String.
Here is a little example class that uses your enum values NORTH, EAST, SOUTH, WEST,
linked to Strings of different (invalid enum naming) structures.
public class EnumExample {
enum SwitchEnum {
NORTH ("North star"),
EAST ("Eastpack rulez!"),
SOUTH ("https://www.southafrica.net/"),
WEST ("java.awt.BorderLayout.WEST");
private final String label;
SwitchEnum(final String label) {
this.label = label;
}
#Override
public String toString() {
return this.label;
}
private static final Map<String,SwitchEnum> map;
static {
map = new HashMap<String,SwitchEnum>();
for (SwitchEnum v : SwitchEnum.values()) {
map.put(v.label, v);
}
}
public static SwitchEnum findByLabel(String label) {
return map.get(label);
}
}
public static String doEnumSwitch(String enumString) {
SwitchEnum enm = SwitchEnum.findByLabel(enumString);
if (enm != null) {
String enumReturn = enm.name() +" : "+ enm;
switch (enm) {
case NORTH:
return enumReturn +" - Up there.";
case EAST:
return enumReturn +" - Now for sale.";
case SOUTH:
return enumReturn +" - Now with 50% more elephants.";
default:
return "UNHANDLED ENUM : "+ enm.name() +" - "+ enm;
}
} else {
return "UNKNOWN ENUM : "+ enumString;
}
}
public static void main(String[] args) {
System.out.println(doEnumSwitch("North star"));
System.out.println(doEnumSwitch("Eastpack rulez!"));
System.out.println(doEnumSwitch("https://www.southafrica.net/"));
System.out.println(doEnumSwitch("java.awt.BorderLayout.WEST"));
System.out.println(doEnumSwitch("I only want to get out of here."));
}
}
This outputs the following
NORTH : North star - Up there.
EAST : Eastpack rulez! - Now for sale.
SOUTH : https://www.southafrica.net/ - Now with 50% more elephants.
UNHANDLED ENUM : WEST - java.awt.BorderLayout.WEST
UNKNOWN ENUM : I only want to get out of here.
I have some variables:
float firstFloatSize = 0.0;
float secondFloatSize = 1.0;
float thirdFloatSize = 2.0;
float fourthFloatSize = 3.0;
I would like to change these variables from a method, which would receive the name and the new value of the variable as a parameter. Like this:
public void changeValue("firstFloatSize", 3.0);
If I ran that, I would change the value of the variable "firstFloatSize" to 3.0.
Would this be somehow possible? I know I could create a wrapper class for the floats and implemented such a method in that class, but I'm just curious if I could achieve this in another way.
use setProperty from apache common PropertyUtils
PropertyUtils.setProperty(this,"firstFloatSize", 3.0);
You could do this using reflection, but it would create code that would be difficult to maintain. For example, changing a variable name will break the reflection code: you would not notice that until runtime. You'd also be circumventing encapsulation (perhaps moot given you note that the member data are public).
I'd suggest you do this in the normal way, with set and get methods.
If the main discriminatory point of these fields is the "first", "second", etc., then you could use an array to store the values, und set up a method which changes the values according to the index in the array:
float[] floatSizes = new float[]{ 0, 1, 2, 3 };
public void changeValueAtPosition(int index, float newValue){
floatSizes[index] = newValue;
}
This example of course lacks some common guards on the parameters (like ensuring the index is valid), and could be improved by using a Standard Type (like an enum) instead of a primitive int to switch the value you want to change.
Changing the "firstFloatSize" would then be possible by calling changeValueAtPosition(0, 3);
To reiterate the point of other answers: Do Not Use Reflection if there are other, simpler ways. Reflection-based code is a maintenance nightmare in any project size > 100 LOC.
I recommend to use third party libraries.
But if you want to use Java raw APIs, below is a sample code..
public class ReflectionSample {
private float value1 = 1.0f;
public float getValue1() {
return this.value1;
}
public void changeValue(String fieldName, float value) throws Exception {
Field field = this.getClass().getDeclaredField(fieldName);
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.set(this, value);
field.setAccessible(accessible);
}
public static void main(String[] args) throws Exception {
ReflectionSample sample = new ReflectionSample();
sample.changeValue("value1", 3.0f);
System.out.println(sample.getValue1());
}
}
You have basically two options:
Either write a custom dispatch method:
public void changeValue(String fieldName, float newValue)
{
// Java 6 style:
if("firstFloatSize".equals(fieldName)) {
targetClass.firstFloatSize = newValue;
} else if("secondFloatSize".equals(fieldName)) {
targetClass.secondFloatSize = newValue;
} else if // ... and so on
// or, alternatively, Java 7 style:
switch(fieldName)
{
case "firstFloatSize": targetClass.firstFloatSize = newValue; break;
case "secondFloatSize": targetClass.secondFloatSize = newValue; break;
// ... and so on
}
}
Or use reflection:
public void changeValue(String fieldName, float newValue)
{
try
{
Field field = targetObject.getClass().getField(fieldName);
field.setFloat(targetObject, newValue);
}
catch( ... ) { ... }
}
I don't know if your floats are fields in the same class or another class. If it's the same class, you don't need the targetObject, obviously. Otherwise, of course, you need to replace targetObject with a reference to the object you want.
Note that both ways are not very nice as other comments already state. Both are not very maintainable and if, for example, you want to rename one of the floats in the future, then you have to manually check for all occurrences of the string, because your compiler cannot determine correctness in these cases.
Also (though this is kind of obvious), if you have multiple similar floats which you want to access like this, you could also create a single array and use an index (possibly backed by an enum) instead of a string to address them. But that goes too far away from the original question so I won't elaborate here further...
As a good coding practice.
You should not have public variables in your class.
Variables should be private with proper get and set methods. That is one of the basic OOPs principle. Encapsulation.
But back to your code.
First there is a small problem in how you have defined float variables. these should be
float firstFloatSize = 0.0f;
Now there are few ways you can achieve this.
Writing your own reflection based code.
Using conditional code something like below.
Using Apache PropertyUtils. Which uses reflection to set your property.
Still in the end your calling code should be calling a proper set method. Hope it helps.
public void changeValue(String property, float value) {
if(property.equals("firstFloatSize")) {
firstFloatSize = value;
} else if(property.equals("secondFloatSize")) {
secondFloatSize = value;
} else if(property.equals("thirdFloatSize")) {
thirdFloatSize = value;
} else {
fourthFloatSize = value;
}
}
Not sure what exactly you need to set values this way, but this is what i came up without reflection:
public class PropertySetter {
private float valOne;
private float valTwo;
private float valThree;
private float valFour;
public void setValue(FIELDS name, float value) {
switch (name) {
case valOne:
valOne = value;
break;
case valTwo:
valTwo = value;
break;
case valThree:
valThree = value;
break;
case valFour:
valFour = value;
break;
default:
throw new AssertionError(name.name());
}
}
public enum FIELDS {
valOne,
valTwo,
valThree,
valFour;
}
}
however if reflection is allowed, then i would do this:
public class ReflectionSetter {
private float valOne;
private float valTwo;
private float valThree;
private float valFour;
public boolean setValue(String name, float value) {
Field[] fields = this.getClass().getDeclaredFields();
for (Field f : fields) {
if (f.getName().equals(name)) {
try {
f.setFloat(this, value);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(ReflectionSetter.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}
}
return false;
}
}
First method is a bit difficult to maintain because refactoring of this class would be a nightmare.
Second way is quite nice, because you only just need to know fieldname.
The old way, if we wanted to switch on some complicated bitmask, we could easily do it like this (a random example from the top of my head just to demonstrate the issue):
private static final int MAN = 0x00000001;
private static final int WOMAN = 0x00000002;
// ...alive, hungry, blind, etc.
private static final int DEAD = 0xFF000000;
public void doStuff(int human) {
switch (human) {
case MAN | DEAD:
// do something
break;
// more common cases
}
}
Nowadays, since we use enums and EnumSets, I'd sometimes like to do a similar thing:
enum Human {
MAN, WOMAN, DEAD; // etc.
}
public void doStuff(EnumSet human) {
switch (human) {
case Human.MAN | Human.DEAD:
// do something
break;
// more common cases
}
}
which doesn't work, because we can only switch on an int, enum or String value. At this point, I realized it can't be done, even though that enum values are basically just hidden integers. But I like to dig around and the feature looks very useful, so:
private static final EnumSet<Human> DEAD_MAN = EnumSet.of(Human.MAN, Human.DEAD);
public void doStuff(EnumSet human) {
switch (human) {
case DEAD_MAN:
// do something
break;
// more common cases
}
}
Still no luck. Knowing the trick for switch on Strings and that EnumSets are actually 64-bit fields (or arrays of them), I would also try:
switch (human.hashCode()) {
case (Human.MAN.hashCode() | Human.DEAD.hashCode()):
// do something
break;
// more common cases
}
thinking that when the Human hashCode() would be properly implemented to give consistent results, it could work. Nope:
java.lang.Error: Unresolved compilation problem: case expressions must be constant expressions
Now, I wonder why there's no possibility to do this. I always thought of enums and EnumSets in Java like a proper replacement for those old-school bitfields, but here it seems that the new ways can't handle more complicated cases.
The right solution kind of sucks compared to any of the switch possibilities:
public void doStuff(EnumSet human) {
if (human.contains(Human.MAN) && human.contains(Human.DEAD)) {
// do something
} else {
// more common cases
}
}
In particular, since the introduction of switch on Strings, I believe there are at least two possible implementations of switch on EnumSets:
In the case (Human.MAN | Human.DEAD) expressions, simple use a compile-time type check and ordinal() instead of the enums themselves.
Using the same trick as for Strings.
At compile time, compute the hashCode() of the name of the enum values (and possibly something additional - the number of values in enum, the ordinal() etc. - everything is static and constant from the compile time on). Yes, this would mean to change the hashCode() either of the EnumSet class or the Enum class.
use instead of the enums themselves
Now, is there any serious obstacle I didn't take into count (I can come up with a few, all can be easily overcame) that would render this impossible to implement easily? Or am I right that this would indeed be possible, but not desirable enough for Oracle to implement it, because it is not used so often?
Also, let me state that this is a purely academic question possibly without a good answer (don't know, I wouldn't ask otherwise). I might make it community wiki if it proves to be unanswerable. However, I couldn't find an answer (or even anyone discussing it) anywhere, so here it goes.
In Java & Object Oriented world you would have class with setters and getters on an Object and you would use those
public void doStuff(Human human) {
if(human.isDead()) {
if(human.isMale()) {
// something
} else if (human.isFemale()) {
// something else
} else {
// neither
}
}
}
Note: switch is not a good idea because it only takes exact matches. e.g. case MAN | DEAD: will not match MAN | HUNGRY | DEAD unless you only want to match those who were not hungry before they died. ;)
I will see your "absolutely sufficient" benchmark and raise you another flawed benchmark which "shows" it takes a fraction of a clock cycle (in cause you are wondering, that is hard to believe)
public static void main(String... args) {
Human human = new Human();
human.setMale(true);
human.setDead(true);
for(int i=0;i<5;i++) {
long start = System.nanoTime();
int runs = 100000000;
for(int j=0;j< runs;j++)
doStuff(human);
long time = System.nanoTime() - start;
System.out.printf("The average time to doStuff was %.3f ns%n", (double) time / runs);
}
}
public static void doStuff(Human human) {
if (human.isDead()) {
if (human.isMale()) {
// something
} else if (human.isFemale()) {
// something else
} else {
// neither
}
}
}
static class Human {
private boolean dead;
private boolean male;
private boolean female;
public boolean isDead() {
return dead;
}
public boolean isMale() {
return male;
}
public boolean isFemale() {
return female;
}
public void setDead(boolean dead) {
this.dead = dead;
}
public void setMale(boolean male) {
this.male = male;
}
public void setFemale(boolean female) {
this.female = female;
}
}
prints
The average time to doStuff was 0.031 ns
The average time to doStuff was 0.026 ns
The average time to doStuff was 0.000 ns
The average time to doStuff was 0.000 ns
The average time to doStuff was 0.000 ns
Thats 0.1 clock cycles on my machine, before it is optimised away completely.
How about using Set methods of EnumSet.
private static final EnumSet<Human> DEAD_MAN =
EnumSet.of(Human.MAN, Human.DEAD);
public void doStuff(EnumSet human) {
if ( human.containsAll( DEAD_MAN ) )
{
// do something
break;
}
else
{
// more common cases
}
}
Acutally EnumSet's implementation of Set interface methods is very efficient and underneath is the bitfield comparison that you are looking for.
Do the following (based on your example):
enum Human {
MAN, WOMAN, DEAD; // etc.
}
public void doStuff(Human human) {
switch (human) {
case MAN:
case DEAD:
// do something
break;
// more common cases
}
}
If you want EnumSet's then you can't use switch and should refactor it to if
public void doStuff(EnumSet<Human> human) {
if( human.containsAll(EnumSet.<Human>of(Human.MAN, Human.DEAD) {
// do something
}
}
latter variant will do bitwise comparison internally.
I am in the process of refactoring my existing code. It actually works fine, but it is a bit cluttered with multiple if-else conditionals checking the value of one variable and change the value of a second variable to an updated value taken from a fixed enumeration structure.
else if (var1 == 'valueX')
{
if (var2 == MyEnum.A)
var2 = MyEnum.B;
else if (var2 == MyEnum.B)
var2 = MyEnum.C;
else if (var2 == MyEnum.C)
var2 = MyEnum.D;
else if (var2 == MyEnum.D)
var2 = MyEnum.A;
}
else if (....)
{
..similar block of conditionals
}
I am a bit confused as to what is the best way to refactor and clean-up this code. Would you suggest the use of a switch perhaps? Or something more elegant?
Thanks in advance!
The classic answer to refactoring conditionals is Replace Conditional With Polymorphism. In this case, if each of MyEnum knew what its successor was, you could simply say (in the 'valuex' case: var2 = var2.successor. For var1 - if it could be an object that implemented an interface that knew how to handle whatever you're doing inside the loop, and each implementing class knew what it, specifically, should do... Well, you'd be done.
Update:
And here's a dandy little successor function in a test case:
public class EnumTest extends TestCase {
private enum X {
A, B, C;
public X successor() {
return values()[(ordinal() + 1) % values().length];
}
};
public void testSuccessor() throws Exception {
assertEquals(X.B, X.A.successor());
assertEquals(X.C, X.B.successor());
assertEquals(X.A, X.C.successor());
}
}
At least with J2SE 1.5 forward, you can give enums extra attributes. This means you might be able to replace that entire string of if-else with something that looks like
var2 = var1.getNextInSequence();
Now, in this case, it looks like you would want the attribute to be a reference to another enum, which adds some wrinkles, for example you can't forward reference enums when you initialize them, but there might be a workable solution for you this way.
When the attributes aren't other instances of the same enum, this kind of thing will work:
public enum Animal {
FOX(4),
CHICKEN(2),
WORM(0);
private int countLegs;
Animal(int n) {
countLegs = n;
}
public int getLegCount() {
return countLegs;
}
// .. more getters setters etc
}
But when the enum is self-referential, you have to be careful about the order of declaration of your instances. I.e., this will have some issues:
public enum Animal {
FOX(4, CHICKEN), // 'CHICKEN' doesn't exist yet
WORM(0, null),
CHICKEN(2, WORM); // this actually will compile
private int countLegs;
private Animal eatsWhat;
Animal(int n, Animal dinner) {
countLegs = n;
eatsWhat = dinner;
}
public int getLegCount() {
return countLegs;
}
// .. getters, setters, etc
}
So if you had need of a circular set of references among the enums, you'd have to work something else out, but if not, you could use this technique, though you may have to order your enum instances just so to make it work.
You can use a simple map:
enum MyEnum { A, B, C };
Map<MyEnum, MyEnum> VALUE_X = new HashMap<MyEnum, MyEnum>() {{
put(MyEnum.A, MyEnum.B);
put(MyEnum.B, MyEnum.C);
...
}};
// define another kind of ordering
Map<MyEnum, MyEnum> VALUE_Y = new HashMap<MyEnum, MyEnum>() {{
put(MyEnum.A, MyEnum.D);
put(MyEnum.B, MyEnum.A);
...
}};
This way, the logic of the next var2 value isn't hard-coded in the enum itself, and can be dependant of context (i.e. value of var1):
if ("valueX".equals(var1)) { // use equals() instead of == for Strings
var2 = VALUE_X.get(var2);
}
else if ("valueY".equals(var1)) {
var2 = VALUE_Y.get(var2);
}