Using enums to avoid using switch/if

A

aks_java

Hi, I want to avoid using if cases or switch in the following piece of
code:
package calculator;

public class Operations {

public double calculateResult() {
double totalVal = Calculator.calculator.prevValue;
double val2 = Double.parseDouble
(Calculator.calculator.displayField.getText());

if (Calculator.calculator.operatorUsed.equals("+")) {
totalVal += val2;
}
if (Calculator.calculator.operatorUsed.equals("-")) {
totalVal -= val2;
}
if (Calculator.calculator.operatorUsed.equals("/")) {
totalVal /= val2;
}
if (Calculator.calculator.operatorUsed.equals("*")) {
totalVal *= val2;
}
if (Calculator.calculator.operatorUsed.equals("=")) {
totalVal = val2;
}
return totalVal;
}
}

I read in a java tutorial that you can use enums to get rid of this :

public enum Operation {

PLUS {

double eval(double x, double y) {
return x + y;
}
},
MINUS {

double eval(double x, double y) {
return x - y;
}
},
TIMES {

double eval(double x, double y) {
return x * y;
}
},
DIVIDE {

double eval(double x, double y) {
return x / y;
}
};

abstract double eval(double x, double y);
}

But here's my problem: In my program I've strings ("+" , "-", "/", "="
etc) instead of enums. I need a mechanism to map string to enum.
 
L

Lew

aks_java said:
public enum Operation {
PLUS {

Please consider using narrower indentation, four spaces per level or less.
double eval(double x, double y) {
return x + y;
}
},
MINUS {
double eval(double x, double y) {
return x - y;
}
},
TIMES {
double eval(double x, double y) {
return x * y;
}
},
DIVIDE {
double eval(double x, double y) {
return x / y;
}
};

abstract double eval(double x, double y);
}

But here's my problem: In my program I've strings ("+" , "-", "/", "="
etc) instead of enums. I need a mechanism to map string to enum.

public enum Operation
{
PLUS( "+" )
{
double eval(double x, double y)
{
return x + y;
}
},

MINUS( "-" )
{
double eval(double x, double y)
{
return x - y;
}
},

TIMES( "*" )
{
double eval(double x, double y)
{
return x * y;
}
},

DIVIDE( "/" )
{
double eval(double x, double y)
{
return x / y;
}
};

private final String sym;
Operation( String sym )
{
this.sym = sym;
}

abstract double eval(double x, double y);

@Override public String toString()
{
return this.sym;
}

public static Operation fromString( String nym )
{
if ( nym == null )
{
return null;
}
for ( Operation op : Operation.values() )
{
if ( nym.equals( op.sym ))
{
return op;
}
}
return null;
}
}
 
L

Lew

