Im writing a program for homework where I need to validate user input and then create an object and add it to an array list. i have included just what i think is the relevant code, but im a beginner for sure so let me know if there is something else you need to see.
I have the user enter a string, then check to see if its a double. if its not a double, i throw an exception that i created
try{
price = Double.parseDouble(strPrice);
}
catch(NumberFormatException nfe){
CDException cde = new CDException();
cde.setMessage("Price must be a number,\nCannot create CD");
throw cde;
}
after making sure that it is a number, in my other class i check to make sure it is in the range that i want. (non negative in this case) then create an object with the value
public void setPrice(double newPrice)throws Exception{
if(newPrice >= 0){
this.price = newPrice;
}
else{
CDException cde = new CDException();
cde.setMessage("CD Price cannot be negative,\nCannot create CD");
throw cde;
}
}
so my question is...
is there a way to do this in one step, check both that the user entered a number and that the number is non negative. one other thing is that if the input is blank, that is the instruction to end the input loop.
Well, you could change your code to read:
try {
price = Double.parseDouble(strPrice);
if (price < 0) {
throw new CDException("Can't be negative");
}
} catch (NumberFormatException ex) {
...
}
But the question is whether you'd really like to do that. From a design perspective, it might make more sense to do the "negative" check inside setPrice, rather than doing it as part of the parsing logic.
Having it split out into separate functions is better, in my opinion. You have better separation of concerns, which promotes code reuse. It's a pretty straightforward 'mashup' though, if you insist on combining the functions (which I don't think you should):
public void setPrice(String newPriceStr) throws CDException {
if(newPriceStr == null) throw new CDException("Null value given for price");
double newPrice = -1;
try {
newPrice = Double.valueOf(newPriceStr);
} catch(final NumberFormatException nfe) {
throw new CDException("Price must be a number,\nCannot create CD");
}
if(newPrice >= 0){
this.price = newPrice;
}
else{
throw new CDException("CD Price cannot be negative,\nCannot create CD");
}
}
Note the shortened form for creating and throwing exceptions.
I know this is for homework and this answer might not be accepted by your class instructor, but in the "real world" I would use a validation framework rather than reinvent the wheel, for example the built in one in Java EE 6: http://en.wikipedia.org/wiki/Bean_Validation
Here is a tutorial using them: http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html
Some examples:
public class CD {
#NotNull
#Size(min=1, max=16)
private String CDName;
#Digits(integer=6, fraction=2)
BigDecimal price;
}
Benefits
DRY (don't repeat yourself, e.g. declare validation once)
Readable (it's clear and documented)
Drawbacks
Java EE has some tendency for over complicating things, but it's still a valid choice
Not everyone likes the "Magic" of using annotations and like to see the code in their eyes
I'm sure there are more pros / cons, but that's out of the scope of this answer / question.
Related
The method returns an "Ingredient" object that is constructed from a given line in a recipe txt file. Note: an InvalidIngredientException is like an Ingredient version of an InputMismatchException. This isn't thrown by any of the lines in the given recipe file.
public static Ingredient parseString(String line)
throws InvalidIngredientException {
double quantity = 1;
String measurement = "";
String[] parts = line.split(";");
if (parts.length == 1) {
throw new InvalidIngredientException(EXP_MSG);
}
if (!parts[0].trim().isEmpty()
&& !(Double.parseDouble(parts[0]) == 1)) {
quantity = Double.parseDouble(parts[0].trim());
}
if (!parts[1].trim().isEmpty()) {
measurement = parts[1].trim();
}
return new Ingredient(quantity, measurement, parts[2].trim());
}
A recipe file looks like this:
Cranberry Oatmeal Chews
8; tablespoon; butter
2; tablespoon; oil
1; cup; light brown sugar
1; ; zest of one orange
6; tablespoon; sour cream
2; teaspoon; vanilla
1.5; cup; flour
.5; teaspoon; baking soda
1; teaspoon; cinammon
.5; teaspoon; salt
2; cup; oats
1.5; cup; dried cranberries
.5; cup; walnuts
The method works, but I feel like it could use less code.
What you are trying to do is called "bind CSV row to an object". There are quite a few good libraries for parsing CSV, most mature ones offering the binding functionality as well. Also there are annotation-based code generation enabled frameworks like Lombok or Jackson which make Java one step closer to convenient languages like Scala, by saving you from writing very verbose getters/setters by hand (with a minor complication to the build process, maybe).
And once you use correct search term you will find a plenty of examples. One doing just what I described above is this one, below is a version adjusted to your naming. It is using Jackson.
Object definition with Jackson annotations:
#JsonPropertyOrder({"quantity", "measure", "ingredient"})
public class Ingredient {
public double quantity;
public String measure;
public int ingredient;
}
Invocation code with the Jackson CsvMapper:
List<Ingredient> result = new CsvMapper()
.readerWithTypedSchemaFor(Ingredient.class)
.readValues(csvFile)
.readAll();
There are a few little things that you can do to make your code look better and a increase the performance a bit also.
Change the regex when splitting the line to "\s;\s". This way you avoid the trim() calls multiple times
Use else if...else syntax. This will make your code not only a bit shorter but also easier to read.
I'm not used to Java, so there might be minor errors in this code. Feel free to edit if you see one.
Coming from a C# perspective, I'd make the following changes:
Move the .trim() calls to one place. Here I do that just after splitting the input lines into parts by creating a Stream using of() then calling map (assuming Java 8 or newer).
Remove the lines instantiating default values for quantity and measurement. Because we don't have to trim, we can use the ternary operator to declare and instantiate the variables on the same line.
Don't check if parts[1] is empty. Since "" is the fallback value, it doesn't matter if parts[1] is also "". This also means you don't need the intermediate measurement variable.
public static Ingredient parseString(String line)
throws InvalidIngredientException {
String[] parts = Stream.of(line.split(";")).map(p => p.trim()).toArray();
if (parts.length == 1) {
throw new InvalidIngredientException(EXP_MSG);
}
double quantity = parts[0].isEmpty() ? 1 : Double.parseDouble(parts[0]);
return new Ingredient(quantity, parts[1], parts[2]);
}
You also have the potential to throw errors other than InvalidIngredientException if parts.length == 0 or if parts[0] cannot be parsed to a Double. I'm not sure how strict you're supposed to be when declaring which exceptions your method can throw, but here's a version that should catch any exceptions and only return the InvalidIngredientException you declared.
public static Ingredient parseString(String line)
throws InvalidIngredientException {
try {
String[] parts = Stream.of(line.split(";")).map(p => p.trim()).toArray();
double quantity = parts[0].isEmpty() ? 1 : Double.parseDouble(parts[0]);
return new Ingredient(quantity, parts[1], parts[2]);
}
catch (Exception e) {
throw new InvalidIngredientException(EXP_MSG);
}
}
I am working on a project in my Java class that is using multiple classes as well as GUI (not sure if that info is relevant). My group partner and I have come across an issue though. We have a Validator class, that should validate a "SSN" but we are continuously given the error:
java:146: error: incompatible types: double cannot be converted to boolean
if(Validator.isValidSSN(jTextFieldEmpSSN)){
Now obviously java:146 is the line. the code we have for each class is:
employeeUI class (the one showing the error):
private void jButtonEnterActionPerformed(java.awt.event.ActionEvent evt)
{
Employee e=new Employee();
if(Validator.isValidName(jTextFieldEmpFirst)){
if(Validator.isValidName(jTextFieldEmpLast)){
if(Validator.isValidEmail(jTextFieldEmpEmail)){
if(Validator.isValidSSN(jTextFieldEmpSSN)){
e.setFirstName(jTextFieldEmpFirst.getText());
e.setLastName(jTextFieldEmpLast.getText());
e.setEmailAdd(jTextFieldEmpEmail.getText());
e.setSSN(Integer.parseInt(jTextFieldEmpSSN.getText()));
}}}}
and the Validator class for isValidSSN is:
public static double isValidSSN(JTextField textfield)
{
double number = 0;
boolean inRange = false;
while(!inRange)
{
number = Double.parseDouble(textfield.getText());
if (number >= 100000000 && number <= 999999999)
{
inRange = true;
} else {}
}
return number;
}
We have been beating our head on how to fix this for quite some time, but are coming up at a loss. Are we missing something? we would greatly appreciate any help with this.
If I ask, "Is 123-45-6789" a valid SSN?" you wouldn't reply "123456789.0", would you? You'd give me a yes or a no. By returning double your method is doing the former. It's responding with a number instead of an answer to the question.
A good rule of thumb is that methods starting with is or has should return booleans. "Is this a valid SSN?" is a yes/no question, so isValidSSN should return the programming equivalent of yes/no.
public static boolean isValidSSN(JTextField textfield)
There are a couple of other design points here:
The loop isn't necessary. The SSN is either valid or it isn't.
A text field is not itself an SSN. It holds some text, and that text is the SSN. Rather than taking a text field and looking up the text in the field with getText(), it'd be better to have isValidSSN take the text directly. Let the caller extract the text from the text field.
In broader terms this is known as the single responsibility principle. Every method should ideally do just one thing.
Result:
public static boolean isValidSSN(String ssn) {
double number = Double.parseDouble(ssn);
if (number >= 100000000 && number <= 999999999) {
return true;
}
else {
return false;
}
}
P.S. If I don't mention it someone will surely comment that the if and else blocks aren't necessary; one can return the if result directly. They would be right, though I consider it a bit of an advanced trick. It would look like so:
public static boolean isValidSSN(String ssn) {
double number = Double.parseDouble(ssn);
return number >= 100000000 && number <= 999999999;
}
public void readFile() {
while (x.hasNext()) {
try {
String name = x.next();
int magic = x.nextInt();
int cunning = x.nextInt();
int courage = x.nextInt();
int wisdom = x.nextInt();
int temper = x.nextInt();
Card card = new Card(name, magic, cunning, courage, wisdom, temper);
for(int i=0;i<cardArray.length;i++){
cardArray[card];}
} catch (Exception e) {
}
}
}
I'm just making this code reading attribute from text file. The problem is how to gather all cards in one array? I try but it's not working.
I highly advise you to go thorough the basic tutorial. See the Arrays section and read it carefully.
You should assign the card this way:
cardArray[i] = card;
Note that you're using the same Card object in the loop, you'll end up with array full of the same card. Is this what you want? If not, you should create a new instance on each iteration.
Also please note that it's not a good practice to catch an exception and do nothing with it. The least you should do is print it to the console, otherwise you might get silent errors.
More questions you should ask yourself:
Do you want to declare the variables inside the while loop?
Is it worth to make a custom class that wraps magic, wisdom and all other variables? I think your code will be more modular and readable.
The full tutorial is available here, it's really worth reading. Give it a try!
I've got a bit of an issue with my little program.
I have a JOptionPane asking for a number, and if that number is less than 10, a loop that just continues on and on forever doing what's in it, keeping on asking for numbers. Inside that loop, I call a method, with an int as parameter. In the method, I need to (without altering any of the code in the class that calls the method) find out whether the number I entered is less than 1. If it is, I need to call on another method. That bit's done.
But! The mainloop keeps rolling, so it keeps doing the other stuff in the loop. I need to stop it from doing that, so in the if-statement in the method I need to break that specific iteration of the loop the method is in, and make it go on to a new iteration of the same loop, asking for a new number.
The first class (example):
number=Integer.parseInt( JOptionPane.showInputDialog( "bla bla" ) );
while (number !=- 10) {
themethod(number);
blah
blah
...
}
The called method (example):
public void themethod(int number) {
if (number<1) {
call the other method
break the iteration im in
}
There are a number of things you can do here. Ultimately what you do should depend on your coding style and what you are trying to accomplish.
Option 1 would be some variation of:
for (;;)
{
int number = /* ... */;
myMethod(number);
if (number == -10)
break;
}
You might say, rather subjectively and depending on circumstances, that this is bad, because knowledge of the termination condition is contained in the loop rather than the method doing the "real work". Maybe for your loop that's OK. Maybe in other circumstances (or perhaps with other programmers? This is very much a matter of taste.) you might want to make myMethod make that decision. In general my own personal taste usually leans towards not having scenario knowledge be distributed throughout various methods in source, but in one place.
So most of what I'll write from here on will be how to make myMethod make the decision about whether or not to terminate.
Option 2 - myMethod returns a boolean indicating we should terminate:
for (;;)
{
int number = /* ... */;
if (myMethod(number))
break;
}
boolean myMethod(int number)
{
// TODO - do stuff
return number == -10;
}
But you might say that myMethod already wants to return some other type. I come from very much a C background so the idiom I'm most used to would be the "out parameter". Leading me to option 3:
Option 3 - Out parameter lets caller decide to terminate:
public class CancelIndicator
{
public boolean shouldCancel;
};
CancelIndicator cancel = new CancelIndicator();
while (!cancel.shouldCancel)
{
int number = /* ... */;
myMethod(number, cancel);
}
int myMethod(int number, CancelIndicator cancel)
{
// TODO - do stuff.
cancel.shouldCancel = (number == -10);
return /* ... */;
}
Or maybe you're more a fan of exceptions:
Option 3:
public class CancellationException extends Exception
{
}
try
{
for (;;)
{
int number = /* ... */;
myMethod(numberl);
}
}
catch (CancellationException ex)
{
}
void myMethod(int number) throws CancellationException
{
// TODO - do stuff.
if (number == -10)
throw new CancellationException();
}
As you can see there are a number of options. I'm sure one could spend a whole day talking about different ways to do it. Here is my sample of idioms I have seen - I'll warn you that it's been some time since I've done much in Java so I might not write the most idiomatic code here. :-)
Add a return value indicating that the while should break:
public boolean themethod(int number) {
if(number<1) {
call the other method
return true;
}
return false;
}
Then:
while(number !=-10) {
if(themethod(number)) break;
bla
bla
...
}
Edit: If you can't change the while code, throw an exception from the method:
public void themethod(int number) {
if(number<1) {
call the other method
throw new RuntimeException("Negative Number");
}
}
Wait, so did I get this straight? You have a loop that asks for a number, does something if the number is not -10, and otherwise breaks?
If so, look at this:
while(true) {
number=Integer.parseInt( JOptionPane.showInputDialog( "bla bla" ) );
if(number == -10) {
break;
}
themethod(number);
}
Otherwise, if this is not the case, and you want to break in two cases, the -10 case and the method is false case, you can do this:
Change your method to return a boolean. If it's true, then it doesn't want to break. If it's false then it wants to break, then do this:
while(true) {
number=Integer.parseInt( JOptionPane.showInputDialog( "bla bla" ) );
if(number == -10) {
break;
}
if(!themethod(number)) break;
}
If you really can't edit the loop, then just throw an exception from the method! That will exit your entire program, though. I don't see any other possible way of doing this, however.
Without a return value for themethod(int) and without changing the other class's code, this isn't possible since as it is, there is no return communication. You'll have to change both; it can't be done without changing the logic in the loop.
Which one of the following is a better practice to check if a string is float?
try{
Double.parseDouble(strVal);
}catch(NumberFormatException e){
//My Logic
}
or
if(!strVal.matches("[-+]?\\d*\\.?\\d+")){
//My Logic
}
In terms of performace, maintainence and readability?
And yeah, I would like to know which one is good coding practice?
Personal opinion - of the code I've seen, I would expect that most developers would tend towards the try - catch blocks. The try catch is in a sense also more readable and makes the assumption that for most cases the string will contain a valid number. But there are a number of things to consider with you examples which may effect which you choose.
How often do you expect the string to not contain a valid number.
Note that for bulk processing you should create a Pattern object outside of the loop. This will stop the code from having to recompile the pattern every time.
As a general rule you should never use expectations as logic flow. Your try - catch indicates logic if it's not a string, where as your regex indicates logic if it is a number. So it wasn't obvious what the context of the code is.
If you choose the regex technique, you are still probably going to have to convert at some point, so in effect, it may be a waste of effort.
And finally, is the performance requirements of the application important enough to warrant analysis at this level. Again generally speaking I'd recommend keeping things as simple as possible, making it work, then if there are performance problems, use some code analysis tools to find the bottle necks and tune them out.
Performance: Exceptions are slow, and so is exception-based logic, so second would be faster.
Maintenance / Reliability: The first one is crystal clear and will stay updated with updates to the Java Framework.
That being said, I would personally prefer the first. Performance is something you want to consider as a whole in your architecture, your data structure design, etc. not line by line. Measure for performance and optimize what is actually slow, not what you think might be slow.
The first one is going to perform better than the regex when the string matches the double. For one it's very fast to parse it when the recognizer is hard coded as it would be with Double.parse. Also there's nothing to maintain it's whatever Java defines as the Double is as a string. Not to mention Double.parseDouble() is easier to read.
The other solution isn't going to be compiled so the first thing that the regex has to do is compile and parse the regex expression, then it has to run that expression, then you'll have to execute Double.parseDouble() to get it into a double. And that's going to be done for every number passed to it. You might be able to optimize it with Pattern.compile(), but executing the expression is going to be slower. Especially when you have to run a Double.doubleParse to get the value into a double.
Yes exceptions are not super fast, but you'll only have to pay that price when you parse an error. If you don't plan on seeing lots of errors then I don't think you'll notice the slow down from gathering the stacktrace on the throw (which is why exceptions perform poorly). If you're only going to encounter a handful of exceptions then performance isn't going be a problem. The problem is you expected a double and it wasn't so probably some configuration mistake so tell the user and quit, or pick a suitable default and continue. That's all you can do in those cases.
If you use parseDouble, you will end up with what Mark said, but in a more readable way, and might profit from performance improvements and bug fixes.
Since exceptions are only costly when they are thrown, there is only need to look for a different strategy if you
expect wrong formats to happen often
expect them to fall in a specific pattern which you can catch faster and beforehand
In the end you will call parseDouble either, and therefore it is considered alright to use it that way.
Note that your pattern rejects 7. as a Double, while Java and C/C++ don't, as well as scientific notation like 4.2e8.
May be you can also try this way.But this is generic for a string containing valid number.
public static boolean isNumeric(String str)
{
str = "2.3452342323423424E8";
// str = "21414124.12412412412412";
// str = "123123";
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}
And yeah, I would like to know which one is good coding practice?
Either can be good coding practice, depending on the context.
If bad numbers are unlikely (i.e. it is an "exceptional" situation), then the exception-based solution is fine. (Indeed, if the probability of bad numbers is small enough, exceptions might even be faster on average. It depends on the relative speed of Double.parseDouble() and a compiled regex for typical input strings. That would need to be measured ...)
If bad numbers are reasonably (or very) likely (i.e. it is NOT an "exceptional" situation), then the regex-based solution is probably better.
If the code path that does the test is infrequently executed, then it really makes no difference which approach you use.
Below is performance test to see the performance difference between regular expression VS try catch for validating a string is numeric.
Below table shows stats with a list(100k) with three points (90%, 70%, 50%) good data(float value) and remaining bad data(strings).
**90% - 10% 70% - 30% 50% - 50%**
**Try Catch** 87234580 122297750 143470144
**Regular Expression** 202700266 192596610 162166308
Performance of try catch is better (unless the bad data is over 50%) even though try/catch may have some impact on performance. The performance impact of try catch is because try/catch prevents JVM from doing some optimizations. Joshua Bloch, in "Effective Java," said the following:. Joshua Bloch, in "Effective Java," said the following:
• Placing code inside a try-catch block inhibits certain optimizations that modern JVM implementations might otherwise perform.
public class PerformanceStats {
static final String regularExpr = "([0-9]*[.])?[0-9]+";
public static void main(String[] args) {
PerformanceStats ps = new PerformanceStats();
ps.statsFinder();
//System.out.println("123".matches(regularExpr));
}
private void statsFinder() {
int count = 200000;
int ncount = 200000;
ArrayList<String> ar = getList(count, ncount);
System.out.println("count = " + count + " ncount = " + ncount);
long t1 = System.nanoTime();
validateWithCatch(ar);
long t2 = System.nanoTime();
validateWithRegularExpression(ar);
long t3 = System.nanoTime();
System.out.println("time taken with Exception " + (t2 - t1) );
System.out.println("time taken with Regular Expression " + (t3 - t2) );
}
private ArrayList<String> getList(int count, int noiseCount) {
Random rand = new Random();
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < count; i++) {
list.add((String) ("" + Math.abs(rand.nextFloat())));
}
// adding noise
for (int i = 0; i < (noiseCount); i++) {
list.add((String) ("sdss" + rand.nextInt() ));
}
return list;
}
private void validateWithRegularExpression(ArrayList<String> list) {
ArrayList<Float> ar = new ArrayList<>();
for (String s : list) {
if (s.matches(regularExpr)) {
ar.add(Float.parseFloat(s));
}
}
System.out.println("the size is in regular expression " + ar.size());
}
private void validateWithCatch(ArrayList<String> list) {
ArrayList<Float> ar = new ArrayList<>();
for (String s : list) {
try {
float e = Float.parseFloat(s);
ar.add(e);
} catch (Exception e) {
}
}
System.out.println("the size is in catch block " + ar.size());
}
}