Can I map a String to a method in java? - java

I'm writing an expression evaluator in Java. I would like the ability to add more operators (I currently have only (, ), +, -, *, /, and ^). Currently, my code looks like this:
case '+':
return a+b;
case '-':
return a-b;
case '*':
return a*b;
...
This works for my code because I have only a few operators. However, if I were to add more operators, the code would become cluttered. I am looking for a way to map an operator (represented by a String) to a method. For example, "ln" would be mapped to Math.log(), "^" would be mapped to Math.pow(), etc.
How would I go about doing this? If it's not feasible, what are some alternatives?

Not possible unless you want to use reflection. A solution without reflection could look like this:
public interface Operation {
int apply(int... operands);
}
public abstract class BinaryOperation implements Operation {
#Override
public int apply(int... operands) {
return apply(operands[0], operands[1]);
}
abstract int apply(int a, int b);
}
Map<String, Operation> operations = new HashMap<String, Operation>() {{
put("+", new Operation() {
#Override
public int apply(int... operands) {
return operands[0] + operands[1];
}
});
put("-", new BinaryOperation() {
#Override
public int apply(int a, int b) {
return a - b;
}
});
}};

You could use template methods.
public enum Functions {
ADD() {
#Override public int execute(int a, int b) {
return a+b;
}
},
SUB() {
#Override public int execute(int a, int b) {
return a-b;
}
};
//Template method
public abstract int execute(int a, int b);
}
Then map between string and enum with Map<String, Functions> functionMap
So if you want to add you can do functionMap.put("+", Functions.ADD);
Then call functionMap.get("+").execute(a,b);
I suppose you could also use varargs if different functions take different numbers of arguments.
public abstract int execute (Integer... inputs);
This example is modified from Making the Most of Java 5.0: Enum Tricks and what #duffymo said.

Building on the Operation suggestion above, a Map<String, Operation> would manage it with a lookup.

I think your setup is the optimal setup as I cannot think of a way to do this easily in java, although in a language like c/c++ you could easily map strings to function pointers but I don't think there's an equivalent of this in Java AFAIK. The beauty of switch statements though is that they actually avoid the clutter because visually you can easily see what the case of the switch statement is and just look for the appropriate case that you want (although for strings you made need a giant if cascade since == operator is not overloaded in java for string comparison).
Edit: See Ryan Stewarts comment, they use OOP ways of doing exactly what you want. Although that seems more cluttered than your switch statement in some cases.

Related

Custom "sumDouble()" function in OptaPlanner for constraints

