JAVA - Use functional interface for calculations - java

So... this is my first post here on Stack and i'm also new into Java (into programming at all). I'm trying to make a simple commandline app that will calculate employees' profit depending of generated income. Already did it but as i'm learning functional interfaces and lambdas right now, i'd like to try use them. Down below you can find the code.
package BalanceCounter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Number of employees: ");
int empCounter = input.nextInt();
System.out.println();
List<Employee> employees = new ArrayList<>(empCounter);
for (int i = 0; i < empCounter; i++) {
employees.add(new Employee());
}
for (Employee employee : employees) {
System.out.println("Employee: " + employee.getEmpName()
+ "\nBase salary: " + employee.getEmpBaseSalary()
+ "\nProfit from income: " + employee.getEmpBonus()
+ "\n");
}
}
}
Here's Employee class with getEmpBonus() method in comment block. That's where i've tried to use functional interfaces.
package BalanceCounter;
import java.util.Scanner;
class Employee {
private String empName;
private double empBaseSalary;
private double empIncome;
private double empBonus;
Employee() {
Scanner input = new Scanner(System.in);
System.out.print("Employees name: ");
setEmpName(input.nextLine());
System.out.print("Type basic salary: ");
setEmpSalary(input.nextDouble());
System.out.print("Generated income: ");
setEmpIncome(input.nextDouble());
setEmpBonus();
System.out.println();
}
/*
* Here are all the setters
*/
private void setEmpName(String empName) {
this.empName = empName;
}
private void setEmpSalary(double empBaseSalary) {
this.empBaseSalary = empBaseSalary;
}
private void setEmpIncome(double empIncome) {
this.empIncome = empIncome;
}
private void setEmpBonus() {
if (getEmpIncome() <= 10000)
empBonus = (getEmpIncome() * 3) / 100;
else if (getEmpIncome() > 10000 && getEmpIncome() <= 20000)
empBonus = (getEmpIncome() * 2) / 100;
else empBonus = (getEmpIncome() * 1) / 100;
}
/*
* Time for the getters
*/
String getEmpName() {
return empName;
}
double getEmpBaseSalary() {
return empBaseSalary;
}
private double getEmpIncome() {
return empIncome;
}
double getEmpBonus() {
return empBonus;
}
/*
* double getEmpBonus(Calculation calculation) {
* return empBonus = calculation.calculate(this.empBonus);
* }
*/
}
And the last thing is Calculation interface.
package BalanceCounter;
public interface Calculation {
double calculate(double arg);
}
class CalcBonus implements Calculation{
public double calculate(double empBonus) {
return empBonus;
}
}
Sorry for the long post but wanted to give you all informations i have.
Also if you see some mistakes and bad habits in my code - please let me know. Kind regards.

package training;
public class Calculator {
interface IntegerMath {
int operation(int a, int b);
}
interface RealMath {
double operation(double a, double b);
}
public int operateBinary(int a, int b, IntegerMath op) {
return op.operation(a, b);
}
public double operateBinary(int a, int b, RealMath op) {
return op.operation(a, b);
}
public static void main(String... args) {
Calculator cal = new Calculator();
IntegerMath addition = (a, b) -> a + b;
IntegerMath subtraction = (a, b) -> a - b;
IntegerMath multiplication = (a, b) -> a * b;
RealMath division = (a, b) -> a / b;
System.out.println("Add: 40 + 22 = " +
cal.operateBinary(40, 22, addition));
System.out.println("Sub: 120 - 80 = " +
cal.operateBinary(120, 80, subtraction));
System.out.println("Mul: 12 * 12 = " +
cal.operateBinary(12, 12, multiplication));
System.out.println("Div: 478 / 12 = " +
cal.operateBinary(478, 12, division));
}
}

This interface :
public interface Calculation {
double calculate(double arg);
}
has the same contract that DoubleUnaryOperator :
#FunctionalInterface
public interface DoubleUnaryOperator {
double applyAsDouble(double operand);
...
}
So you don't really need to introduce a new interface for this.
You could use the built-in one.
But if you want to really stress on the name and or arguments of the method.
As a general way, look before whether built-in Functional Interfaces could not match to your requirement before creating it.
Suppose now you uncomment your method and you want to use this method :
double getEmpBonus(DoubleUnaryOperator calculation) {
return empBonus = calculation.applyAsDouble(this.empBonus);
}
Without lambda, you have to create a subclass or an anonymous class if you want to pass an implementation that doubles the bonus :
class DoubleBonus implements DoubleUnaryOperator {
public double applyAsDouble(double operand) {
return operand * 2;
}
}
The idea of the lambda is that you could inline the subclass with a lambda expression.
You could so invoke the method in this way :
double doubledBonus = getEmpBonus(empBonus->empBonus*2);
You don't need any longer of the subclass or an anonymous class.

