Recursive Descent Parser - Adding Unitialized Variables - java

So, I have a recursive descent parser that analyzes a mathematical expression in infix. The expression is tokenized, parsed with the aforementioned parser, which generates an AST on the fly (with nodes for each type of expression) and evaluates the final value. I am handling all of these values as doubles; so, I use this parser like so:
Parser parser = new Parser();
try {
ExpressionNode expression = parser.parse("5 + 4*cos(pi)");
System.out.println("The value of the expression is "
+ expression.getValue());
} catch (ParserException | EvaluationException e) {
System.out.println(e.getMessage());
}
}
With Exceptions I defined myself.
The line expression.getValue() returns a double, and the way my parser works is that every expression node returns a double, so each branch is evaluated bottom up, until it finally ends up at one double answer.
The thing is, I want to handle unitialized variables in my expressions, like so if I wanted to parse 5 + x (where x is not initialized prior) the expression's value would return 5 + x.
Would I have to change my expression node's getValue() return type to a String? I feel like that would complicate and bloat the program, and there must be a better way to accomplish this. Does anyone have any experience with this type of thing?
I know the description of my parser might have been a little vague, so this is where I learned how to implement most of it.

I assume in your expression tree you have classes defined for operators and constants. You will need to define a new class for variables.
You will then need to add a method like getAllVariables which can return all variables below any point in the tree.
The I suggest you change getValue to accept a Map<String, Double> to provide values for any variables at evaluation time. This will need to be ignored by all nodes other than variables which will return their own value from the map. If they don't find a mapping for themselves as a key they should throw an EvaluationException.
Finally if you want to be able to print out the expression as a string then that's really a separate method to your getValue. Perhaps getExpressionText. Then each class can override this to return a String representing the expression from that point down with the variables just returning the variable name.
So now once you've parsed your expression you can get all variables, prompt the user for values for them, evaluate the expression for given values (catching the exception if any are undefined) and print it out again.
ExpressionNode expression = Parser.parse("x + 5 * y");
System.out.println(expression.getExpressionText());
System.out.println(expression.getAllVariables());
Map<String, Double> variableValues = new TreeMap<>();
variableValues.put("x", 4);
variableValues.put("y", -2);
System.out.println("Evaluates to " + expression.getValue(variableValues));
I would expect your Variable class to end up looking something like:
public class Variable implements ExpressionNode {
private final String name;
public double getValue(Map<String, Double> variableValues) {
if (variableValues.containsKey(name)) {
return variableValues.get(name);
} else {
throw new EvaluationException(name + " is undefined");
}
}
public String getExpressionText() {
return name;
}
public List<String> getAllVariables() {
return Arrays.asList(name);
}
}
Another common operation you might want to perform on an expression tree is to simplify it. That essentially means to evaluate to a constant anything that can be evaluated. In my view the best way to do this is to return a new simplified tree rather than changing the current tree. So I recommend adding a new method to ExpressionNode:
public ExpressionNode simplify();
For variables and constants this would just return this. For operators it needs to do something more complicated. Something like:
class Operator implements ExpressionNode {
public ExpressionNode simplify() {
if (getAllVariables().isEmpty()) {
return new Constant(getValue());
} else {
Operator simplified = new Operator(operation);
for (ExpressionNode operand: operands) {
simplified.addOperand(operand.simplify());
}
return simplified;
}
}
Hopefully you see what that does. If the operation can be completely evaluated then it's converted to a constant. Otherwise it remains an operation but each of its operands is simplified in turn.
So now if you want to simplify an expression you can do:
System.out.println(Parser.parse("7 * 2 + x * 3").simplify().getExpressionText());
Which will return "14 + x * 3".
If you then want to get even more sophisticated you can build awareness of association and distribution into your operators and change simplify so that it reorganises the tree to group variables. But I believe that's a bit beyond the scope of this question!

Related

How do you use a lambda expresion with complex math in java [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
hello i a trying to compare to values after i apply a lambda experrsion to them im trying to compare a location of a player and another to see the distance between them and im having trouble with lambdas
public class mathprob {
public static void main(String[] args) {
}
Location loc = player.getlocation();
Location newloc = player.getlocation();
(loc, newloc) -> Math.pow((loc.getX()-newloc.getX()), 2) +
Math.pow(loc.getY()-newloc.getY(), 2)+Math.pow(loc.getZ()-
newloc.getZ(),
2));
}
i keep getting a error because the lambda is incorrect i dont know how to use a lambda in this situation and then comparing the two values to each other (loc, newloc) the two values or two points P1(loc.getX(), loc,getY(), loc.getZ()) and P2(newloc.getX(), newloc.getY(), newloc.getZ()) i wanna compare the x and the y and the z of each point to see the number gap between them
Lambdas are just a way to create a type for a function. Keep in mind that a function has no "values" and hasn't been executed yet.
You can apply any Lambda to a set of values by calling it's apply method. It will then take the inputs (parameters to apply) and return the value as the result. A Lambda for a function that looks like this
(Coordinate x) -> { return new Distance(Math.sqrt(x.x * x.x + x.y * x.y)) }
would return the distance to the origin for a Coordinate assuming a Coordinate looked a little like
public class Coordinate {
public double x;
public double y;
}
and Distance looked a bit like like
public class Distance {
public Distance(double value) {
... whatever the implementation is ...
}
}
This function has a type conversion in it, it takes a Coordinate and returns a Distance. This means it fits the java "interface" of
Function<Coordinate, Distance>
and just by writing this Lambda
(Coordinate x) -> { return new Distance(Math.sqrt(x.x * x.x + x.y * x.y)) }
The Java compiler will generate some unnamed class of type Function<Coordinate, Distance> and instantiate an instance (create an object the class) to use in the context of the location of the Lambda.
Now if that lambda is within a method of a stream, such that the stream's parameter types are compatible, the stream will (in some manner) call apply on each value the stream is handling. Those values come from a Supplier which is basically an object that has a T get() method.
Stream calls the Supplier's get() method.
Stream has a method .forEach( ... ) containing a lambda that consumes the get() type.
Stream applies the value of get() to the lambda in forEach() by passing it into apply(value).
Stream collects the result of apply(value)
Stream returns from the .forEach(...) method a new stream with values typed to match the return value of the lambda in the forEach() method.
Eventually, these values are passed into a Collector method which combines values into some sort of buffer. Sometimes a List, sometimes a single value.
Conveniences exist for various ways of simplifying the collectors. Conveniences exist for generating values without coding suppliers.
The lambda syntax itself is a convenience for not having to write an implementation of one of the "xxxFunction" interfaces, create an object of it, and pass it into the stream.
Predicates are what they call Functions that return boolean values. There are even more convenience functions that work with predicates.
So, if you don't have a collection of data points to process, you probably shouldn't be using lambdas. If you do have a collection of data points to process, then keep in mind that streams and lambdas provide a new not-quite-like-a-loop way of processing them. They are guaranteed to be applied to all values, but the order of their application is not necessarily in the strong ordering that a traditional loop would apply. With the right options, you can effectively split the input into multiple chunks (spliterator vs iterator) and process the data in parallel.
Now that you have a quick overview of Lambdas, Streams, and the Functional interfaces, you can see that
(loc, newloc) -> Math.pow((loc.getX()-newloc.getX()), 2) +
Math.pow(loc.getY()-newloc.getY(), 2)+Math.pow(loc.getZ()-newloc.getZ(),
2));
wouldn't "do" anything, because at best it describes this
public class MyFunction implements Function<Location, Location, Double> {
Double apply(Location first, Location second) {
return Math.pow((first.getX()-second.getX()), 2)
+ Math.pow(first.getY()-second.getY(), 2)
+ Math.pow(first.getZ()-second.getZ(), 2)
}
}
MyFunction myFunc = new MyFunction();
Which has the following problem"
It's a coding error as it's only creating the facility to transform locations, and never using it.
Using the facility would look like
double result = myFunc.apply(loc, newloc);
Now, the very astute readers will mention auto-boxing, but in reality the compiler would choose the ToDoubleBiFunction type, probably side-stepping some of the possible auto-boxing issues. I just didn't want to write the example up in the non-generic manner, as again, the primitive functional types are a convenience (and optimization) of the general "all object" description above.
Lambda expressions are used to generate anonymous functions. They can be used where a #FunctionalInterface is expected.
Read more about them here: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
If you'd like your code to work you can assign your lambda to a BiFunction variable and then execute it passing in the loc and newloc.
public class mathprob {
public static void main(String[] args) {
Location _loc = player.getlocation();
Location _newloc = player.getlocation();
BiFunction<Location, Location, Double> lambdaExpression = (loc, newloc) -> {
return Math.pow((loc.getX()-newloc.getX()), 2) +
Math.pow(loc.getY()-newloc.getY(), 2)+Math.pow(loc.getZ()-newloc.getZ(),
2);
};
double result = lambdaExpression.apply(_loc, _newloc);
}
}
Here is an example of how the equivalent method declaration would look like instead of using a lambda:
public class mathprob {
public static void main(String[] args) {
Location loc = player.getlocation();
Location newloc = player.getlocation();
double result = calculate(loc, newloc);
}
public static double calculate(Location loc, Location newloc) {
return
Math.pow((loc.getX() - newloc.getX()), 2) +
Math.pow(loc.getY() - newloc.getY(), 2) +
Math.pow(loc.getZ() - newloc.getZ(), 2);
}
}
Read the 14.5. Statements from JLS.
value;
is not a valid statement, as
"text"; or 5; are not.
Lambda Expression is a value, which constitutes an anonymous method, and which can be assigned to the variable (of Functional Interface type) or can be passed into method, as an ordinary argument value.
public void someMethod() {
5; //does not compile, as this is not a statement.
int x = 5; //compiles, as this is a statement.
//Similarly,
() -> System.out.println("Hi"); //does not compile, as this is not a statement
Runnable r1 = () -> System.out.println("Hi"); //compiles, as this is a statement
}

