Evaluating user input using StringTokenizer while utilizing custom checked exceptions - java

I've been working on a java project for the last couple days, and while things have gone smoothly to this point, I have hit a bit of a snag.
The point of the project is to create a query of sorts, where the user searches for a report using a GUI interface and the app spits out all related data.
Ex: report all where quality > 3
I use a StringTokenizer object to break the String down and evaluate each token. The first token MUST be report, the second token MUST be all, third token MUST be where, the fourth token MUST be either quality, basePrice or numInStock, the fifth token MUST be a relational operator(> < <= >= ==). We were instructed to throw custom checked exceptions if any of the tokens do not match what they should be. So far I have evaluated each token, and throw an Exception if the expected token is not what it should be.
Now once I reach the relational operator, i'm supposed to dump it into a new String called optok. The problem is, I can't seem to get my program to do this and i'm having a hard time figuring out how to do so. I've tried many different things and nothing seems to work.
The final goal is, once all the tokens have been evaluated and checked, to call a method to print the correct query and all data that goes along with said query. If one of the tokens doesn't match, an Exception is thrown.
Here is my code for evaluating each token, to check that it is in the correct format:
public void detectUserInput(String input) throws MissingInputException
{
if (input.equals(""))
{
System.out.println("Null input");
throw new MissingInputException();
}
else
{
System.out.println("Input is not null");
}
}//end detectUserInput
public void countTokens(String input) throws IncorrectFormatException
{
StringTokenizer tokenLength = new StringTokenizer(input, " ,");
if (tokenLength.countTokens() < 6)
{
throw new IncorrectFormatException();
}
}//end countTokens
public void evaluateTokens(String input) throws IllegalStartOfQueryException,
InvalidSelectorException,
InvalidQualifierException,
InvalidLValueException,
InvalidOperatorException
{
StringTokenizer testTokens = new StringTokenizer(input, " ,");
if (!testTokens.nextToken().equalsIgnoreCase("report"))
{
throw new IllegalStartOfQueryException();
}
else if (!testTokens.nextToken().equalsIgnoreCase("all"))
{
throw new InvalidSelectorException();
}
else if (!testTokens.nextToken().equalsIgnoreCase("where"))
{
throw new InvalidQualifierException();
}
else if (!testTokens.nextToken().matches("quality|numInStock|basePrice"))
{
throw new InvalidLValueException();
}
else if (!testTokens.nextToken().matches(">|<|>=|<=|=="))
{
throw new InvalidOperatorException();
}
//here is where I try to take the relational operator
//and dump it into optok, after all the previous input
//has been validated, but it doesnt work :(
while (testTokens.hasMoreTokens())
{
tok = testTokens.nextToken();
if (tok.matches("<|>|>=|<=|=="))
{
optok = tok;
}
}
}//end evaluateTokens
And here is the actionPerformed() of my program that reacts when the user types their query into the TextField and presses the GO! JButton :
private class ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent ev)
{
if (ev.getSource() == goBtn)
{
input = queryFld.getText();
try
{
detectUserInput(input);
countTokens(input);
evaluateTokens(input);
}
catch (MissingInputException mie)
{
errorFld.setText("Enter an expression");
queryFld.setText("");
System.err.println(mie);
mie.printStackTrace();
}
catch (IncorrectFormatException ife)
{
errorFld.setText("Too few terms");
queryFld.setText("");
System.err.println(ife);
ife.printStackTrace();
}
catch (IllegalStartOfQueryException isqe)
{
errorFld.setText("Word REPORT expected");
queryFld.setText("");
System.err.println(isqe);
isqe.printStackTrace();
}
catch (InvalidSelectorException ise)
{
errorFld.setText("Selector must be ALL");
queryFld.setText("");
System.err.println(ise);
ise.printStackTrace();
}
catch (InvalidQualifierException iqe)
{
errorFld.setText("Qualifier error - keyword WHERE missing");
queryFld.setText("");
System.err.println(iqe);
iqe.printStackTrace();
}
catch (InvalidLValueException ilve)
{
errorFld.setText("Invalid query. quality, numInStock, "
+ "or basePrice expected");
queryFld.setText("");
System.err.println(ilve);
ilve.printStackTrace();
}
catch (InvalidOperatorException ioe)
{
errorFld.setText("InvalidOperatorException. < <= > >= == expected");
queryFld.setText("");
System.err.println(ioe);
ioe.printStackTrace();
}
}
}//end actionPerformed
}//end ButtonHandler
I apologize if this seems trivial, but i'm having a really hard time figuring it out for some reason. I appreciate any input or suggestions. If i'm missing any info needed please let me know and i'll add it asap. Also, here are the instructions for this segment:
11) Now, focus on the evaluateAll method. Get the next token. It should be any one of 3 words:
“basePrice” or “quality” or “numInStock” . If it is not, place the message “Invalid query, quality, numInStock or basePrice expected. If is one of those 3 words, you expect a relational operator, so get the next token, but save it in a new String, call it optok. If it is not a correct operator, place the message “invalid query,
You now have two Strings: token which is either “basePrice” or “quality” or “numInStock” and an optok which is one of the 5 relational operators listed above.
Thanks in advance :)