Related

How to aggregate methods from another class?

I have a class Fraction with the arithmetic operations for fractions. Here is an abstract of my class Fraction. (I've included only method of addition.)
package com.company;
import java.util.Scanner;
public class Fraction {
private int num; // numerator
private int denom; // denominator
public Fraction() {
super();
}
public Fraction(int num, int denom) {
super();
this.num = num;
this.denom = denom;
if (denom == 0) {
this.denom = 1;
}
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public int getDenom() {
return denom;
}
public void setDenom(int denom) {
if (denom > 0) {
this.denom = denom;
}
}
public void inputFraction() {
Scanner innum = new Scanner(System.in);
System.out.println("Input numerator: ");
num = innum.nextInt();
Scanner indenom = new Scanner(System.in);
System.out.println("Input denominator: ");
denom = indenom.nextInt();
}
public String toString() {
return num + "/" + denom;
}
// addition
public Fraction add(Fraction f2) {
int num2 = f2.getNum();
int denom2 = f2.getDenom();
int num3 = (num * denom2) + (num2 * denom);
int denom3 = denom * denom2;
Fraction f3 = new Fraction(num3, denom3);
f3.simplifyFraction();
return f3;
}
}
Now my second task is to make a class Calculator, which aggregates two instances of class Fraction as its attributes and create a complete set of arithmetic operations using instances of the class Fraction as operands. So, if I am correct, I basically have to use those methods from the class Fraction in my Calculator. I've attempted to do that but I do not get any output when I call for method add (from class Calculator) in main().
Here is an abstract of my Calculator class. (I've included only method of addition to give the general idea.)
package com.company;
public class Calculator {
private Fraction f1 = new Fraction();
private Fraction f2 = new Fraction();
private Fraction f;
public Calculator() {
super();
}
public Calculator(Fraction f) {
this.f = f;
}
public void input() {
f1.inputFraction();
f2.inputFraction();
}
public void view() {
f1.toString();
System.out.println("Fraction = " + f1.toString());
f2.toString();
System.out.println("Fraction = " + f2.toString());
}
public Calculator add() {
Calculator f = new Calculator(f1.add(f2));
return f;
}
}
And part of my main():
Calculator m = new Calculator();
m.input();
m.view();
System.out.println("Sum = " + m.add());
I'm assuming there are multiple places where I have gone wrong, so I'd be grateful for some advice.
Your add method is the problem here. It is returning a Calculator object and println calls that object's toString method so the toString method for Calculator is being called. The add method should not return a new Calculator but instead a new Fraction that represents your result. Then the code will print the toString method in your Fraction class which is what you want to display.
public class Calculator {
.
.
.
public Fraction add() {
return f1.add(f2);
}
}

How to pass the value of variables from main class to another class?

Hello everyone I'm currently creating a simple program. I have 2 classes the first one is calculator and the second one is parameters_return. What I want to happen is that when I read the values of x and y in my second class i want to use them in my first class Unfortunately, I can't run the program because it has an error. The code is below please help me with regards to this matter. I'm just self studying I really want to learn Java.
Code in (first class) calculator class is:
class calculator {
//with parameters with return type
int add(int a, int b) {
return (a + b);
}
//with parameters without return type
void sub(int a, int b) {
System.out.print(a - b);
}
//without parameters with return type
int mul() {
parameters_return s1 = new parameters_return();
int c = (s1.x) * (s1.y);
return c;
}
//without parameters without return type
void div() {
parameters_return s2 = new parameters_return();
int c = (s2.x) / (s2.y);
System.out.println("Division = " + c);
}
}
Code in my (second class) parameters_return class is:
class parameters_return {
int x, y;
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
x = sc.nextInt();
y = sc.nextInt();
calculator perform = new calculator();
//addition
int z = perform.add(x, y);
System.out.println("Added value = " + z);
//subtraction
System.out.println("Subtracted value = ");
perform.sub(x, y);
//multiplication
z = perform.mul();
System.out.println("Multiplication value = ");
//division
perform.div();
}
}
Is there any way to get values from main class and can be used in another class?
import java.util.*;
class ParametersReturn {
static int x, y;
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
x = sc.nextInt();
y = sc.nextInt();
Calculator perform = new Calculator();
//addition
int z = perform.add(x, y);
System.out.println("Added value = " + z);
//subtraction
System.out.println("Subtracted value = ");
perform.sub(x, y);
//multiplication
z = perform.mul();
System.out.println("Multiplication value = " + z);
//division
perform.div();
}
}
This should be your ParametersReturn Class and make sure you should start your class name with capital letter , you are using Scanner class to use it you have to import java.util package. And to use these variables in Calculator class make these variables static
class Calculator {
//with parameters with return type
int add(int a, int b) {
return (a + b);
}
//with parameters without return type
void sub(int a, int b) {
System.out.print(a - b);
}
//without parameters with return type
int mul() {
ParametersReturn s1 = new ParametersReturn();
int c = (s1.x) * (s1.y);
return c;
}
//without parameters without return type
void div() {
ParametersReturn s2 = new ParametersReturn();
int c = (s2.x) / (s2.y);
System.out.println("Division = " + c);
}
}
And in multiplication you forgot to print the value of z

(java.lang.StackOverflowError) how do i solve it? [duplicate]

This question already has answers here:
What is a StackOverflowError?
(16 answers)
Understanding recursion [closed]
(20 answers)
Closed 3 years ago.
i'm writing a program based on the Quadratic Equation everything looks good to me and there are not syntax or logical errors from what i see and also Eclipse isn't detecting any errors before running.
this is the output from the code:
Exception in thread "main" java.lang.StackOverflowError
at QuadraticEquation.getDiscriminant(QuadraticEquation.java:33)
note it continues like this for about 50 lines or so
public class QuadraticEquation {
private double a;
private double b;
private double c;
public QuadraticEquation() {
double a = 0;
double b = 0;
double c = 0;
}
public QuadraticEquation(double newA, double newB, double newC) {
a = newA;
b = newB;
c = newC;
}
public double discriminant1 = Math.pow(b, 2) - 4 * a * c;
public double discriminant2 = Math.pow(b, 2) - 4 * a * c;
public double getA() {
return getA();
}
public double getB() {
return getB();
}
public double getC() {
return getC();
}
public double getDiscriminant() {
double discriminant = (b * 2) - (4 * a * c);
return getDiscriminant();
}
public double getRoot1() {
double r1 = (-1*b) + Math.sqrt(discriminant1) / (2*a);
return getRoot1();
}
public double getRoot2() {
double r2 = (-1*b) - Math.sqrt(discriminant2) / (2*a);
return getRoot2();
}
public void setA(double newA1) {
a = newA1;
}
public void setB(double newB1) {
b = newB1;
}
public void setC(double newC1) {
c = newC1;
}
}
import java.util.Scanner;
public class TestEquation {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
QuadraticEquation Quadratic = new QuadraticEquation();
System.out.println("Please enter the values of the following variables: ");
System.out.println("a: ");
Quadratic.setA(input.nextDouble());
System.out.println("b: ");
Quadratic.setB(input.nextDouble());
System.out.println("c: ");
Quadratic.setC(input.nextDouble());
if (Quadratic.getDiscriminant() < 0) {
System.out.println("The equation has the following roots:");
System.out.println("The first one is " + Quadratic.getRoot1());
System.out.println("The second one is " + Quadratic.getRoot2());
}
else if (Quadratic.getDiscriminant() == 0) {
System.out.println("The equation has one root:");
System.out.println(Quadratic.getRoot1());
}
else {
System.out.println("The equation has the no real roots");
return;
}
}
}
Your error is an infinite recursion here:
public double getDiscriminant() {
double discriminant = (b * 2) - (4 * a * c);
return getDiscriminant();
}
This function calls itself infinitely until the stack overflows. I believe you wanted to return the variable discriminant instead?
Same for your functions getRoot1, getRoot2, getA, getB, and getC.