Do you have to store the value returned by conditional operator in java

I have a method , where I am doing a conditional operation.
But I get a compilation error.
public void hello(){
int x=15;
x==15 ?"Hi":"Bye";
}
If I edit the line and put something mentioned below , the error goes away:
String salutation=x==15 ?"Hi":"Bye;
My question is --is it mandatory to assign the value being returned by a conditional operator to a variable?
x==15 ? "Hi" : "Bye; just floating around does nothing; it's a pure expression. It's like just writing "Hi" in the middle of your code. You need to assign it to a variable for it to actually effect anything.
So yes, it's mandatory in the sense that if you want the ternary to do something, you must assign the result; providing no part of ternary (the condition, and both of the clauses) carries out side effects.
Do you have to store the value returned by conditional operator in
java
Not necessarily, but to simplify you cannot declare it without using it.
You may for example assign it to a variable as you did :
String salutation=x==15 ?"Hi":"Bye;
But you are not forced to store the value in a local variable.
You have other ways to use it.
You may for example pass it as a parameter that waits for a String :
myMethod(x==15 ?"Hi":"Bye");
public void myMethod(String string) {... }
Or you can still use it to apply a method on :
if ((x==15 ?"Hi":"Bye").equals("Bye")){
...
}
You are getting an error because you are not assigning the value based on the condition. Assigning a single variable to one of two states based on a single condition is such a common use of if-else that a shortcut has been devised for it, the conditional operator, ?:. you can't use the shorthand form ?: if the condition doesn't return any value. Your example can be rewritten
public void hello(){
int x = 15;
String salutation;
if (x == 15){
salutation = "Hi";
}else
salutation = "Bye;
}
Using the conditional operator we can rewrite the above example in a single line like this:
public void hello(){
int x = 15;
String salutation = x==15 ?"Hi":"Bye;
}

