Assign value to method invocation - java

For later reference:
Operations o = new Operations(); //class containing the operation methods
HashMap<String, Method> ops = new HashMap<String, Method>();
I'm working on a program that will parse a mathematical expression input via console or eventually maybe a GUI.
Currently, I have a class called "Operations" which has various basic math functions (more will be added later, just testing right now). In another class, I have a method which calculates the result by taking an operand, the successive operator, and another operand, and invoking a method to evaluate the expression. It stores the info necessary to the calculation in:
double numOne = //...
char operator = //...
double numTwo = //...
double result = //...
Now I don't want to have a long switch/case statement or if statement saying:
if (operator.equals("+")) //I know .equals() doesn't use chars; it's an example
o.add(numOne, numTwo);
else if (operator.equals("-"))
o.subtract(numOne, numTwo);
on and on for every operation. That's why I tried creating a HashMap<String, Method> to store the operator (String) and the method which should be called. Basically, in the current class' constructor, I put:
ops.put("+", o.getClass().getMethod("add", double.class, double.class));
ops.put("-", o.getClass().getMethod("subtract", double.class, double.class));
//etc. Which in and of itself is also pretty lengthy
Now to once the method is identified via operator, I need another method to return a Method to call.
private Method getMethodFromKey(HashMap<String, Method> map, char op) {
Method method = null;
for (Map.Entry<String, Method> e: map.entrySet()) {
if (e.getKey().equals(op))
method = e.getValue();
}
return method;
}
Finally, once I have the correct method, I can call it with:
getMethodFromKey(ops, operator).invoke(o, numOne, numTwo);
That all works great. My problem is, the method(s) I am/will be invoking are getter methods; they return a double. Example:
public double add(double one, double two) {
double answer = 0;
answer = one + two;
return answer;
}
I guess this is all just a long-winded way of asking is there a way to assign the returned value of an innvoked method? Something like:
result = getMethodFromKey(ops, operator).invoke(o, numOne, numTwo); //This doesn't work :(
Any help is appreciated. Additionally, if my aproach is completely wrong, I would appreciate a bump in the right direction.
DISCLAIMER: I'm relatively inexperienced at Java and known for overcomplicating things, so please point out any grievous flaws in my design. :)

invoke() returns Object and since Java does not know how to assign an Object to a double this won't compile. invoke starts by boxing the double from the method into a Double. You have to cast it now from Object to Double (and could then call .doubleValue() but that's done automatically) for that to work.
I'm [...] known for overcomplicating things, so please point out any grievous flaws in my design. :)
Using reflection instead of an interface. A Method is a function object. But it's not type-safe to use. An interface can do the same without those problems.
interface Operation {
double evaluate(double a, double b);
}
Then put objects that implement the interface in your map:
ops.put("+", new Operation() {
public double evaluate(double a, double b) {
return a+b;
});
and you can do
double result = getMethodFromKey(ops, operator).evaluate(numOne, numTwo);
The need to cast is gone.

If you're sure that all of your operations are going to be on a single class (no extensibility), then you should consider using an enum instead. You can add an instance field to the enum to represent the character command corresponding to the operation and then have an abstract evaluate method that's implemented by each enum value.

If invoke() is returning an Object that you know is a double, you can cast it like so:
result = (Double) getMethodFromKey(ops, operator).invoke(o, numOne, numTwo);
Since double is a primitive, which is not of type Object, you need to cast it to a Double, and through unboxing, we get a double.

Related

Method reference and Lambda expression

I´m currently reading through someone else´s code and he has the following two methods:
public static double fac(double d) {
return d <= 0 ? 1 : d * fac(d - 1);
}
public static DoubleUnaryOperator getfun() {
return LamdaTests::fac; // LamdaTests is the classname of this class
}
First of all, i´m currently trying to understand lambda expressions/method references.
I have 2 questions:
1) What does the getFun() method exactly do? It should call the fac(double d) method in this class LambdaTests right? But with which argument and how can the return value be a DoubleUnaryOperator, shouldn´t "LamdaTests:fac" return a double?
2) What would be the equivalent Lamda expression for Lamdatests::fac in this case?
Edit: As far as i know
return LamdaTests::fac;
should be equal to
return x -> fac(x);
But i just dont understand where it gets the argument x from.
getFun doesn't call anything. It just returns a reference to the fac function. You need to call the returned function still to get a result. getFac isn't very useful here, so that may be what's confusing things. In reality, you would just use LamdaTests::fac directly, unless that method was private.
For the latter question, think of it this way:
x -> fac(x)
is a function that takes a double and returns a double. What is fac? It's the same thing: a function that takes a double and returns a double. The argument is just implicit here.

