Home > other >  How to create a variable that contains an Operator in Java?
How to create a variable that contains an Operator in Java?

Time:04-08

I'm trying to write a program in 30 lines or less for my class (self imposed challenge).

The program asks the user a simple addition, division, multiplication, or subtraction question and the player answers, rinse and repeat 10 times, then the player is asked if they want to continue or end the program. The type of question (add, mult, etc.) should be selected randomly.

So that I don't need to use a huge switch case or if-else tree, I want to know if there is any way to contain an operator in a variable, and then use it later.

Example:

var operator =  ;
int[] n = {1, 2};
System.out.println(n[0] operator n[1]);

And the output would be "3"

That's an example of what kinda thing I want to do. Is this possible?

CodePudding user response:

No, you can't do that directly. You will have to make a type that represents an operator.

The most common way to do this is with an enum:

enum Operator {
  PLUS {
    @Override int operate(int a, int b) {
      return a   b;
    }
  };

  abstract int operate(int a, int b);
}

Operator operator = Operator.PLUS;
int[] n = {1, 2};
System.out.println(operator.operate(n[0], n[1]));

CodePudding user response:

It's not possible to assign an operator to a variable.

in 30 lines or less ... the program asks the user a simple addition, division, multiplication, or subtraction

If you want to implement it using as fewer lines as possible, build functional interfaces will be a good choice. For that, you need IntBinaryOperator that represents an operation done on two int arguments.

Functional interface can be implemented either by using a lambda expression or a method reference (also, you can do that with an anonymous inner class as well by it'll not be shorter).

The type of question (add, mult, etc.) should be selected randomly

For that, firstly, you need to define a Random object. In order to obtain a random integer in the given range, use

rand.nextInt(RANGE);

Where range should be defined as a global constant instead of hard-coding it in place.

Because your application has to interact with the user, every operation should be associated with a name that will be exposed to the user.

It can be done by declaring a record (a special kind class with final field and auto-generated constructor, getters, hashCode/equals, toString()). Syntax for declaring records is very concise:

public record Operation(String name, IntBinaryOperator operation) {}

Records representing arithmetical operations can be stored in a list. And you can pick an operation by generating a random index (from 0 up to list size).

operations.get(rand.nextInt(operations.size()))

Because your application relies on a string entered by the user, you can map each function representing an operation to a string key by placing them in a map Map<String, IntBinaryOperator>.

In order to use the function retrieved from the map, you need to invoke the method applyAsInt() on it, passing the two number entered by user.

That's how it might look like.

public class Operations {
    public static final int RANGE = 100;
    public static final Random rand = new Random();
    
    public record Operation(String name, IntBinaryOperator operation) {}
    public static final List<Operation> operations =
            List.of(new Operation("add", Integer::sum), new Operation("sub", (i1, i2) -> i1 - i2),
                    new Operation("mult", (i1, i2) -> i1 * i2), new Operation("div", (i1, i2) -> i1 / i2));

    public static void main(String[] args) {
        // you code (instansiate a scanner, enclose the code below with a while loop) 
        for (int i = 0; i < 10; i  ) {
            Operation oper = operations.get(rand.nextInt(operations.size()));
            int operand1 = rand.nextInt(RANGE);
            int operand2 = rand.nextInt(RANGE);
            System.out.println(operand1   " "   oper.name()   operand2);        // exposing generated data to the user
            System.out.println(oper.operation().applyAsInt(operand1,operand2)); // exposing the result
        }
        // termination condition of the while loop
    }
}

You can also spare a couple of lines by sacrificing intermediate variables:

int result = operations.get(sc.next().toLowerCase())
                       .applyAsInt(sc.nextInt(), sc.nextInt());

Also, you might add same input validation, in that case containsKey() method can be useful.

  • Related