You didn't post a stacktrace, so I'm guessing you're not having an exception, and reading from your code I'm trying to understand what could be happening .. so I might be wrong.
It seems to me that you are using a tokenizer. A tokenizer is like a stream, once you call nextToken() it returns the token, and unless you save it somewhere the next call to nextToken() will make the previous one not accessible.
So, where you make :
else if (!testTokens.nextToken().matches("quality|numInStock|basePrice"))
{
throw new InvalidLValueException();
}
else if (!testTokens.nextToken().matches(">|<|>=|<=|=="))
{
throw new InvalidOperatorException();
}
You are consuming the tokens. As a result, when you get to the while :
while (testTokens.hasMoreTokens()) {
All the tokens are consumed, so it will not iterate here.
You should instead save your tokens in variables, so that you can both check and the use them :
StringTokenizer testTokens = new StringTokenizer(input, " ,");
if (!testTokens.nextToken().equalsIgnoreCase("report"))
{
throw new IllegalStartOfQueryException();
}
else if (!testTokens.nextToken().equalsIgnoreCase("all"))
{
throw new InvalidSelectorException();
}
else if (!testTokens.nextToken().equalsIgnoreCase("where"))
{
throw new InvalidQualifierException();
}
// TODO here i use local variables, since you need to use these outside this method,
// maybe use class fields or whatever else
String subject = testTokens.nextToken();
String opttok = testTokens.nextToken();
if (!subject.matches("quality|numInStock|basePrice"))
{
throw new InvalidLValueException();
}
else if (!opttok.matches(">|<|>=|<=|=="))
{
throw new InvalidOperatorException();
}
// done, now you have opttok and subject

Related

Is it possible to make a catch block that waits until the whole try block is executed?

What I'm doing
I'm trying to make a cleaner version of nested try catch blocks and I'm solving a very basic exception problem while doing so. I'm making a calculator that will do great things. Before then however, it must take in user inputs as strings and convert them to either floats or integers. I'm doing this by simply calling the in built parseInt and parseFloat functions of java. Right now I'm using a nested try catch block to do this:
String stringToParse = "1.0"
try{Integer.parseInt(stringToParse);}
catch(NumberFormatException n){
try{Float.parseFloat(stringToParse);}
catch(NumberFormatException n){
System.out.println(n)
}
}
Why is that a problem?
This is messy to me and I'd rather have a try block that collects the errors but doesn't immediately go to the catch block, rather it executes the entire try and catches any errors after the try has been executed. I've made a runnable example of this myself that shows what I desire:
String num = "1.0";
int i = 0;
ArrayList<Object> listofResults = new ArrayList<>();
ArrayList<Integer> listOfErrorIndices = new ArrayList<>();
try {
listofResults.add(Integer.parseInt(num));
i++;
listofResults.add(Float.parseFloat(num));
i++;
listofResults.add(Integer.parseInt(num));
} catch (NumberFormatException n) {
listOfErrorIndices.add(i);
}
for (Integer element:listOfErrorIndices) {
System.out.println(element);
//this currently prints out 0 and I want it to print out both 0 and
//2 so that it catches both errors.
}
My idea of how to solve the problem/What I've tried otherwise
My plan is to gather a list of all the NumberFormatException indices (i) thrown in the try. Each time I try to parse the string, an element is added to the resultsList. My goal is to then use this theoretical try catch block to obtain the indices of all the exceptions and then remove them from the resultsList if they threw an error. TLDR; Right now the above code prints out 0 and I want it to print out 0 and 2. Basically, Instead of having nested try catch blocks I use list comprehension and Exception handling indicies with i to remove the error results and only keep the good ones. I don't know if this is possible hence this question. I've looked at the "better ways to implement nested try catch blocks" question however it wasn't useful to me because It provided a solution in delphi and I didn't understand exactly how it worked or if it even worked the way I want mine to work. I at first thought the finally block might be what I needed but that only runs after the catch is executed or if there is no exception, after the try. I need something that postpones the catch block untill the try is complete and I can't think of/find anything that does that.
What are you, crazy?
right now you may be asking, what the hell is the point of this? Well imagine if you had the above problem but instead of two ways to parse the string you had 10 or 100. Pretty quickly, exception handling that with nested try catch blocks would be nigh impossible. I've seen solutions where the catch block calls a custom exception method that then at least takes care of the bad formatting. It looked like this:
try{
//bad code
}
catch{
trysomethingelse();
}
trysomethingelse(){
//equally bad code
catch{
//ya done screwed up son
}
}
However I'm not satisfied because it means that you need a million different method names just to potentially handle one error. Imagine the error would always be the same you just need to try 100 different string parsing methods. Its always going to be a numberformatException if you're trying to convert a string to a number so why have a million catch blocks just for the same error? I want to try to do this with one theoretical catch block that specifies one error that happens many times over in the try block.
You build a list/array of parsers, then iterate that list, catching exception for each.
With Java 8 method references, this is real easy. First, define a Parser functional interface that allows exceptions to be thrown:
#FunctionalInterface
public interface Parser {
Object parse(String text) throws Exception;
}
Next, build your array of parsers to try:
Parser[] parsers = {
Integer::valueOf,
Double::valueOf,
BigInteger::new,
BigDecimal::new
};
Finally, try them one at a time:
String text = "45.8";
Object[] results = new Object[parsers.length];
for (int i = 0; i < parsers.length; i++) {
try {
results[i] = parsers[i].parse(text);
} catch (Exception e) {
results[i] = e;
}
}
Now you can go through the results:
for (Object result : results) {
if (result instanceof Exception)
System.out.println("Error: " + result);
else
System.out.println("Parsed as " + result.getClass().getSimpleName() + ": " + result);
}
Output
Error: java.lang.NumberFormatException: For input string: "45.8"
Parsed as Double: 45.8
Error: java.lang.NumberFormatException: For input string: "45.8"
Parsed as BigDecimal: 45.8
Or put the parsed objects and the exceptions into two different lists. Up to you.
You can do something like this:
interface Parser {
Number parse(String);
}
class IntegerParser implements Parser {
#Override
public Number parse(String) {
// implementation here
}
}
class FloatParser implements Parser {
}
List<Parser> parsers = asList(new FloatParser(), new IntegerParser(), ...);
Number result = null;
List<NumberFormatException> exceptions = new ArrayList<>();
for (Parser parser : parsers) {
try {
result = parser.parse(stringToParse);
break;
} catch (NumberFormatException e) {
exceptions.add(e);
}
}
if (result != null) {
// parsed ok with some parser
// probably discard exceptions
} else {
// show exceptions from the list
}
Try this:
public static void test() {
final String num = "1.0";
final ArrayList<Object> listofResults = new ArrayList<>();
final java.util.function.Function<String, ?>[] parseMethods = new java.util.function.Function[3];
parseMethods[0] = Integer::parseInt;
parseMethods[1] = Float::parseFloat;
parseMethods[2] = Integer::parseInt;
int[] badIndeces = IntStream.range(0, parseMethods.length).map(i -> {
try {
listofResults.add(parseMethods[i].apply(num));
return -i-1;
} catch (NumberFormatException exc) {
return i;
}
}).filter(i -> i >= 0).toArray();
for (int element : badIndeces) {
System.out.println(element);
}
}

display exception in JTextField

My code does some arithmetic to convert a binary input to decimal output. I also made an exception class that extends NumberFormatException to throw an error if the input is not a 1 or 0. What I want is to throw the exception to a JTextField.
private void biTodeciActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String binary;
binary = binaryStringText.getText();
int total = 0;
for(int i = 0; i < binary.length(); i++)
{
if (binary.charAt(i) != '0' && binary.charAt(i) != '1')
{
throw new ParseMethods.BinaryNumberFormatException(binary.charAt(i)+" is not"
+" a valid binary input.");
}
else if(binary.charAt(i) == '1'){
total += Math.pow(2, (binary.length()-1)-i );
}
}
deciOut.setText(""+total);
}
Essentially, what you're trying to do won't work. The BinaryNumberFormatException doesn't declare that it throws any exceptions (and assuming you're using NetBeans), you won't be able to (easily) modify it.
You could wrap all you code in a try-catch block within the method, but that's just, well, kind of messy (IMHO)
Instead, what I might do, is create a class which does the conversation, something like...
public static class BinaryConverter {
public static String toDecimal(String binary) throws BinaryNumberFormatException {
//...
}
// Maybe a toBinary method as well...
}
for example. The toDecimal declares the fact that it will throw a BinaryNumberFormatException (although I think some kind of parse exception would be better)
Then in your action performed method, you could do something like...
private void biTodeciActionPerformed(java.awt.event.ActionEvent evt) {
try {
deciOut.setText(BinaryConverter.toDecimal(binaryStringText.getText()));
} catch (BinaryNumberFormatException exp) {
exp.printStackTrace();
deciOut.setText(exp.getMessage());
}
}
which would allow to deal with the operation been successful and unsuccessful in a more succinct manner.
This makes the code more reusable and easier to manager.
As an idea
Print exception directly into textfield in STRING format
deciOut.setText(""+exp);