Is there a way to match a String with a method?

As far as I've researched, there's no way to match a String with a variable. probably I'm using the wrong word, here's what I mean by matching:
String grade="a";
double a=4.0;
And there's no way to associate the value of String grade with double a.
Similarly, what I want to do is associating value of a String with a method. Maybe I'm on the wrong track, let me briefly explain what I'm trying to achieve:
In the class player, there's a String name() method that returns This.name. There's no graphical design, and the only way for user to communicate with the program is typing. Basically, when person types name, I want name method to be ran. I'm pretty new, and the only way I can think of doing it is using a bunch of if statements, and adding another if statement for each method I add does not sound right to me.
Note: The reason I need String to be associated is because I'm going to use javax.swing.JTextArea to get input from the user, which returns String.
Thanks in advance
Yes. It's called a Map.
Here's some sample code of how to use one:
Map<String, Double> map = new HashMap<>();
map.put("grade", 4.0);
double a = map.get("grade");
If you want to store a variety of value types use Map<String, Object>, but you'll have to make unsafe casts when retrieving and using the values returned from get().
Java is not a dynamic interpreted language like Python or Perl.
To associate arbitrary strings with values you should use a Map<String,ValueClass> where ValueClass is the value to associate, such as Integer, Float, BigDecimal or your own value class.
Because grades are usually fixed from A to F, I would use an enum to map each grade to a numeric value:
enum Grade {
A(4.0), B(3.0) // etc...
private double val;
private Grade(double val) {
this.val = val;
}
public double getVal() {
return val;
}
}
Then use Grade.A.getVal() when you need the numeric value of the A grade.

Return two Strings from method