aks_java said:
public enum Operation {
PLUS {
double eval(double x, double y) {
return x + y;
}
}, ....
abstract double eval(double x, double y);

The 'eval()' method most likely should be 'public'.
 
P

Philipp

You could also take the look-up approach (see below). This is also
possible with enums as Lew proposed them, using a Map instead of the
linear search in the fromString() method.
HTH Phil



import java.util.HashMap;
import java.util.Map;

public class ATest {

static interface Operator{
public double eval(double a, double b);
}

static class Add implements Operator{
@Override
public double eval(double a, double b) {
return a + b;
}
}

private static Map<String, Operator> operators = new HashMap<String,
Operator>();
static{
operators.put("+", new Add());
// etc
}

public static void main(String[] args) {
double a = 12.3;
double b = 23.4;
String opStr = "+";
// instead of if/else
Operator op = operators.get(opStr);
// should probably check for null
double result = op.eval(a, b);
System.out.println("Result is " + result);
}
}
 
W

Wojtek

Lew wrote :
Please consider using narrower indentation, four spaces per level or less.


public enum Operation
{
PLUS( "+" )
{
double eval(double x, double y)
{
return x + y;
}
},

MINUS( "-" )
{
double eval(double x, double y)
{
return x - y;
}
},

TIMES( "*" )
{
double eval(double x, double y)
{
return x * y;
}
},

DIVIDE( "/" )
{
double eval(double x, double y)
{
return x / y;
}
};

private final String sym;
Operation( String sym )
{
this.sym = sym;
}

abstract double eval(double x, double y);

@Override public String toString()
{
return this.sym;
}

public static Operation fromString( String nym )
{
if ( nym == null )
{
return null;
}
for ( Operation op : Operation.values() )
{
if ( nym.equals( op.sym ))
{
return op;
}
}
return null;
}
}

Don't return null. Throw an exception instead.
 
L

Lew

Philipp said:
You could also take the look-up approach (see below). This is also
possible with enums as Lew proposed them, using a Map instead of the
linear search in the fromString() method.
...
import java.util.HashMap;
import java.util.Map;

public class ATest {

static interface Operator{
public double eval(double a, double b);
}

static class Add implements Operator{
@Override
public double eval(double a, double b) {
return a + b;
}
}

private static Map<String, Operator> operators = new HashMap<String,
Operator>();
static{
operators.put("+", new Add());
// etc
}

This differs from the given enum approach by not declaring the nested classes
as extensions of the outer (enum) class and by permitting future operations to
be retrofitted.

This points up the interesting design question of when an enum is better
versus another kind of class.
 
R

Roedy Green

But here's my problem: In my program I've strings ("+" , "-", "/", "="
etc) instead of enums. I need a mechanism to map string to enum.

see http://mindprod.com/jgloss/enum.html

It will tell you how to go String -> enum, enum->String, enum ->
ordinal, ordinal -> enumu etc. and how to have aliases.

--
Roedy Green Canadian Mind Products
http://mindprod.com

Never discourage anyone... who continually makes progress, no matter how slow.
~ Plato 428 BC died: 348 BC at age: 80
 
G

Giovanni Azua

Hi Lew,

Lew said:
This points up the interesting design question of when an enum is better
versus another kind of class.
enum are quite a constrained type, you are only allowed to implement
interfaces but not to extend existing classes nor let other classes extend
from enums.

I bumped into this limitation recently while trying to implement a
componentized State Pattern. Ideally, static references to the different
States would be done via an enum type. This enum would function as an
Abstract Factory that would expose the stateless Enum instances to the
Context and to other States for use-cases like e.g. state transition.

The limitation of using Enums in this case would be compromised reusability
and extendibility i.e. the concrete Abstract Factory being an enum:

1-. Can not extend a base reusable AbstractStateFactory
2-. Can not be extended to:
a) Redefine State instances (extending and overriding existing States)
b) Introduce new States

In conclusion, even when enum types would be a very strong match for a
design, these limitations would defeat using it.

The clients of this implementation would have two choices:

1) Sealed choice: Create an enum type that makes all State instances
statically available to the Context and other State instances.

2) Extendible choice: Create a proper Abstract Factory that extends the
reusable AbstractStateFactory (that offers support for e.g. partial-states)
and can also be extended to redefine State instances or even introduce new
ones.

As example, I modeled the lifecycle of a FX LimitOrder:

<http://perfectjpattern.svn.sourcefo...esources/images/state_example.png?view=markup>

<http://perfectjpattern.svn.sourcefo...ore/behavioral/state/Example.java?view=markup>

<http://perfectjpattern.svn.sourcefo...ate/FXLimitOrderStateFactory.java?view=markup>

Best regards,
Giovanni
 
L

Lew

Mark said:
I had exactly the same problem with a little test program I wrote to
suss out Item 34 of Effective Java, "Emulate extensible enums with
interfaces."

In a larger sense, EJ's advice is part of a larger concept of type-
based programming. Since enums can implement interfaces it's possible
to make enums appear to be of a particular type. This could be useful
in certain circumstances.

However:
The facts that you cannot derive new classes from existing enum classes,
and the inability to derive from a common abstract base class, are just
too limiting in almost every circumstance.  If the enum refers to some
value that could change or need to be extended later, it's better to not
use an enum.