Error Checking a project in Java

My goal in the below code is to check for input that is longer than two places after the decimal point, then throw an exception. I cant seem to get it correct though. I am trying to use indexOf to get to the decimal point and then I want to check the length of the portion after it. If it is greater than 2 I want it to throw the exception. Anybody have some tips for this situation?
public ChangeJar(final String amount) {
int i = amount.indexOf('.');
String temp = amount.substring(i + 2);
if(temp.length() > 2 ){
throw new IllegalArgumentException("Too many decimal places!");
}
if (amount == null || Double.parseDouble(amount) < 0) {
throw new IllegalArgumentException("amount cannot be null!");
}
double amt;
try {
amt = Double.parseDouble(amount);
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("Invalid entry. Format is 0.00.");
}
amountHelper(amt);
}
I also wanted to know how I could add error checking to this constructor as I dont want null inputs. I get an error when trying to add error checking that says the constructor call must be the first statement in the method.My code for the constructor is:
public ChangeJar(final ChangeJar other){
if(other == null){
throw new IllegalArgumentException("Values cannot be null!");
}
this(other.quarters, other.dimes, other.nickels, other.pennies);
}
All suggestions are appreciated!
As Java does not allow to put any statements before the super or constructor calls in a constructor. Hence you cant do this:
public ChangeJar(final ChangeJar other){
if(other == null){
throw new IllegalArgumentException("Values cannot be null!");
}
this(other.quarters, other.dimes, other.nickels, other.pennies);
}
You may add the check in the constructor that you are calling.