Quick conditional without return value Java [duplicate]

I was wondering if it was possible to do a ternary operation but without returning anything.
If it's not possible in Java is it possible in other languages, if so which ones apply?
name.isChecked() ? name.setChecked(true):name.setChecked(false);
No, you can't. But what's the point of this over an if-else statement? Are you really trying to save 7 characters?
if (name.isChecked()) {
name.setChecked(true);
} else {
name.setChecked(false);
}
or if you prefer bad style:
if (name.isChecked()) name.setChecked(true); else name.setChecked(false);
Never mind the fact that you can just do (in this case):
name.setChecked(name.isChecked());
The point of the ternary or "conditional" operator is to introduce conditionals into an expression. In other words, this:
int max = a > b ? a : b;
is meant to be shorthand for this:
int max;
if ( a > b ) {
max = a;
} else {
max = b;
}
If there is no value being produced, the conditional operator is not a shortcut.
I was wondering if it was possible to do a ternary operation but without returning anything.
No it is not possible:
The 2nd and 3rd operands are required to be non-void expressions; i.e. they must produce some actual value.
"It is a compile-time error for either the second or the third operand expression to be an invocation of a void method." - JLS 15.25.
A ternary expression is an expression, and cannot be used as a statement.
"Certain kinds of expressions may be used as statements by following them with semicolons." ... and the ternary expression is not one of those kinds - JLS 14.8.
If you really, really want to use a ternary expression but not use the value of the expression, then the simplest thing is to assign the value to a dummy variable, and add an annotation to suppress the warning about the variable not being used.
But a better idea is to use a plain if statement.
If it's not possible in Java is it possible in other languages, if so which ones apply?
I'm a bit rusty, but I believe that C, C++ and Perl all allow arbitrary expressions to be used in places where their values are not used.
Sometimes, you can use ternary operation on method arguments to solve your request.
name.setChecked(name.isChecked() ? true : false);
By the way, the best solution for your problem is
name.setChecked(name.isChecked());
I assume the use case in the question is just a poor example because it's equivalent to the following statement:
name.setChecked(name.isChecked());
... which doesn't make sense either. But the intent is clear and there are indeed many relevant use cases.
The only viable and general solution is adding a helper method like this:
static void ternaryVoid(boolean condition, Runnable ifTrue, Runnable ifFalse) {
(condition ? ifTrue : ifFalse).run();
}
and using it like this:
ternaryVoid(name.isChecked(), () -> name.setChecked(true), () -> name.setChecked(false));
But it loses the elegance of ternary operator and worth the 'effort' only if used by multiple parts of the code and only if nanoseconds don't matter.
But what's the point of this over an if-else statement? Are you really trying to save 7 characters?
I'm surprised that such statements appear in a form of rhetorical questions. Yes, saving 4 lines and making the code more elegant is important, especially in the context of functional programming.
Moreover, it's at least arguable whether void methods return a complete Void. Essentially, they return a notification of a completed task. This is why logically, ternary expression makes sense equally regardless of whether it returns something or nothing:
condition ? doThis() : doThat();
Here is a real world example of a class which may process millions of incremental updates per second:
public class DataHandler {
private final TreeMap<Integer, Long> tree = new TreeMap<>();
public void onUpdate(int price, long amount) {
if (amount == 0) {
tree.remove(price);
} else {
tree.put(price, amount);
}
}
}
If allowed, the onUpdate() method would be a nice ternary expression like this:
public void onUpdate(int price, long amount) {
(amount == 0) ? tree.remove(price) : tree.put(price, amount); // compilation error
}
Fortunately, in some cases like this, both target methods return values, and these values are of the same type, which is Long in this case. This allows either to make the onUpdate method to return the previous amount at price (which is even useful)
public Long onUpdate(int price, long amount) {
return (amount == 0) ? tree.remove(price) : tree.put(price, amount);
}
... or alternatively (e.g. in case the method is determined by an interface), to use a dummy variable and suppress its uselessness warning:
public void onUpdate(int price, long amount) {
#SuppressWarnings("unused")
Long dummy = (amount == 0) ? tree.remove(price) : tree.put(price, amount);
}
Otherwise, these solutions are not applicable, and as answered by others, doesn't exist. For instance, one may try the following:
Consumer<Void> dummy = (x) -> {};
dummy.accept(/*...*/);
but interestingly, the second line compiles with neither anything nor nothing as an argument.
It seems the best general solution is the above helper method ternaryVoid().
You have to return some value and it will not work if you want it to act like a void method which performs some action without a returning a value.
Hope this helps...
In java following code isn't possible:
(your-condition) ? (true-statements) : (false-statements)
for sample you can't compile following snipet code :
(1==1) ? System.out.println("") : System.out.println("");
you achieve following compilation error:
The left-hand side of an assignment must be a variable

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...