This is the point - enums are not the class for every season. They
have a particular use case for which they are extremely well suited.
That is a fairly large use case; even with the restrictions, that an
enum is a full-fledged class in its own right gives it tremendous
power and flexibility. For use cases that fall outside that range,
well, you just have to use a different kind of class. You could, for
example, write a type-safe enumeration like Josh Bloch recommended in
the first edition of EJ. You can't use it in a 'switch', but in other
respects you can make it as much like an enum as you need, and you can
make it heritable if you want. Beware of the oddities inherent in
using static members of a class from its subclasses.
 
L

Lew

Mark said:
I had exactly the same problem with a little test program I wrote to
suss out Item 34 of Effective Java, "Emulate extensible enums with
interfaces."

The facts that you cannot derive new classes from existing enum classes,
and the inability to derive from a common abstract base class, are just
too limiting in almost every circumstance. If the enum refers to some

About which the cited chapter suggests, "[f]or the most part, extensibility of
enums turns out to be a bad idea."

That said, the example given of where it's a good idea is the OP's very
problem. His solution is to use multiple enums that implement an interface in
different ways. I wonder what issues you encountered with that approach.
 
M

Mark Space

Lew said:
That said, the example given of where it's a good idea is the OP's very
problem. His solution is to use multiple enums that implement an
interface in different ways. I wonder what issues you encountered with
that approach.


To be honest, it was long enough ago that I've forgotten the details.
But I do recall that the inability to make a sub-class of the existing
enum classes was a big deal. Yes, enums were the wrong pattern for that
problem, even with interfaces.

I'm sure there's some uses for enums, especially where they're just kept
simple. Nothing wrong in concept with an enumerated type. But try to
fancy them up too much and they loose their enum-ess. That's where I
think one needs to make the shift from enums to a class made especially
for the problem domain. The exact point where an enum must be converted
to a different type is hard to define. It's just something to be aware
of and to watch for when using enums.
 
K

Karl Uppiano

Philipp said:
You could also take the look-up approach (see below). This is also
possible with enums as Lew proposed them, using a Map instead of the
linear search in the fromString() method.
HTH Phil



import java.util.HashMap;
import java.util.Map;

public class ATest {

static interface Operator{
public double eval(double a, double b);
}

static class Add implements Operator{
@Override
public double eval(double a, double b) {
return a + b;
}
}

private static Map<String, Operator> operators = new HashMap<String,
Operator>();
static{
operators.put("+", new Add());
// etc
}

public static void main(String[] args) {
double a = 12.3;
double b = 23.4;
String opStr = "+";
// instead of if/else
Operator op = operators.get(opStr);
// should probably check for null
double result = op.eval(a, b);
System.out.println("Result is " + result);
}
}

Or you can use the valueOf method built into enums, to return the enum,
given the name that was used to define the enum. It effectively implements
the mapping for you.

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Enum.html#valueOf(java.lang.Class,
java.lang.String)

An example is given towards the bottom of this article:
http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html
 
M

Mayeul

Wojtek said:
Lew wrote :

Don't return null. Throw an exception instead.

Shouldn't that depend on how you plan to use it? Programming by
exceptions isn't the wisest move either.
 
A

aks_java

The problem here is that you can't use switch statements with strings.
So you are obliged to use if cases which is considered a bad
programming practice. My professor has asked me to get rid of such if
cases but in some places it doesn't make sense because all it does is
bloat the code even more. So what is your suggestion ?
 
M

Mayeul

aks_java said:
The problem here is that you can't use switch statements with strings.
So you are obliged to use if cases which is considered a bad
programming practice. My professor has asked me to get rid of such if
cases but in some places it doesn't make sense because all it does is
bloat the code even more. So what is your suggestion ?

If you ask me, switch statements are little more than glorified if
ladders, with the additional hassle that you might forget some 'break'
statements.
In appropriate OO design, you should need neither.