Java - Catching multiple exceptions and Identifying which exception occured

I had some difficulty with the title, wasn't sure how to word it more accurately.
I'm having this issue, I have a several methods which ask the user for 3 Double inputs.
For each input it checks if it's valid (for example if its a positive value), if it's not it throws an IllegalArgumentException. Now I made a Tester class to check if the methods are working properly. It's supposed to catch the exception thrown by the methods and re-ask the user for the input which caused that specific exception.
All 3 methods throw and IllegalArgumentException but the error message is different for each one. Is there anyway (when catching the exception) to see which input cause the error? Here's a sample of my code:
public class account
{
double value;
public account(double initialValue)
{
if (initialValue < 0)
{
throw new IllegalArgumentException("Initial value cannot be negative.");
}
value = initialValue;
}
public add(double addValue)
{
if (addValue < 0)
{
throw new IllegalArgumentException("Added value cannot be negative.");
}
value = value + addValue;
}
}
and the tester class would be something like:
public class accountTester
{
public static void main(String[] args)
{
try
{
double initialValue = Double.parseDouble(JOptionPane.showInputDialog("Enter initial value"));
account acc = new account(initialValue);
double addValue = Double.parseDouble(JOptionPane.showInputDialog("Enter value to add"));
acc.add(addValue);
} catch (Exception e) {
System.out.println("Wrong ammount");
initialValue = Double.parseDouble(JOptionPane.showInputDialog("Re-enter ammount"));
}
}
So what would I have to change in the tester class to throw that code only if the IllegalArgumentException is "Initial value cannot be negative."
Sorry if I made this hard to understand.
EDIT: According to my prof, we're supposed to use do
String error = e.toString;
if (error.contains("Added value cannot be negative.")
{
//DO CODE FOR FIRST ERROR
}
I know this isn't the most proper way of doing it though.
Since you can't match over Strings like you would do in a functional language you have to provide three different kind of objects if you want to be able to distinguish them using the try-catch mechanics.
Or with a simplified approach attach a parameter to the exception so that you can use just a catch clause but you could behave differently. Something like
class MyIllegalArgumentException extends IllegalArgumentException {
public int whichParameter;
public MyIllegalArgumentException(String string, int which) {
super(string);
whichParameter = which;
}
}
now you can:
catch (MyIllegalArgumentException e) {
if (e.whichParameter == 0)
..
else if (e.whichParameter == 1)
..
}
You could also check the string for equality but this would be really not a good design choice, you could also have many try-catch blocks but this is not always possible.
After having expanded your code the solution is easy:
public static void main(String[] args) {
try {
double initialValue = ...
account acc = new account(initialValue);
} catch (IllegalArgumentException e) {
...
}
try {
double addValue = ...
acc.add(addValue);
} catch (Exception e) {
System.out.println("Wrong ammount");
initialValue = Double.parseDouble(JOptionPane.showInputDialog("Re-enter ammount"));
}
}
Surround each method call with its own try/catch block?
In your catch block you should only catch IllegalArgumentException. Then what you can do is invoke the getMessage() function which will enable you to do a very simple String.equals call.

Missing Return Statement

i am attempting to take the value of a textfield and make apply it to a method in order to search a textfile for that value. But in my method i am shown a Missing Return Value error and cannot seem to make it work. below is my code:
submitsearch.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
whatToSearch = searchfield.getText();
result = SearchString(whatToSearch);
}
});
}
public String SearchString(String result)
{
String input;
try{
String details, id, line;
int count;
Scanner housenumber = new Scanner(new File("writeto.txt"));
while(housenumber.hasNext())
{
id = housenumber.next();
line = housenumber.nextLine();
{
if(!housenumber.hasNext())
JOptionPane.showMessageDialog(null,"No Properties with this criteria");
}
if(result.equals(id));
{
JOptionPane.showMessageDialog(null,id + line );
}
}
}
catch(IOException e)
{
System.out.print("File failure");
}
}
}
Addendum:
In SearchString i am hoping to search my textfile for the value entered in my textfield display it in a JOptionPane. Although i now have the return statement when i click search i am shown all of the records in JOptionPanes one by one regardless of whether they match my search
You have declared the function with a return type of String, so it must return a String on all code paths. If you don't need it to return anything, use void instead.
Add a return null; after catch block.
The method signature says that it returns a String. That implies no matter what flow your code takes, the method should return a value. But when an exception happens, there is no return. Hence you must specify a return value in the case when an exception happens

Categories

Resources