I'm a beginner in Java programming, and I'm trying to make a voting machine program, where you can vote for Republicans or Democrats. My question is, how can I edit my method so I would be able to return two strings with two distinct values?
For example, look at my code all the way in the bottom. It's wrong, but I wanted the tester to be able to print out Democrats: (some number) and Republicans: (some number) in one method. How can I do that?
import java.lang.String;
public class VotingMachine1 {
private double Democrats;
private double Republicans;
public VotingMachine1() {
Democrats = 0;
Republicans = 0;
}
public void voteRepublican() {
Republicans = Republicans + 1;
}
public void voteDemocrat() {
Democrats = Democrats + 1;
}
public void clearMachineState() {
Republicans = 0;
Democrats = 0;
}
//this is where I'm having difficulties. I know its wrong
public double getTallies() {
System.out.println("Democrats: ", return Democrats);
System.out.println("Republicans: ", return Republicans);
}
}
No return is necessary there, since you aren't leaving a function. To do what you seem to want to do, just replace that last method with the following:
public void getTallies()
{
System.out.println("Democrats: " + Double.toString(Democrats));
System.out.println("Republicans: " + Double.toString(Republicans));
}
Also, since your votecounts should only ever be integers, there's no reason to declare them as doubles instead of ints.
What you are looking for here is a format string. A format string is used when you know what your output should look like, and only have a few "holes" where unknown data should be filled in. To output your data using format strings, you would use the System.out.format(String, Object...) method:
System.out.format("Democrats: %f\n", Democrats);
System.out.format("Republicans: %f\n", Republicans);
In this case, the %f indicates that a floating-point number (since your variables are declared as double) will be printed instead of the %f. However, you may wish to consider declaring them as int (or long) instead, in which case you would use %d instead of %f in the format strings.
Finally, you ought to change your getTallies() method to return void instead of double, as you are printing the values, not returning them.
Your code and your description are so contradictory, it is not clear that you even know what you are trying to do. I believe that this is the real root of your problems.
Here goes:
public double getTallies()
{
System.out.println("Democrats: ", return Democrats);
System.out.println("Republicans: ", return Republicans);
}
First, your question says that you want to "return two strings with two values" ... but you have declared the method as returning one double.
Next, your code is printing values ... not returning them.
You've also made some major mistakes at the syntactic level, largely (I believe) because you are trying to do contradictory things:
return Republicans is not a valid Java expression, so you can't use it as a argument to the println method.
The println method can't be called with two arguments, as your code is trying to do. There is a zero argument version and a number of one argument overloads ... but no overloads with two or more arguments.
Basically, you need to start by making up your mind about what this method is supposed to do. Is it supposed to:
return the tallies (as two doubles)?
return a string representing the two tallies?
return nothing ... and output the two tallies to standard output?
do something else?
Once you've made up your mind:
code the method to do what you've decided it should do, and
chose a method name that correctly reflects what it is supposed to do. Hint: a method that starts with get is conventionally a "getter" that returns the attribute or attributes themselves ... not a String rendering.
double is a bad choice of type for a vote count too:
You cannot have a fractional vote.
You want to represent vote counts precisely and floating point types (like double) are not precise. (Or at least, not in the sense that you require.)
When you attempt to format or output a double, the resulting character string is likely to include a pesky decimal point ... or worse.
You should use int or long instead of double.
Finally, this is a serious Java style violation, and should get you a significant penalty if your marker is paying attention.
private double Democrats;
private double Republicans;
Variable names in Java should start with a LOWER CASE letter.
A few more random comments:
import java.lang.String; is superfluous as all classes in package java.lang are automatically imported in every Java source file.
Votes can not be fractional. People can't vote 0.75 candidate A, and 0.25 candidate B. If you use integer datatypes (int or long), you will be reflecting this fact better. Also, you will be saving yourself a lot of headache when you start obtaining results like 379857.999999. This is because floating point types have a better range, but worse precision (especially noticeable when working with pure integers).
According to Java usual naming conventions, variable names should start with a lowecase letter.
A better name for function getTallies is printTallies.
For output purposes, it's much better to use string formatting than concatenation. Some advantages are: multiple formats supported, ease of use, and internationalization.
Putting all together:
private int democratVotes;
private int republicanVotes;
public void printTallies() {
System.out.format("Democrats: %,d%n",democratVotes);
System.out.format("Republicans: %,d%n",republicanVotes);
}
In this particular case, votes will be printed with thousand separation (ex: 3,345,623 instead of 3345623). Check Java's Formatting Numeric Print Output tutorial.
Thinking better about it, there are some alternatives where getTallies would effectively be returning some form of value:
1) Make it to return a String with both tallies. It would be hard and inefficient to separate the tallies later, though.
public String getTallies() {
return "Democrats: %,d votes. Republicans: %,d votes.%n".format(democratVotes,republicanVotes);
}
2) Make it to return an array.
public int[] getTallies() {
return new int[2]{ democratVotes, republicanVotes };
}
public int[] getTallies1() { // Same as getTallies, but written step by step.
int[] result= new int[2] ;
result[0]= democratVotes ;
result[1]= republicanVotes ;
return result ;
}
3) Make it to return a class.
public VotingMachineResults getTallies() {
return VotingMachineResults(democratVotes,republicanVotes) ;
}
public static class VotingMachineResults {
private int democratVotes;
private int republicanVotes;
public VotingMachineResults(democratVotes,republicanVotes) {
this.democratVotes= democratVotes ; // `this` required to disambiguate field democratVotes from parameter democratVotes.
this.republicanVotes= republicanVotes ;
}
public int getDemocratVotes() {
return democratVotes ;
}
public int getRepublicanVotes() {
return republicanVotes ;
}
}
As you can see, this class is very similar to VotingMachine1, but it does not accept internal state changes. It is a "value" class.
In Java, you concatenate Strings with the + operator. Proper syntax for what you were trying to do looks like this:
System.out.println("Democrats: " + Democrats);
System.out.println("Republicans: " + Republicans);
A return statement is only used when you want to return some object or value to a method that called your current method. It is not appropriate in this place since you're only passing a value to another method (println()).
ALSO, you need to fix your getTallies() method. Make it return void instead of double since you aren't returning anything.
Here's something completely different: why not override toString()?
Presumably, any instance of VotingMachine1 will apply for all votes that you care about for that instance. That is to say, you don't create a new instance of a VotingMachine1 every time someone casts a vote.
So, what you can do is override the toString() method. We'll also use String.format() to handle the numerical values.
#Override
public String toString() {
// assumes that Democrats and Republicans are declared as int
// since it's pointless to indicate percentages of a vote
return String.format("Democrats: %d\nRepublicans: %d", Democrats, Republicans);
}
Now, whenever you vote, you can use the toString() method to get the information (which is called whenever one does System.out.println(object).
VotingMachine1 voter = new VotingMachine1();
voter.voteDemocrat();
voter.voteRepublican();
System.out.println(voter);
/* This prints:
Democrats: 1
Republicans: 1
*/
A less specific answer to your question would be to return an Object called (say) Votes
public class Vote {
int democratVotes
int republicanVotes
}
and then make your VotingMachine class simply return an instance of this object (suitably changed to make it immutable).
On my project we have created a generic version of this called a Tuple that returns a pair of values in a single object - it has an overloaded toString method for easy printing.
you can return an array with [0] and [1] as key and devide it on the basis of your need..
like
returnArray[0]="first string";
returnArray[1]="second string";
and use it ur way...

Where do you put the parentheses to concisely convert a casted object to a primitive type without auto-unboxing?

With autounboxing, this statement will automatically work:
int myPrimitive = (Integer) doIt();
But if I want to explicitly convert from an Integer to an int here in a single line, where do I have to put the parentheses?
You could do this :
int myPrimitive = (int) (Integer) doIt();
But as you said, auto-unboxing will get that for you.
A bad example to show that chain casts work (don't ever use this code) :
Map notReallyAMap = (Map) (Object) new String();
The thing with chain casts, is that wherever you use it, either the cast is legit, and you can remove intermediaries; or the cast will simply cause a ClassCastException. So you should never use it.
Either the compiler unboxes the Integer for you, or you do it yourself - this cannot be avoided.
So you need to either do
int myPrimitive = ((Integer) doIt()).intValue();
or more simply, change doIt() to return an int since you seem to want to deal with ints rather than (null-able) Integers.

Java- Identifying ints and doubles

I want to write a conditional statement, depending on whether a variable is an int or double, i.e
if (x is a double)
do stuff
else if(x is an int)
do stuff
else
do stuff
I know this might not be a good idea, but its my only choice for now. Is this possible?
I have no idea how x could be an int or a double without you knowing at compile time, but
void dostuff(int x) {
do stuff...
}
void dostuff(double x) {
do stuff...
}
then
dostuff(x)
will call the appropriate method.
Edited to add:I don't think this question is really what you want, based on your comment to the original question. I'll post a comment on the other question to try and offer some assistance to yoru real issue.
As Bill the Lizard says, you'll know at compile time what type a primitive is:
public void foo(int x, double y){...}
On the other hand, if you're putting your types inside another object, like
Vector v = new Vector();
v.add((int)1);
v.add((double)1.0));
then you're really dealing with objects not primitives. Each primitive has a corresponding class:
int has Integer
double has Double
float has Float
boolean has Boolean
etc.
You can use the instanceof keyword to determine what type you're dealing with (you can do this with any class):
if( x instanceof Double ) {
doDoubleThing();
} else if( x instanceof Integer ) {
doIntegerThing();
} // and so on
I'm guessing you're trying to check if a number has a decimal part or not.
double n;
if(n-floor(n)>0)
it has a decimal part
else
it's an integer
What atk wrote is valid if you have the ability to use two methods. If this isn't an option or you don't want to do this (personally think it might be more readable and less repetitious to have one method and just do an if-else branch, depends on your code), you can use reflection:
Class intClass = Integer.class;
Class doubleClass = Double.class;
if intClass.isInstance(foo)
bar();
else if doubleClass.isInstance(foo)
spam();
else
eggs();
This might not necessarily be the best solution. Just thought you should know about it.

Categories