You might have noticed that in the example code that was suggested to
you, there is only one 'if' statement trying to identify the operator.
This 'if' is inside a while loop that loops over all operators defined
in the enum. This is way less verbose nor error-prone than a switch, or
than if ladders.
 
L

Lew

Shouldn't that depend on how you plan to use it?

APIs are not written by how the client plans to use it, but by how the
API writer intends the client to use it.

Throwing a run-time exception is a perfectly valid option. It
represents programmer error in the client.
Programming by exceptions isn't the wisest move either.

Programming without exceptions isn't the wisest move. What he
suggested isn't "programming by exceptions", it's programming with
exceptions. Just what do you think exceptions are for, anyway?

Throwing an exception for an illegal argument is standard and
perfectly good practice.
 
L

Lew

The problem here is that you can't use switch statements with strings.
So you are obliged to use if cases which is considered a bad
programming practice. My professor has asked me to get rid of such if
cases but in some places it doesn't make sense because all it does is
bloat the code even more. So what is your suggestion ?

public enum Operation { ... as above ... }

public class Client
{
public void foo()
{
...
Operation op = obtainOp();
switch ( op )
{
case PLUS:
// ...
break;
case MINUS:
// etc.
break;
}
...
}
...
}

OR:

public class Client
{
public void foo()
{
...
Operation op = obtainOp();
op.operate( x, y ); // polymorphism - very O-O
...
}
...
}
 
L

Lew

Mayeul said:
If you ask me, switch statements are little more than glorified if
ladders, with the additional hassle that you might forget some 'break'
statements.

And for-each loops are little more than glorified for() loops with the
additional hassle that you might forget that you needed an index.
Generics are little more than glorified Objects with the additional
hassle that you need to actually understand the type model of your
code. Assertions are little more than glorified if statements with
the additional hassle that you might forget and leave them on in
production. Methods are little more than glorified goto statements
with the additional hassle that you have to match up by type all the
arguments. If statements are little more than glorified gotos with
the additional hassle that you have to remember your braces or
mismatch your 'else' clauses. Object-oriented programming is little
more than glorified assembly-language programming with the additional
hassle that you have to understand the model for your application.
 
W

Wojtek

Mayeul wrote :
Shouldn't that depend on how you plan to use it? Programming by exceptions
isn't the wisest move either.

By passing back a bad value as a flag, each method up the chain must
test for that bad value until you reach a point where the bad value can
be handled.

A thrown exception bypasses this set of operations.

In the OP code, it may well be that the kickoff for the calculation was
based on user input. Notifying the user should occur in the UI portion
of the application and no intermidiate layer really needs to know about
(be responsible for) bad input, or have to have special code to handle
bad input.

So you may call it "programming by exception" whereas I call it
"responsibility point".

And if for some reason an intermediate layer does need to do something
(close a connection), then it can catch the exception, do its cleanup
work, then re-throw the same exception (or package it into another
exception).
 
J

John B. Matthews

aks_java said:
The problem here is that you can't use switch statements with
strings. So you are obliged to use if cases which is considered a bad
programming practice. My professor has asked me to get rid of such if
cases but in some places it doesn't make sense because all it does is
bloat the code even more. So what is your suggestion?

I like a recursive descent parser for this kind of problem [1]. Each
token for a terminal symbol in the grammar is singular and immutable,
so a Symbol enum seems natural [2]. Given a simple LL(1) grammar,
one-symbol lookahead is sufficient; but you still need a branch for
each choice in the grammar, symbolized by a vertical bar, "|".

Your grammar is very simple, requiring only choices between two
additive operators and two multiplicative operators. Each pair could be
factored into its own enum, but you might ask your professor if that's
essential to the assignment's goal.

Adding a new Symbol necessarily means changing the grammar. As this
implies changing the code, the limitations on extensibility of enum
discussed in this thread may apply.

[1]<http://en.wikipedia.org/wiki/Recursive_descent_parser>
[2]<http://sites.google.com/site/drjohnbmatthews/enumerated-functions>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top