How to print out a toString for this class?

I have written a polynomial class and a tester class. The polynomial class can evaluate and return the sum of the polynomial when the degree, coefficients and the value of x are provided. Basically I need to edit my toString method so it actually prints out the polynomial
import java.util.Arrays;
import java.util.Scanner;
public class Polynomial {
private int degree;
private int [] coefficient;
private double evaluation;
private double sum;
private double value;
Scanner key = new Scanner(System.in);
public Polynomial(int degree)
{
this.degree = degree;
coefficient = new int [degree+1];
}
public void setCoefficient(int coefficient)
{
this.coefficient[this.degree] = coefficient;
}
public int getCoefficient(int degree)
{
return coefficient[degree];
}
public double Evaluate(double value)
{
this.value =value;
for (int i=0; i<=degree; i++)
{
System.out.println("Enter coefficent for position " + i);
this.coefficient[i] = key.nextInt();
evaluation = Math.pow(value, i)*this.coefficient[0] ;
this.sum += evaluation;
}
return sum;
}
/** Standard toString method */
//needed something better than this below...needed an actual polynomial printed out
public String toString()
{
return "The degree of the polynomial is " + degree + " and the value for which it has been evaluated is" + value;
}
}
This should be along the lines you should be proceeding. I included the main function in your Polynomial class for simplicity, so you will have to modify that if you want to keep it in your tester class. Notice that degree has been made into an integer array of size degree +1(allocated in the constructor):
import java.util.Scanner;
public class Polynomial {
private int degree;
private int [] coefficient;
private double evaluation;
private double sum;
Scanner key = new Scanner(System.in);
public Polynomial(int degree)
{
this.degree = degree;
coefficient = new int [degree+1];
}
public void setCoefficient(int coefficient, int degree)
{
this.coefficient[degree] = coefficient;
}
public int getCoefficient(int degree)
{
return coefficient[degree];
}
public void Evaluate(double value)
{
for (int i=0; i<=degree; i++)
{
System.out.println("Enter coefficent for position " + i);
this.coefficient[i] = key.nextInt();
evaluation = Math.pow(value, i)*this.coefficient[0] ;
this.sum += evaluation;
}
}
public double getSum(){
return sum;
}
public String toString()
{
String s = "";
for (int i=0; i <= degree; i++)
{
s += coefficient[i];
switch (i) {
case 0:
s += " + ";
break;
case 1:
s += "x + ";
break;
default:
s += "x^" + i + ((i==degree)?"":" + ");
}
}
return s;
}
public static void main(String[] args) {
int degree;
double sum;
int coefficient;
Scanner key = new Scanner(System.in);
System.out.println("Enter the degree of the polynomial");
degree=key.nextInt();
Polynomial fun = new Polynomial(degree);
fun.Evaluate(3.0);
System.out.println(" The sum of the polynomial is " + fun.getSum());
System.out.println(fun);
}
}
The usual way of making the objects of a class printable is to supply a toString method in the class, which specifies how to express objects of that class as a String. Methods such as println and other ways of outputting a value will call a class's toString method if they need to print an object of that class.
You should adopt the same pattern with your Polynomial class - write a toString method with all the output logic. Then in your PolynomialTester class, all you need to write is System.out.println(fun); and the rest will just happen. You'll find this far more versatile than writing a method that actually does the printing. For example, you'll be able to write something like
System.out.println("My polynomial is " + fun + " and " + fun + " is my polynomial.");
if that's your idea of fun.
A few other things concern me about your class.
You seem to be only storing one coefficient and one exponent. I'd expect a polynomial to have a whole array of coefficients.
You have fields for evaluation and sum - but these only really make sense while a polynomial is being evaluated. They're not long-term properties of the polynomial. So don't store them in fields. Have them as local variables of the evaluate method, and return the result of the evaluation.
I'd expect a class like this to be immutable. That is, you should provide all the coefficients when the object is created, and just never change them thereafter. If you do it that way, there's no need to write setter methods.
So I've written my own version of your class, that fixes those issues listed above, and implements a toString method that you can use for printing it. A second version of toString lets you specify which letter you want to use for x. I've used "varargs" in the constructor, so you can construct your polynomial with a line such as
Polynomial fun = new Polynomial (7, 2, 5, 0, 1);
specifying the coefficients from the constant term through in order to the coefficient of the term with the highest exponent. Or you can just pass an array.
See that I've changed the logic a wee bit - my version prints the polynomial in the conventional order, from highest to lowest exponent. It leaves off the decimals if the coefficient is an integer. It doesn't print a 1 in front of an x. And it deals cleanly with - signs.
import java.util.Arrays;
public class Polynomial {
private double[] coefficients;
public Polynomial(double... coefficients) {
this.coefficients = Arrays.copyOf(coefficients, coefficients.length);
}
public int getDegree() {
int biggestExponent = coefficients.length - 1;
while(biggestExponent > 0 && coefficients[biggestExponent] == 0.0) {
biggestExponent--;
}
return biggestExponent;
}
public double getCoefficient(int exponent) {
if (exponent < 0 || exponent > getDegree()) {
return 0.0;
} else {
return coefficients[exponent];
}
}
public double evaluateAt(double x) {
double toReturn = 0.0;
for (int term = 0; term < coefficients.length; term++) {
toReturn += coefficients[term] * Math.pow(x, term);
}
return toReturn;
}
#Override
public String toString() {
return toString('x');
}
public String toString(char variable) {
boolean anythingAppendedYet = false;
StringBuilder toReturn = new StringBuilder();
for (int exponent = coefficients.length - 1; exponent >= 0; exponent--) {
if (coefficients[exponent] != 0.0) {
appendSign(toReturn, exponent, anythingAppendedYet);
appendNumberPart(toReturn, exponent);
appendLetterAndExponent(toReturn, exponent, variable);
anythingAppendedYet = true;
}
}
if (anythingAppendedYet) {
return toReturn.toString();
} else {
return "0";
}
}
private void appendSign(StringBuilder toAppendTo, int exponent, boolean anythingAppendedYet) {
if (coefficients[exponent] < 0) {
toAppendTo.append(" - ");
} else if (anythingAppendedYet) {
toAppendTo.append(" + ");
}
}
private void appendNumberPart(StringBuilder toAppendTo, int exponent) {
double numberPart = Math.abs(coefficients[exponent]);
if (numberPart != 1.0 || exponent == 0) {
//Don't print 1 in front of the letter, but do print 1 if it's the constant term.
if (numberPart == Math.rint(numberPart)) {
// Coefficient is an integer, so don't show decimals
toAppendTo.append((long) numberPart);
} else {
toAppendTo.append(numberPart);
}
}
}
private void appendLetterAndExponent(StringBuilder toAppendTo, int exponent, char variable) {
if (exponent > 0) {
toAppendTo.append(variable);
}
if (exponent > 1) {
toAppendTo.append("^");
toAppendTo.append(exponent);
}
}
}
So I tested it with this class
public class PolynomialTester {
public static void main(String[] args) {
Polynomial fun = new Polynomial (7, 2, 5, 0, 1);
System.out.println(fun.getDegree());
System.out.println(fun.evaluateAt(3));
System.out.println(fun);
}
}
and the output was
4
139.0
x^4 + 5x^2 + 2x + 7
then I realised that you wanted to be able to input the coefficients in a loop. So I changed PolynomialTester to this. See how I build the array and then create the object.
import java.util.Scanner;
public class PolynomialTester {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter the degree:");
int degree = input.nextInt();
double[] coefficients = new double[degree + 1];
for( int exponent = 0; exponent <= degree; exponent++) {
System.out.println("Enter the coefficient of x^" + exponent);
coefficients[exponent] = input.nextDouble();
}
Polynomial fun = new Polynomial (coefficients);
System.out.println(fun.evaluateAt(3));
System.out.println(fun);
input.close();
}
}
Note that if you really want your polynomial to be printed in "reverse" order, with the constant term first, you could change the loop in the toString method to this.
for (int exponent = 0; exponent < coefficients.length; exponent++) {
You may add a class member String poly, then modify the following method.
public void Evaluate(double value)
{
for (int i=0; i<=degree; i++)
{
System.out.println("Enter coefficent for position " + i);
this.coefficient= key.nextInt();
evaluation = Math.pow(value, i)*coefficient ;
this.sum += evaluation;
this.poly = "";
if(coefficient != 0)
{
if(i > 0)
{
this.poly += " + " + Integer.toString(coefficient) + "x^" + Integer.toString(i); // you may replace x with the actual value if you want
}
else
{
this.poly = Integer.toString(coefficient)
}
}
}
}

Implementing a Jump Table in Java

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.
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.
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.
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);
}
}
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";
}
}
}

Categories

Resources