In Java, How do I return a String or a double depending on the circumstance of the method? Is it possible?

For example, I have a method that looks through a string for data separated by a specified deliminator, but some items might be a names, and other items might be numbers.
If a user calls my method to return item number X from the deliminated list, i want it to return a string if item X is a name, or a double if item X is a number.
For example, objectName.get(5); would get the 5th item in the deliminated list.
Would I have to use some type of overloading for this?
Or would I have to instead do something like objectName.getDouble(5); and objectName.getString(5); based on the fact that the user knows what item 5 is?
But what if the user doesn't know what item 5 is? He just needs a String or a Double depending on what it happens to be.
Here's one way to do this:
public Object get() {
if (blueMoon) {
return new Double(42.0);
} else {
return "fred";
}
}
Note that this will return a Double wrapper rather than a double.
I don't think this is a good idea though, since the caller now has to test the type of the returned value and do a typecast to do something with it.
For the record, Java does not allow a method to return a String or double because these types do not have a common supertype in the Java type system.
For this sort of thing, I prefer to use something akin to the Maybe/Option pattern from the functional programming camp. You end up with an interface like:
public abstract class DoubleOrString
{
// Constraint isDouble() xor isString()
public boolean isDouble();
public boolean isString();
//Must throw iff !isString()
public String getString();
//Must throw iff !ifDouble()
public Double getDouble();
public static DoubleOrString wrap(final double wrapMe)
{
return new DoubleOrString()
{
public boolean isDouble() {return true;}
public boolean isString() {return false;}
public Double getDouble() {return wrapMe;}
public String getString() {throw new RuntimeException();}
};
}
//same for wrap(String)
}
This forces the issue for clients, in that there is always a sanity check that there was indeed a double or String at the appropriate time. In your case, I'd make just one get() method, so when the client (thinks they) knows what the type is, the call is
objectName.get(5).getString();
and in your get(int) method, rather than returning a String or a double, the return statement looks like
DoubleOrString.wrap(theThingToReturn)
It's a little extra work up front, but it has paid of for me several times in the past.
Here's how you'd use it to build one (warning - this hasn't been near a compiler)
public static DoubleOrString parseADoubleOrString(String input) {
try {
return DoubleOrString.wrap(Integer.parseInt(input))
} catch (NumberFormatException nfe) {
return DoubleOrString.wrap(input);
}
}
and here's what the client looks like
String input = //get the input from the user somehow
DoubleOrString parsed = parseADoubleOrString(input);
if (parsed.isDouble())
aFunctionThatTakesADouble(parsed.getDouble());
else
aFunctionThatTakesAString(parsed.getString());
If you need to do this then there is problem with your design. Since the original datasource is String you have to accept that all returned values will be string and leave it to the client to check whether the result can be converted to a number.
If you want to save the client from doing the check, you can provide him with a minimal API which may look something like:
public class ValueExtractor {
public ValueExtractor(String delimitedText) {
// ...
}
/**
* Determines whether there is a next element
* to be returned
*/
public boolean next() {
// ...
}
public String get() {
// ...
}
/**
* Returns the value as a Double if possible
* null otherwise.
*/
public Double getPossibleDouble() {
// ...
}
}
The Java language does not expose an overload on the return type of a method. (As Thilo pointed out, this is a restriction of the Java language and not the JVM/bytecode.)
Generally this type of thing does not fit well into the Java type system. One could imagine returning an Either<String,Double> type (a more restricted return type than Object as suggested by Stephen C and a more general type than DoubleOrString as pointed out by B. Bear), but the general effort required to use such a construct in Java generally results in simply having multiple methods, e.g. getString(...) and getDouble(...).

Categories