I need a sum functionality that sums up double values for my ConstraintProviding functionality. Currently OptaPlanner offers sum() and sumBigDecimal() functionality, where the first is only summing integer values and the second BigDecimal values. So therefore I started with the compose approach as described in the manual chapter 6.4.5.3. for implementing my own functionality (didn't want to override the original one).
Deriving from there and taking the implementation of the sum functionality from the ConstraintCollector.java class of the OptaPlanner source code itself, I ended up with the following code:
public static <A> UniConstraintCollector<A, ?, Double> sumDouble(ToDoubleFunction<A> groupValueMapping) {
return compose((resultContainer, a) -> {
double value = groupValueMapping.applyAsDouble(a);
resultContainer[0] += value;
return () -> resultContainer[0] -= value;
},
resultContainer -> resultContainer[0]);
}
within my "OwnConstraintProvider" class. But this doesn't work out. The error is:
java: method compose in interface java.lang.module.ModuleFinder cannot be applied to given types;
required: java.lang.module.ModuleFinder[]
found: (resultCon[...]ue; },(resultCon[...]er[0]
reason: varargs mismatch; java.lang.module.ModuleFinder is not a functional interface
multiple non-overriding abstract methods found in interface java.lang.module.ModuleFinder
I am aware that there must be a clearer relationship and calculation approach between the input A and the result.
Frankly speaking I have only recently starting Java programming seriously. So I can't sort out where I am mistaken in that case. In the manual of the current version used (8.19.0) there is "a generic sum() variant for summing up custom types" mentioned in chapter 6.4.5.1.3. but I have no glue about the details on that.
Can anybody give me a hint on this please.
Thanks in advance!
First of all, Radovan is completely correct in his answer. In fact, the potential score corruptions are the reason why sumDouble() is not provided. Instead, we provide sumBigDecimal(), which doesn't suffer from the same issue. However, it will suffer in terms of performance. The preferred solution is to use either sum() or sumLong(), using fixed-point arithmetic if necessary.
That said, implementing sumDouble() is relatively simple, and you do not need composition to achieve that:
public static <A> UniConstraintCollector<A, ?, Double> sum(ToDoubleFunction<? super A> groupValueMapping) {
return new DefaultUniConstraintCollector<>(
() -> new double[1],
(resultContainer, a) -> {
int value = groupValueMapping.applyAsDouble(a);
resultContainer[0] += value;
return () -> resultContainer[0] -= value;
},
resultContainer -> resultContainer[0]);
}
Now, DefaultUniConstraintCollector is not a public type. But you can use an anonymous class instead:
public static <A> UniConstraintCollector<A, ?, Integer> sum(ToDoubleFunction<? super A> groupValueMapping) {
return new UniConstraintCollector<A, double[], Double>() {
#Override
public Supplier<double[]> supplier() {
return () -> new double[1];
}
#Override
public BiFunction<double[], A, Runnable> accumulator() {
return (resultContainer, a) -> {
double value = groupValueMapping.applyAsDouble(a);
resultContainer[0] += value;
return () -> resultContainer[0] -= value;
};
}
#Override
public Function<double[], Double> finisher() {
return resultContainer -> resultContainer[0];
}
}
}
Use this at your own risk, and make sure you check for score corruptions, preferrably in a very long solver run.
Have you considered using a different type, e.g. long, to represent values you need to sum() in your constraint?
Using floating-point numbers in the score calculation is generally not recommended as it may lead to score corruption.

Provide arguments with a method

Is there a way in Java to create a method that would return the list of parameters of another method such that I am able to call
anotherMethod(method())
where anotherMethod has arbitrary arguments like
public void anotherMethod(int a, int b, String c)
And what is if the types stay the same, like with
public int add(int a, int b, int c)
If there is no such way, how could I model the list of parameters such that it would work? Is it a List or an array or something else?
If the number of parameters is fixed at the call site, you could use varargs
int add(int... numbers)
otherwise you'd use an array or collection
int add(int[] numbers)
You can then of course have another method provide the value of these parameters:
add(someOtherMethod())
Varargs
Java has a built-in feature to denote a variable length of arguments. It is called varargs (documentation) (variable arguments) and it only works if the type stays the same. The syntax for a method is like this:
public int add(int... values)
Note the int... values which denotes varargs. A caller can now call the method like
add(null) // Passing null
add(values) // Passing an int[]
add() // No arguments
add(a) // One int
add(a, b) // Two ints
add(a, b, c) // Three ints
add(a, b, c, d) // Four ints
...
Note the three special cases null, int[] and empty.
What Java does is it will convert the arguments into an array. So inside the method values will be a regular int[]. You could thus implement the method like
public int add(int... values) {
int sum = 0;
for (int value : values) {
sum += value;
}
return sum;
}
If you, as a caller, want to pass the return value of a function you just need to make sure that it returns an array like int[]. So the following would work:
public int[] valueProvider() {
int[] values = ...
return values;
}
and then call it like
int sum = add(valueProvider());
Collection, Iterable and Stream
Besides that, if you don't want to use varargs or arrays, you can use Collections (documentation). A collection may be a List or a Set and so on. For example you could declare
public int add(Collection<Integer> values)
and feed it like
Collection<Integer> values = new ArrayList<>();
values.add(1);
values.add(2);
int sum = add(values);
An Iterable<Integer>, in contrast to Collection<Integer> would even be more flexible.
Using a Stream (documentation) would also work like a charm and is probably one of the most flexible variants since the source of a stream could be anything and nearly anything of the standard library supports a stream representation.
Changing type
Now note that what you searched for in the beginning, a method that is able to feed arbitrary arguments, is not possible in Java.
The main problem is that the types may change, so you may have a method like
public void doSomething(int first, String second, File third)
and you won't be able to feed the method with varargs, Collections or any of the presented methods.
In that case you will need a wrapper class like
public class DoSomethingArguments {
private int mFirst;
private String mSecond;
private File mThird;
public DoSomethingArguments(int first; String second, File third) {
this.mFirst = first;
this.mSecond = second;
this.mThird = third;
}
// Some getters
}
(or a generic tuple class, a triple in this case)
But then you would need to change the method to
public void doSomething(DoSomethingArguments arguments)
what is probably not what you wanted since you probably intended to not change the signature of doSomething.
But unfortunately there is no way to feed a method like this in such a way.
There is nothing that works the way you wish for at compile time. As the other answers are pointing out, there are varargs. But that is just syntactical sugar. That is just the compiler implicitly creating an array of a certain type for you.
But beyond that, there is reflection. Reflection allows you to dynamically inspect classes and methods at *runtime.
In other words: you can do something like
Object whatever = ...
Class<?> someClass = whatever.getClass();
And now you can ask someClass about the methods it has. And which parameters they need.
But as said: all of that is runtime only. And it the reflection APIs are very easy to get wrong. And you only find out at runtime, when some exception is thrown.
There is not direct way to pass multiple values in the way you want. But you can use a indirect way to pass a group of values of different type. I can think of two ways but their can be more.
Firs - Use a map, just insert the values you want to pass in the collection and pass the collection to the second method.
Second - Create a bean (Java POJO) to pass as parameter to the consuming method.
A small sample code.
class Sample{
private int a;
private String b;
private int c;
Sample(int a,String b,int c){
this.a = a;
this.b = b;
this.c = c;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public int getC() {
return c;
}
public void setC(int c) {
this.c = c;
}
}
public class PassingExample {
public void consumerofInputs (Map<Integer, Object> input)/*(int a, String b, int c)*/{
System.out.println("I use three different inputs : int, string and int");
for (Map.Entry<Integer, Object> entry : input.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}
}
public Map producingInput() {
Map<Integer, Object> input = new HashMap<Integer, Object>();
input.put(1, 10);
input.put(2, "input");
input.put(3, 89);
return input;
}
public Sample createClassAsInput(){
Sample input = new Sample(10,"class-input",30);
return input;
}
public void useSampleAsInput(Sample input){
System.out.println("\nUsing Class as input \nInt::"+input.getA()+"\nString::"+input.getB()+"\nInt::"+input.getC());
}
public static void main(String[] args) {
PassingExample example = new PassingExample();
example.consumerofInputs(example.producingInput());
example.useSampleAsInput(example.createClassAsInput());
}
}

What does ()->{} represent in java?

What does ()->{} represent in java?. Any help would be highly appreciated.
It's a lambda expression, basically a concise way of writing a function. ()->{} is a function that takes no arguments and does nothing. A longer way of writing the same thing:
new Runnable() {
#Override
public void run() {
// nothing
}
};
Let's consider old way of writing functions(i.e methods) in java.
//lets assume this is inside calculate class
public int sum(int a, int b){
return a+b;
}
in java 8 we have something called lambda's in which we have concept called passing behaviours(methods) to another behaviour(methods).
in those case we use syntax like (a,b) -> return a+b;
BiFunction<Integer,Integer,Integer> sum= (a,b)->{
return a+b;
};
System.out.println(sum.apply(1, 2));
Even we can store Function in a variable and pass to another function. you
can see here
now lets see about syntax (a,b) ->{ return a + b};
(a,b) are arguments to function;
and the line of code inside {} represent the behaviour. -> is to separate
both left and right expressions.
you can explore more about java8 and lambda over here

Is this a correct way to use Enum?

So I have a field called optionType and I want it to be able to take on 4 different integer values corresponding to certain options. For example optionType = 0 means the user wants to handle something a certain way, optionType = 1 means another way, etc.
But numbers by themselves are meaningless so I wanted to define constants instead in the class.
public class MyClass {
public static final int OPTION_TYPE_DO_THIS = 0;
public static final int OPTION_TYPE_DO_THAT = 1;
public static final int OPTION_TYPE_DO_SOMETHING_ELSE = 2;
public static final int OPTION_TYPE_DO_COOL_THING = 3;
private int optionType;
....
Is it considered normal to define all the constants out like that or is it better to use an enum like
public enum OPTION_TYPE {DO_THIS, DO_THAT, DO_SOMETHING_ELSE, DO_COOL_THING};
Or am I supposed to be using Enum instead somehow?
The key point is more on "how will that information be used at runtime". You see, if you starting thinking about writing code such as
switch(someEnum) {
case DO_THIS: ...
case DO_THAT:
... then you are already going into the wrong direction!
The point is: very often think that enums (or their even-more-low-level numeric constant cousins) are a good way to express such designs.
But that actually leads to quite some problems. Very often, the better, "more OO" way of thing is to use some abstract base class with specific subclasses; in other words: polymorphism!
Edit: just to make that more clear ... a "single" switch over an enum isn't really a problem. But far too often, people end up with many many places in code where they switch over their enums. And all of those places might need updates when you create additional enum constants. A coworker of mine calls that the "enum trap".
Take a look at this question and answer,
Even though it is written in the C# context, the conclusion states that:
Enums are great for lightweight state information.
Static class members would be able to support this multiple state without any extra functionality.
In java enums are more than just "enumerated names" as they are in other language (e.g. in C/C++).
My preferred use is to provide stateless behavior:
class Calculator {
enum Operation {
ADD{
double calculate(double a, double b){ return a + b;}
}
SUB{
double calculate(double a, double b){ return a - b;}
}
MUL{
double calculate(double a, double b){ return a * b;}
}
DIV{
double calculate(double a, double b){ return a / b;}
}
abstract double calculate(double a, double b);
}
Map<String,Operation> operations = new HashMap<>();
Calculator(){
operations.put("+",ADD);
operations.put("-",SUB);
operations.put("*",MUL);
operations.put("/",DIV);
}
public double calculate(double a, String operation, double b){
return operations.get(operation).calculate(a,b);
}
}

Detecting type of operator stored as string in java [duplicate]

This question already has answers here:
Is it possible to pass arithmetic operators to a method in java?
(9 answers)
Closed 6 years ago.
In a Java program, I have these strings:
a= 8,7,"+"
b=1,5,"*"
Each line is a separate process. I want in each line, that two number calculated with that operator. But I don't want to use any type of condition system for detecting which operator is in each line.
In fact, my main problem is detecting the type of the operator without conditions. I don't want to use the Javascript engine. I want to know is there any efficient and standard way.
Another solution from J. Selva's response:
Improvements
single class
static block
better abstraction
import java.util.HashMap;
import java.util.Map;
/**
* Created by SEA-HAWK on 23/8/15.
*/
public abstract class Expr {
public static Map<String,Object> op;
static{
op=new HashMap<>();
op.put("+", new Expr() {
#Override
public int evaluate(int a, int b) {
return a + b;
}
});
op.put("-", new Expr() {
#Override
public int evaluate(int a, int b) {
return a - b;
}
});
op.put("*", new Expr() {
#Override
public int evaluate(int a, int b) {
return a * b;
}
});
op.put("/", new Expr() {
#Override
public int evaluate(int a, int b) {
return a / b; // decimal point loss
}
});
}
abstract public int evaluate(int a, int b);
public static int exprEval(String expr){
String a[]=expr.split(",");
a[2]=a[2].replaceAll("\"","");
return ((Expr)op.get(a[2])).evaluate(Integer.parseInt(a[0]),Integer.parseInt(a[1]));
}
}
Main function:
public static void main(String[] args) {
String x="20,10,\"*\"";
System.out.println(x+"="+Expr.exprEval(x));
x="20,10,\"+\"";
System.out.println(x+"="+Expr.exprEval(x));
x="20,10,\"-\"";
System.out.println(x+"="+Expr.exprEval(x));
x="20,10,\"/\"";
System.out.println(x+"="+Expr.exprEval(x));
}
Output:
20,10,"*"=200
20,10,"+"=30
20,10,"-"=10
20,10,"/"=2
Note: change datatype for float/decimal value computation.
First Split the string and store the operator in the Character variable. You can use split() to split a String and assign it to a String array. Access operator using the array index and assign it to a Character variable.
Now You can use Map<Character,Object> where you can store character and object to calculate in single structure and access later with character only without any if-else or switch.
Map<Character,Object> map = new HashMap<>();
map.put('+', plusObject);
map.put('-', minusObject);
map.put('*', multiplyObject);
map.put('/', divideObject);
To get the object type of operator, you can use map.get(character) it will return the object according to the character and null otherwise.
Update: Create four classes and a object for each class namely plusObject, minusObject, multiplyObject,divideObject. These are the objects that you add to HashMap initially. Have a evaluate() function in each class. Now with the returned object, call the evaluate() method which will make call to respective class. You need not check the Object type using any conditional statements.
You can convert the postfix expression into infix mathematical expression and execute it using expression evaluator in Java or javascript(not preferred). As you recommend java, following link will help you:
evaluating-a-math-expression-given-in-string-form
java-parse-a-mathematical-expression-given-as-a-string-and-return-a-number
Answer from above two links:
You can pass it to a BeanShell bsh.Interpreter, something like this:
Interpreter interpreter = new Interpreter();
interpreter.eval("result = 5+4*(7-15)");
System.out.println(interpreter.get("result"));
Let us know if your issue gets resolved.

Categories