enum value for given arguments - java

Is there any esthetic way of retrieving an enum value based on two other enum types? What I'd like to do is to get a state for two enum arguments like is following example:
public enum State{
ONE_STATE,
SECOND_STATE;
THIRD_STATE;
public static State getState(Direction dir, Type type) {
if (dir.equals(Direction.LEFT) && type.equals(Type.BIG)) {
return ONE_STATE;
}
else if (dir.equals(Direction.RIGHT) && type.equals(Type.SMALL)) {
return SECOND_STATE;
}
else if (dir.equals(Direction.UP) && type.equals(Type.SMALL)) {
return FIRST_STATE;
}
return THIRD_STATE;
}
}
Of course this will word but my intention is to make something clearer since number of such possibilities will grow in time.

Why not use a lookup table ? An array of rows - each row containing the 2 inputs and one output.
LEFT, BIG, ONE_STATE
RIGHT, SMALL, SECOND_STATE
etc. and provide a method to look up and return the default if a lookup fails.
Failing that, you could investigate double dispatch

Enums can have fields, you could try something like:
public enum State {
ONE_STATE(Direction.LEFT, Type.BIG),
...
Direction d;
Type t;
private State(Direction d, Type t) {
...
}
public static State getState(Direction d, Type t) {
for (State s : State.values()) {
if (s.d == d && s.t == t) {
return s;
}
}
return null;
}
}

