4

How do I make the switch/case statement in this simple Calculator program into a jump table.

import java.lang.*;
import java.util.*;

public class Calculator
{
    private int solution;
    private static int x, y, ops;
    private char operators;

    public Calculator()
    {
        solution = 0;
    }

    public int addition(int x, int y)
    {
       return x + y;
    }
    public int subtraction(int x, int y)
    {
       return x - y;
    }
    public int multiplication(int x, int y)
    {
       return x * y;
    }
    public int division(int x, int y)
    {
       solution = x / y;
       return solution;
    }

    public void calc(int ops){
         Scanner operands = new Scanner(System.in);

         System.out.println("operand 1: ");
         x = operands.nextInt();
         System.out.println("operand 2: ");
         y = operands.nextInt();

         System.out.println("Solution: ");

         switch(ops)
         {
             case(1):
               System.out.println(addition(x, y));
               break;
             case(2):
               System.out.println(subtraction(x, y));
               break;
             case(3):
               System.out.println(multiplication(x, y));
               break;
             case(4):
               System.out.println(division(x, y));
               break;
          }
    }
    public static void main (String[] args)
    {
      System.out.println("What operation? ('+', '-', '*', '/')");
      System.out.println(" Enter 1 for Addition");
      System.out.println(" Enter 2 for Subtraction");
      System.out.println(" Enter 3 for Multiplication");
      System.out.println(" Enter 4 for Division");

      Scanner operation = new Scanner(System.in);
      ops = operation.nextInt();

      Calculator calc = new Calculator();
      calc.calc(ops);


  }
}

To be completely honest, I don't know exactly what a jump table is (couldn't find any explanations online) so I don't know how it differs from a switch/case statement.

Side Note: This code only deals with integers so if you divide 5/3 its gives you 1. How can I easily change it to take floats/doubles.

Richie Miz
  • 49
  • 7
  • jump tables: http://stackoverflow.com/questions/48017/what-is-a-jump-table . It's all about pointers to functions, not something you'd do in java. I have to ask, why do you want to do this? – tom Oct 09 '13 at 16:03
  • My professor was going over pointers in java and recommended we try an exercise where we take a switch/case statement and switch it to a jump-table, as good practice for working with pointers. Problem is he didn't really explain what it is and I don't know what to do. – Richie Miz Oct 09 '13 at 16:14
  • 1
    What do you mean "pointers in java"? You can pass by reference, which I guess is a similar concept but it's not pointers. Java doesn't have pointers. Your professor sounds confused. – tom Oct 09 '13 at 16:16
  • I agree, he sounds confused and I don't get anything he is saying. Because I am sure he uses the term pointers in Java. – Richie Miz Oct 09 '13 at 16:19

4 Answers4

3

As mentioned, a jump table is an array of offsets/pointers to functions. Unlike C/C++, Java doesn't really have function pointers (Function Pointers in Java)

But you can pretend, and do it the object oriented way. Define a base class (Funky) with one method (f). Derive mutiple children, one for each of your functional operations (+,-,*,/, etc), and create a single object for each child (it is just an interface, after all), and store that child into an array of type (Funky).

Lookup the operation in the table, and call the method on your arguments

Example:

Define a base class, (or an interface, which makes you happier?). Note that if you extend a class, you can use the base class method as a default (generate an error message, or throw an exception),

public class X
//or, public interface X
{
    //method
    Z fun(Z z1, Z z2)
    {
        //nothing to see here
    }
}

class X1 extends X //or, implements X
{
    public Z fun(Z z1, Z z2)
    {
        //variant1 stuff here
    }
}
...
public class Xn extends X //or, implements X
{
    public Z fun(Z z1, Z z2)
    {
        //variantn stuff here
    }
}

Oh, and you will need instances, and load them into an array (the jumptable).

There are certain techniques which are idiomatic to certain languages, and jumptables are more of a systems thing and less of a Java thing, not really a Java idiom.

Community
  • 1
  • 1
ChuckCottrill
  • 4,360
  • 2
  • 24
  • 42
0

well, i don't know what is a jump table, but if you wanna control another type of numbers, you can change of parameter for example you method:

public int addition(int x, int y)
    {
       return x + y;
    }

if you wanna Double-->

 public int addition(Double x, Double y)

but i strongly recommend you user the type Number every other class extens from Number.

Number.class

ex:

public static String numeroToLetra(Number num)
  {
    Integer numero = Integer.valueOf(num.intValue()); //int value 
    Double numero = Double.valueOf(num.doubleValue());........
}//so you can pass whatever type of number.
ZaoTaoBao
  • 2,567
  • 2
  • 20
  • 28
  • Can you explain your recommendation at the end of your answer a little more? I don't quite understand what you mean. – Richie Miz Oct 09 '13 at 16:16
  • try changing every almost every 'int' in your program to 'double' and go from there. (don't change the bit that reads the ops!) – tom Oct 09 '13 at 16:21
  • Thanks got this to work, now to just figure out the jump-table issue. – Richie Miz Oct 09 '13 at 16:32
  • sorry for my bad explanation, all this java objects extends from Number--> AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short. So if you parameter type is Number you can work with all the other classes with the same method. – ZaoTaoBao Oct 10 '13 at 08:01
0

This is an old question, but I think it still has value for illustrating what you can do since Java 8. Basically, you create an interface whose sole purpose is to provide a type for an operations array and then you use method references to populate the operations array. After that, you can use the index to select the proper operation. I made minimal modifications to the OP's code such that the comparison is easiest:

import java.util.Scanner;


public class Calculator
{
    //
    // Create an interface to use as Type for
    // operations array.
    //
    private interface BinaryOperation {
        int performOperation(int a, int b);
    }
    //
    // Array has one unused element to make coding easier
    // and use operation as a direct index.
    // You can replace with 4 element array easily.
    //
    BinaryOperation[] operations = new BinaryOperation[5];

    private int solution;
    private static int x, y, ops;
    private char operators;

    public Calculator()
    {
        solution = 0;
        //
        // Initialize jump table using method references.
        //
        operations[1] = this::addition;
        operations[2] = this::subtraction;
        operations[3] = this::multiplication;
        operations[4] = this::division;
    }

    public int addition(int x, int y)
    {
        return x + y;
    }
    public int subtraction(int x, int y)
    {
        return x - y;
    }
    public int multiplication(int x, int y)
    {
        return x * y;
    }
    public int division(int x, int y)
    {
        solution = x / y;
        return solution;
    }

    public void calc(int ops){
        Scanner operands = new Scanner(System.in);

        System.out.println("operand 1: ");
        x = operands.nextInt();
        System.out.println("operand 2: ");
        y = operands.nextInt();

        System.out.println("Solution: ");
        //
        // Call binary operation through jump table
        //
        System.out.println(operations[ops].performOperation(x, y));
    }
    public static void main (String[] args)
    {
        System.out.println("What operation? ('+', '-', '*', '/')");
        System.out.println(" Enter 1 for Addition");
        System.out.println(" Enter 2 for Subtraction");
        System.out.println(" Enter 3 for Multiplication");
        System.out.println(" Enter 4 for Division");

        Scanner operation = new Scanner(System.in);
        ops = operation.nextInt();

        Calculator calc = new Calculator();
        calc.calc(ops);


    }
}
luv2learn
  • 606
  • 8
  • 12
0

If you're working with a version of Java that supports lambdas, a solution that is more true to the requirement to implement as a "jump table" would use an actual jump table, one that maps operator codes to lambda expressions that implement each the operands.

This is a pleasing way not only to eliminate clunky switch statements, but to produce more maintainable and more easily extensible code. Future new operands can easily be added later without making any changes to the Calculator implementation. Simply implement the new operator and its naming method, and add it to the jump tables. Your Calculator will automatically support the new operand.

import com.google.common.collect.ImmutableMap;

import java.lang.*;
import java.util.*;

public class Calculator
{
    private static final Map<Integer,BinaryOperator<Integer>> evaluators = ImmutableMap.<Integer, BinaryOperator<Integer>>builder()
        .put(1, (Integer x, Integer y) -> new IntAddition().evaluateFor(x,y))
        .put(2, (Integer x, Integer y) -> new IntSubtraction().evaluateFor(x,y))
        .put(3, (Integer x, Integer y) -> new IntMultiplication().evaluateFor(x,y))
        .put(4, (Integer x, Integer y) -> new IntDivision().evaluateFor(x,y))
        .build();

    private static final Map<Integer,Nameable> names = ImmutableMap.<Integer, Nameable>builder()
        .put(1, () -> new IntAddition().getName())
        .put(2, () -> new IntSubtraction().getName())
        .put(3, () -> new IntMultiplication().getName())
        .put(4, () -> new IntDivision().getName())
        .build();

    private int solution;
    private static int x, y, ops;

    public Calculator()
    {
        solution = 0;
    }

    public void calc(int opcode)
    {
        Scanner operands = new Scanner(System.in);

        System.out.println("Enter operand 1: ");
        x = operands.nextInt();
        System.out.println("Enter operand 2: ");
        y = operands.nextInt();

        System.out.print("Solution: ");
        System.out.println(evaluators.get(opcode).evaluateFor(x, y));
    }

    public static void main(String[] args)
    {
        System.out.println("What operation?");
        for (Integer opcode : evaluators.keySet())
        {
            System.out.println(String.format(" Enter %d for %s", opcode, names.get(opcode).getName()));
        }

        Scanner operation = new Scanner(System.in);
        ops = operation.nextInt();

        Calculator calc = new Calculator();
        calc.calc(ops);
    }

    interface Nameable
    {
        String getName();
    }

    interface BinaryOperator<T>
    {
        T evaluateFor(T x, T y);
    }

    static class IntAddition implements BinaryOperator<Integer>, Nameable
    {
        IntAddition() { }

        public Integer evaluateFor(Integer x, Integer y)
        {
            return x + y;
        }

        public String getName()
        {
            return "Addition";
        }
    }
    static class IntSubtraction implements BinaryOperator<Integer>, Nameable
    {
        IntSubtraction() { }

        public Integer evaluateFor(Integer x, Integer y)
        {
            return x - y;
        }

        public String getName()
        {
            return "Subtraction";
        }
    }
    static class IntMultiplication implements BinaryOperator<Integer>, Nameable
    {
        IntMultiplication() { }

        public Integer evaluateFor(Integer x, Integer y)
        {
            return x * y;
        }

        public String getName()
        {
            return "Multiplication";
        }

    }
    static class IntDivision implements BinaryOperator<Integer>, Nameable
    {
        IntDivision() { }

        public Integer evaluateFor(Integer x, Integer y)
        {
            return x / y;
        }

        public String getName()
        {
            return "Division";
        }
    }
}
djenning90
  • 197
  • 1
  • 9