1

I want to convert some String to an operator like this:

int value = 1;
int valueToCompare = 3;
String operation = "<";

if (value operation valueToCompare) {
    // some operation       
}

How do I convert a variable operation into an operator?

Harmlezz
  • 7,524
  • 23
  • 34
Prasad V S
  • 262
  • 3
  • 15

9 Answers9

3

you may try this:

import java.util.*;

interface Operator {
  boolean compare(int a, int b);
}

class Launch
{
    public static void main (String[] args) throws java.lang.Exception
    {
        Map<String, Operator> opMap = new HashMap<String, Operator>();
        opMap.put(">", new Operator() {
            @Override public boolean compare(int a, int b) {
                return a > b;
            }
        });
        opMap.put("<", new Operator() {
            @Override public boolean compare(int a, int b) {
                return a < b;
            }
        });
        opMap.put("==", new Operator() {
            @Override public boolean compare(int a, int b) {
                return a == b;
            }
        });
        String op = ">";
        int i = 4, j = 5;
        boolean test = opMap.get(op).compare(i, j);
        System.out.printf("test: %b, i: %d, op: %s, j: %d\n", test, i, op, j);
            //prints: test: false, i: 4, op: >, j: 5
    }
}
2

Sounds like you need a switch based around a string (for Java 7 and above - otherwise simple use if/else), and a set of Comparator objects e.g.

switch (operation) {
   case ">" : return new GreaterThanComparator();

or

if (operation.equals(">")) {
   return new GreaterThanComparator();
}

where GreaterThanComparator implements the Comparator interface. The class you've created implements your comparison functionality and could do a lot more besides. It's the closest Java has to the encapsulation of a function.

Note that the Comparator above can be used directly in Java collections in order to perform sorting etc.

You could use lookup tables (e.g. a Map of String/Comparators) or similar if you have a lot of these comparisons to make. I think the important part of the above is the encapsulation of the behaviour via the Comparator object.

An alternative is to use the scripting engine built into Java and parse (say) Javascript statements. That's perhaps more work, but certainly a more extensible solution. Note that you're not limited to Javascript, and a number of scripting languages exist, including Beanshell, Jython etc.

Brian Agnew
  • 254,044
  • 36
  • 316
  • 423
  • 2
    Yes this solution works, but it is not `OO`. It teaches procedural programming in my opinion. – Harmlezz May 06 '14 at 11:20
  • 1
    I should point out that OO is a technique and not an end in itself. If you have a set of strings and want to map these to behaviour, at some stage you're going to have to perform some lookup via if/else, switch/case, tables etc. I note you have precisely the same set of lookups in your solution below, but encoded via a set of enums. – Brian Agnew May 06 '14 at 11:22
  • In fact (rereading) I'd suggest it's closer to teaching *functional* programming. Regardless, it's another technique/tool available for use amongst many, with various pros/cons – Brian Agnew May 06 '14 at 11:31
  • 1
    In my opinion a `switch` or huge `if-else` statement is always a candidate to rethink the approach and to consider a polymorphic solution. It is not always a must, but worth to re-evaluate the current solution. I can't see anything functional characteristics in `if-else` and `switch` statements. But this is an off-topic discussion and has nothing to do with the question asked. – Harmlezz May 06 '14 at 11:37
  • That's not the functional bit. The functional bit is returning the stateless object implementing one method (the Comparator) – Brian Agnew May 06 '14 at 11:39
  • You mean like a closure? Your approach does construct a new instance every time. This will burden the garbage-collector more often then necessary I guess, right? – Harmlezz May 06 '14 at 11:41
2

Your approach will never work in Java. Instead you may define your own enum which perform the proper boolean operation like this:

public static void main(String[] args) {
    boolean result = Operator.parseOperator("==").apply(2, 2);
}

enum Operator {

    LESS("<") {
        @Override public boolean apply(int left, int right) {
            return left < right;
        }
    },
    EQUAL("==") {
        @Override public boolean apply(int left, int right) {
            return left == right;
        }
    };

    private final String operator;

    private Operator(String operator) {
        this.operator = operator;
    }

    public static Operator parseOperator(String operator) {
        for (Operator op : values()) {
            if (op.operator.equals(operator)) return op;
        }
        throw new NoSuchElementException(String.format("Unknown operator [%s]", operator));
    }

    public abstract boolean apply(int left, int right);
}
Harmlezz
  • 7,524
  • 23
  • 34
1

Create a custom method which does it for you..

Something like this

private static boolean parseExpression(int number1, String operator, int number2)
{
    if ("<".equals(operator)) {
        return number1 < number2;
    } else if (">".equals(operator)) {
        return number1 > number2;
    } else if ("<=".equals(operator)) {
        return number1 <= number2;
    } else if (">=".equals(operator)) {
        return number1 >= number2;
    } else if ("==".equals(operator)) {
        return number1 == number2;
    } else { 
        throw new IllegalArgumentException("Invalid operator");
    }
}

private static boolean parseExpression(double number1, String operator, double number2)
{
    if ("<".equals(operator)) {
        return Double.compare(number1, number2) == -1;
    } else if (">".equals(operator)) {
        return Double.compare(number1, number2) == 1;
    } else if ("<=".equals(operator)) {
        return Double.compare(number1, number2) <= 0;
    } else if (">=".equals(operator)) {
        return Double.compare(number1, number2) >= 0;
    } else if ("==".equals(operator)) {
        return Double.compare(number1, number2) == 0;
    } else if ("!=".equals(operator)) {
        return Double.compare(number1, number2) != 0;
    } else { 
        throw new IllegalArgumentException("Invalid operator");
    }
}

If you don't want to use a comparator, it's something "simple" but should work. For double/floats should do a bit more of work anyway


P.S with Enums you could do something very elegant. With Java7 you can use switch-strings too.

Marco Acierno
  • 13,987
  • 7
  • 40
  • 53
0

The simplest way would be a chain of if-else statements checking what the the operator is and then performing the mathematical expression.

Marc Deleuran
  • 324
  • 2
  • 6
0

You can use ScriptEngine for that, works for any other JavaScript expressions also :

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");


int value = 1;
int valueToCompare = 3;
String operation = "<";

if ((Boolean)engine.eval("" + value + operation + valueToCompare)) {
    System.out.println("Here we are.");  
}
Danstahr
  • 3,902
  • 17
  • 34
0

You could try using a switch statement:

switch(operation) {
    case "<" : //code here
        break;
    case ">" : //code here
        break;
    case "==" : //code here
        break;
}
renz
  • 996
  • 3
  • 9
  • 21
0

It is not directly possible, you'll have to write some code. One possibility is using enums:

enum Operation {
    LESS_THAN("<") {
        @Override int compare(int o1, int o2) {
            return o1 - o2;
        }
    },
    ...;

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

    private static final Map<Operation, String> MAP = new HashedMap<Operation, String>();
    static {
        for (final Operation op: values()) MAP.put(op.operator, op);
    }

    public static Operation valueOf(final String op) {
        return MAP.get(op);
    }
}

Usage example:

int cmp = Operation.valueOf(operation).compare(value, valueToCompare);
cadrian
  • 7,095
  • 2
  • 30
  • 41
0

Answer

For completeness¸I would like to add that there already exists a lot of code for this. I know you asked a very specific question, but the general answer would be to look at existing solutions how that is done.

Example:

Built-in method for evaluating math expressions in Java

Community
  • 1
  • 1
Lennart Rolland
  • 7,561
  • 6
  • 47
  • 80