How about putting the Direction and Type as members of the enum, something like this:
public enum State {
ONE_STATE(Direction.LEFT, Type.BIG),
SECOND_STATE(Direction.RIGHT, Type.SMALL);
THIRD_STATE(Direction.UP, Type.SMALL);
private Direction direction;
private Type type;
private State(Direction direction, Type type) {
this.direction = direction;
this.type = type;
}
public static State getState(Direction dir, Type type) {
for (State state : values()) {
if (state.direction == dir && state.type == type) {
return state;
}
}
return THIRD_STATE;
}
}
Note that this will not work if there is more than one different combination for each enum. In that case, you will need to use some sort of lookup table as suggested by another poster. For example, you could use a Map<Pair<Direction, Type>, State>. (Java doesn't have a Pair<T, U> class, but you can easily make one or find one in lots of different libraries.)

You could use switches instead of ifs but that won't make the code shorter. It will have the advantage of being clearer and also, depending on your IDE, you can have it gives you error when the switch is missing cases.
Have the enum with the most items be the outer switch and other the inner switch.
Adding fields to your State enum will work only if there's only one combination of Direction and Type that "reach" that State.
switch(dir) {
case LEFT:
{
switch(type) {
case BIG:
...

Use a nested EnummMap. The "Effective Java" book (Item 33) explains why this is the best solution.
// Using a nested EnumMap to associate data with enum pairs
public enum Phase {
SOLID, LIQUID, GAS;
public enum Transition {
MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),
BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID),
SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID);
final Phase src;
final Phase dst;
Transition(Phase src, Phase dst) {
this.src = src;
this.dst = dst;
}
// Initialize the phase transition map
private static final Map<Phase, Map<Phase,Transition>> m =
new EnumMap<Phase, Map<Phase,Transition>>(Phase.class);
static {
for (Phase p : Phase.values())
m.put(p,new EnumMap<Phase,Transition>(Phase.class));
for (Transition trans : Transition.values())
m.get(trans.src).put(trans.dst, trans);
}
public static Transition from(Phase src, Phase dst) {
return m.get(src).get(dst);
}
}
}

You can encapsulate DIRECTION and TYPE in a concrete class(say EnumGroup) . And create a Hashmap that contains key as the object of EnumGroup and value as the value of enum State. In this way we could save the state value for multiple combination of DIRECTION and STATE value . We can also have two different EnumGroup having same state value. Here is the code Demo.
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
class EnumGroup
{
Direction direction;
Type type;
private EnumGroup(){}//To prevent parmeterless construction
public EnumGroup(Direction direction , Type type)
{
if (direction==null || type == null)
{
throw new IllegalStateException("null is not allowed");
}
this.direction = direction;
this.type = type;
}
#Override
public int hashCode()
{
return direction.toString().hashCode() + type.toString().hashCode() ;
}
#Override
public boolean equals(final Object other)
{
if (other == null || !(other instanceof EnumGroup))
{
return false;
}
if (this == other)
{
return true;
}
EnumGroup temp = (EnumGroup)other;
if (temp.type == this.type && temp.direction == this.direction)
{
return true;
}
return false;
}
}
enum Direction
{
LEFT,RIGHT,DOWN,UP,ACCROSS;
}
enum Type
{
BIG,SMALL,MEDIUM;
}
enum State
{
ONE_STATE,FIRST_STATE,SECOND_STATE,THIRD_STATE;
private static final Map<EnumGroup,State> map = new HashMap<EnumGroup,State>();
static
{
map.put(new EnumGroup(Direction.LEFT,Type.BIG),ONE_STATE);
map.put(new EnumGroup(Direction.RIGHT,Type.SMALL),SECOND_STATE);
map.put(new EnumGroup(Direction.UP,Type.SMALL),FIRST_STATE);
/*
.
.
.
*/
}
public static State getState(EnumGroup eGroup)
{
State state = map.get(eGroup);
return state == null ? THIRD_STATE : state;
}
}
public class EnumValueByArgument
{
public static void main(String st[])
{
ArrayList<EnumGroup> list = new ArrayList<EnumGroup>();
for (Direction direction : Direction.values())
{
for (Type type : Type.values() )
{
list.add(new EnumGroup(direction,type));
}
}
for (EnumGroup eGroup : list )
{
System.out.println(State.getState(eGroup));
}
}
}

Related

How to add some special values to an integer type

I would like to create a Java class that besides having integer types allows to have also some Enums, that is special values, a bit like Double.
Consider the case where you want to memorize an integer 0,1,100, 1000 or a special value like "0000" or "/" or "VAR";
I suppose your class has to contain those types? as in :
public class ExampleClass
{
// Instance Variables
int intTypeVar;
String stringTypeVar;
double doubleTypeVar;
// Constructor Declaration of Class
public ExampleClass (int intTypeVar, String stringTypeVar,
double doubleTypeVar)
{
this.intTypeVar= intTypeVar;
this.stringTypeVar= stringTypeVar;
this.doubleTypeVar= doubleTypeVar;
}
You can make your own exclusive type like this:
public class State {
JUST_AN_INTEGER,
CHEESE,
SOMETHING_ELSE;
}
public final class MyInteger {
private final int value;
private final State state;
private MyInteger(int value) {
this.value = value;
this.state = State.JUST_AN_INTEGER;
}
private MyInteger(State state) {
if (state == null) {
throw new IllegalArgumentException("State must be non-null");
} else if (state == State.JUST_AN_INTEGER) {
throw new IllegalArgumentException(State.JUST_AN_INTEGER + " requires a value!");
}
this.state = state;
}
public int getValue() {
if (state != State.JUST_AN_INTEGER) {
throw new IllegalStateException("MyValue has no value, it is of state " + state");
}
return value;
}
public int getState() {
return this.state;
}
#Override
public int hashCode() {
return this.value ^ this.state.hashCode();
}
#Override
public int equals(Object o) {
if (!(o instanceof MyInteger)) {
return false;
}
MyInteger other = (MyInteger) o;
return other.state == this.state && other.value == this.value;
}
#Override
public String toString() {
if (this.state == State.JUST_AN_INTEGER) {
return String.valueOf(this.value);
}
return this.state.name();
}
}
This MyInteger can either have a normal integer value or be of one of the other states. The constructors ensure that it's only ever constructed in a consistent way (for example you wouldn't want a JUST_AN_INTEGER constructed without an explicit value and equally you wouldn't want a CHEESE state to also contain a value).
You could also implement the Number class, but that would lead to all kinds of confusing behaviour, since it doesn't act like a normal Number in many cases.

Design pattern to create an arraylist for a combination of object and value pair [duplicate]

This question already has answers here:
A Java collection of value pairs? (tuples?)
(22 answers)
Closed 6 years ago.
Wanted to know inputs for possible design pattern approach in java:
Scenario: Trying to create an arraylist for a combination of object and value pair.
If Objects has A, B, C...etc
If value has X1, X2, X3...etc
there could be an arraylist of Y1 for a combination of A & X1
there could be an arraylist of Y2 for a combination of A & X2
..... etc, so on and so forth.
I tried with Factory Creational Design Pattern, however did not match quite good.Can anyone suggest a possible design approach for this issue ?
I cannot use Apache Pair in my implementation. ok I have added my problem Java class code:
import java.util.ArrayList;
import java.util.List;
public class FieldsProvider2 {
private MyObject object;
private MyAction action;
public FieldsProvider2(MyObject object, MyAction action) {
this.object = object;
this.action = action;
}
public List<Object> getList() {
if ((action != null && object != null)) {
if (Action.A == action) {
List<Object> fields = new ArrayList<>();
if (object.getTypeKey().equals(MYObject.X1)) {
// fields.add(Y1);
// fields.add(Y2);
// fields.add(Y3);
// fields.add(Y4);
// fields.add(Y5);
// fields.add(Y5);
// fields.add(Y6);
// fields.add(Y7);
return fields;
}
if (object.getTypeKey().equals(MYObject.X2)) {
// nothing
}
if (object.getTypeKey().equals(MYObject.X3)) {
// fields.add(Y1);
}
if (object.getTypeKey().equals(MYObject.X4)) {
// fields.add(Y1);
// fields.add(Y8);
// fields.add(Y9);
}
if (object.getTypeKey().equals(MYObject.X5)) {
// fields.add(Y1);
}
if (object.getTypeKey().equals(MYObject.X6)) {
// fields.add(Y1);
}
if (object.getTypeKey().equals(MYObject.X7)) {
// fields.add(Y1);
}
if (object.getTypeKey().equals(MYObject.X8)) {
// fields.add(Y1);
}
if (object.getTypeKey().equals(MYObject.X9)) {
// fields.add(Y9);
}
if (object.getTypeKey().equals(MYObject.X10)) {
// fields.add(Y10);
}
// Common items
// fields.add(Y11);
// fields.add(Y12);
// fields.add(Y13);
// fields.add(Y14);
// or
// fields.add(Y15);
return fields;
}
if (Action.B == action) {
List<Object> fields = new ArrayList<>();
if (object.getTypeKey().equals(MYObject.X1)) {
// fields.add(Y1);
// fields.add(Y2);
// fields.add(Y3);
// fields.add(Y4);
// fields.add(Y5);
// fields.add(Y5);
// fields.add(Y6);
// fields.add(Y7);
return fields;
}
if (object.getTypeKey().equals(MYObject.X2)) {
// fields.add(Y7);
}
}
//Action.C will start
//Action.D will start and so on...
return null;
}
}
If I get that right you have a structure like that:
Map<Pair<A,X>, List<Y>>
There is no design pattern for filling this Map, but there are some important things to consider.
If you use a Pair as key, you must overwrite hashcode() and equals() methods in Pair to make the Map work correctly. Additionaly you should provide an constructor in Pair to create a key for searches etc. easily in one step.
If you are using Java8 you can use streams/lambdas for filtering/searching.
In my project I implement my own Pair class, similar as Scala does.
Here the code base
import java.util.Objects;
public class Pair<A, B> {
public final A _1;
public final B _2;
private Pair(A _1, B b) {
this._1 = _1;
this._2 = b;
}
public A _1() {
return _1;
}
public B _2() {
return _2;
}
#Override
public String toString() {
return "(" + _1 + "," + _2 + ")";
}
public static <X, Y> Pair<X, Y> of(X a, Y b) {
return new Pair<>(a, b);
}
public static <X, Y> Pair<X, Y> pair(X a, Y b) {
return of(a, b);
}
public boolean equals(Object var1) {
return var1 instanceof Pair && Objects.equals(this._1, ((Pair) var1)._1) && Objects.equals(this._2, ((Pair) var1)._2);
}
public int hashCode() {
return this._1 == null ? (this._2 == null ? 0 : this._2.hashCode() + 1) : (this._2 == null ? this._1.hashCode() + 2 : this._1.hashCode() * 17 + this
._2.hashCode());
}
}

How can I return the right data type of a instance when this instance might have different data type?

I have this code in Modula-2,
PROCEDURE Prune(typeExp: TypeExp): TypeExp;
BEGIN
CASE typeExp.^class OF
| VarType:
IF typeExp^.instance = NIL THEN
RETURN typeExp;
ELSE
typeExp^.instance = Prune(typeExp^.instance);
RETURN typeExp^.instance;
END;
| OperType: RETURN typeExp;
END;
END Prune;
I have several problems when I try to convert this code into java. I can create an instance and judge if its instance is null and then choose what to return. But I don't really know what to do with the case 2, which is the instance might be a new Opentype(); because only one value can be returned in this case.
public TypeExp Prune(TypeExp typeExp){
TypeExp r = new VarType();
if (r.instance == null) {
return r;
}
else {
r.instance = Prune(r.instance);
return r.instance;
}
}
The second issue is I don't think I can call the function Prune() inside itself, so what can I do? Thanks in advance.
I dont really know Modula-2, but it might be something like this:
public TypeExp Prune(TypeExp typeExp) {
if (typeExp instanceof VarType) {
if (typeExp.instance == null) {
return typeExp;
}
else {
typeExp.instance = Prune(typeExp.instance);
return typeExp.instance;
}
} else if (typeExp instanceof OperType) {
return typeExp;
}
//if typeExp is not an instance of VarType or OperType
return null;
}
The Modula code does not return in all code paths. Thats not possible in Java. I inserted return null in those cases. Thats probably wrong for your application though.
Below example not same as your func, but I think you can modify to your needs. It hides your return types behind Type class => you can return objects of two classes.
Main
package com.type;
public class Main {
public static void main(String[] args) {
Type first = new FirstType();
Type second = new SecondType();
System.out.println(func(first).getTypeName());
System.out.println(func(first).getTypeName());
System.out.println(func(second).getTypeName());
}
public static Type func(Type type) {
if(type instanceof FirstType) {
type.setTypeName("First");
} else {
type.setTypeName("Second");
// something here
}
return type;
}
}
Type
package com.type;
public class Type {
private String typeName;
public Type() {}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
}
FirstType
package com.type;
public class FirstType extends Type {
}
SecondType
package com.type;
public class SecondType extends Type {
}

Is it possible to initialize a generic variable with a specific-typed value?

I have a class that I want to be instantiated with either a String or int value, and I define the corresponding instance variable value as generic type T:
public class MathValue<T extends Object> {
private boolean isOperand, isOperator;
// a generic-typed instance variable:
private T value;
// constructor:
public MathValue(int operand) {
// compile-error -- "Incompatible types: required T, found Integer"
this.value = new Integer(operand);
this.isOperand = true;
this.isOperator = false;
}
// constructor:
public MathValue(String operator) {
// compile-error -- "Incompatible types: required T, found String"
this.value = operand;
this.isOperand = false;
this.isOperator = true;
}
}
I could very well have a single constructor instead, with a formal parameter of type T, but I want to enforce the class' instantiation with a String or int argument:
public class MathValue<T extends Object> {
private boolean isOperand, isOperator;
// a generic-typed instance variable:
private T value;
// it totally works, but does not enforce specific-typed instantiation:
public MathValue(T operandOrOperator) {
this.value = operandOrOperator;
if (operandOrOperator instanceof Integer) {
this.isOperand = true;
this.isOperator = false;
} else if (operandOrOperator instanceof String) {
this.isOperand = false;
this.isOperator = true;
}
}
}
So despite the logical error of wanting to make a generic-typed class "not so generic", is it possible to instantiate a generic variable with a specific-typed value?
You could create factory methods. Here's now it might look:
public class MathValue<T extends Object> {
public static MathValue<String> from(String s) {
MathValue<String> mv = new MathValue<String>();
mv.setValue(s);
mv.setIsOperand(true);
return mv;
}
public static MathValue<Integer> from(Integer s) {
MathValue<Integer> mv = new MathValue<Integer>();
mv.setValue(i);
mv.setIsOperand(false);
return mv;
}
// Rest of your class below
}
If you absolutely need a constructor (eg, you don't know the type that you're creating for ahead of time), then I can't see a way around #RohitJain 's suggestion.
You could use sub-classes. Define an abstract class to actually store the value, generically:
abstract class MathValue<T> {
private final T value;
MathValue(T value) {
this.value = value;
}
abstract boolean isOperator();
boolean isOperand() {
return !isOperator();
}
}
Then one subclass that enforces the value type to be an integer.
class OperandValue extends MathValue<Integer> {
OperandValue(int operand) {
super(new Integer(operand));
}
#Override
public boolean isOperator() {
return false;
}
}
and another subtype that enforces it to be a String.
class OperatorValue extends MathValue<String> {
OperatorValue(String operator) {
super(operator);
}
#Override
boolean isOperator() {
return true;
}
}
With this design, you don't actually need to store the Booleans.
(Note, for simplicity I left out the visibility keywords.)

Switch according to input and return dynamic value

In this method I get string as input and according to the string name I need to return value sometimes its string sometime int ,double,int64 ,bool etc
Since its dynamic type i don't know how to define it in the method return type
and how to add to it the value and how to call to this method that the return type is dynamic ,any idea?
public static ? SwitchInput(String TypeName) {
if (TypeName == "java.lang.String" ) {
Return = "A";
}
else if (TypeName == "int" ) {
Return = 1;
}
else if (TypeName == "double") {
Return = 1.00
}
etc for bool and all the other types
}
Object will be your best bet, unless returned type shares an Ancestor
Example :
public static Object switchInput(String typeName) {
if ("java.lang.String".equals(typeName)) {
return "A";
}
else if ("int".equals(typeName)) {
return 1i;
}
else if ("double".equals(typeName)) {
return 1.0d
}
}
Another example with generics
static <T> T switchInput(String typeName){
if ("java.lang.String".equals(typeName)) {
return "A";
}
else if ("int".equals(typeName)) {
return 1i;
}
else if ("double".equals(typeName)) {
return 1.0d
}
}
String str = MyClass.switchInput("java.lang.String")
I have not tested that, this is a simpler version of my first thought about generics
To know what the return type is, you have to find a container where all these types fit in. Obviously, this is Object. You'd have to convert the primitive types to the corresponding object (like int to Integer).
A better approach would be to create a new container class, which holds a generic type <T>. Like
public class SwitchDemo {
public static SwitchInputType<?> switchInput(String typeName) {
if (typeName.equals("java.lang.String")) {
return new SwitchInputType<String>(new String("A"));
} else if (typeName.equals("int")) {
return new SwitchInputType<Integer>(new Integer(312));
}
return null;
}
public static class SwitchInputType<T> {
private T type;
public SwitchInputType(T type) {
super();
this.type = type;
}
public T getType() {
return type;
}
public void setType(T type) {
this.type = type;
}
}
public static void main(String[] args) {
SwitchInputType<?> sit1 = SwitchDemo.switchInput("java.lang.String");
System.out.println(sit1.getType());
SwitchInputType<?> sit2 = SwitchDemo.switchInput("int");
System.out.println(sit2.getType());
}
}
As an ugly solution to your problem, you could set your method to run the type Object. (as Boolean, Integer, Double are all subtypes)
You would have to ensure though that you then inferred the correct type afterwards when using the returned value (using instanceof) and recast it to the correct type.
Can I ask though why you need such a method? This is abusing the notion of a method definition slightly.
public static Object SwitchInput(String TypeName) {
if (TypeName.equals("java.lang.String") ) {
Return = new String("A");
}
else if (TypeName.equals("int") ) {
Return = new Integer(1);
}
else if (TypeName.equals("double")) {
Return = new Double(1.00) ;
}
etc for bool and all the other types
}
And using this code snippet to infer what type it is further on down in your code
if(returned_value instanceof Double)
etc.

Categories