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);
}
}
Related
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;
}
Main:
public class Main{
public static void main(String[] args){
System.out.println(Convert.BtoI("10001"));
System.out.println(Convert.BtoI("101010101"));
}
}
Class:
public class Convert{
public static int BtoI(String num){
Integer i= Integer.parseInt(num,2);
return i;
}
}
So I was working on converters, I was struggling as I am new to java and my friend suggested using integer method, which works. However, which method would be most efficient to convert using the basic operators (e.g. logical, arithmetic etc.)
.... my friend suggested using integer method, which works.
Correct:
it works, and
it is the best way.
However, which method would be most efficient to convert using the basic operators (e.g. logical, arithmetic etc.)
If you are new to Java, you should not be obsessing over the efficiency of your code. You don't have the intuition.
You probably shouldn't optimize this it even if you are experienced. In most cases, small scale efficiencies are irrelevant, and you are better off using a profiler to validate your intuition about what is important before you start to optimize.
Even if this is a performance hotspot in your application, the Integer.parseint code has (no doubt) already been well optimized. There is little chance that you could do significantly better using "primitive" operations. (Under the hood, the methods will most likely already be doing the same thing as you would be doing.)
If you are just asking this because you are curious, take a look at the source code for the Integer class.
If you want to use basic arithmetic to convert binary numbers to integers then you can replace the BtoI() method within the class Convert with the following code.
public static int BtoI(String num){
int number = 0; // declare the number to store the result
int power = 0; // declare power variable
// loop from end to start of the binary number
for(int i = num.length()-1; i >= 0; i--)
{
// check if the number encountered is 1
/// if yes then do 2^Power and add to the result
if(num.charAt(i) == '1')
number += Math.pow(2, power);
// increment the power to use in next iteration
power++;
}
// return the number
return number;
}
Normal calculation is performed in above code to get the result. e.g.
101 => 1*2^2 + 0 + 1*2^0 = 5
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.
I have recently set up find bugs in eclipse to see what reports it generates. Ive set all the settings to be as sensitive as possible. If i create a small application that writes to a file and do not close the stream it picks it up which is all good.
However, using a project that has been written where we no there are a couple of bugs, especially in the output, we get no errors at all (in terms of find bugs)
I was wondering if anyone could run this through their version and report whether I may have find bugs set up incorrectly or whether in fact it could find no bugs?
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class SpellUtil {
private final static String teenSpelling[] = {"Zero", "One", "Two", "Three",
"Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven",
"Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen",
"Seventeen", "Eighteen", "Nineteen"};
private final static String centSpelling[] = {"Twenty", "Thirty", "Forty",
"Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
private final static String suffixSpelling[] = {
"", // Dummy! no level 0 (added for nicer indexing in code)
"", // Nothing for level 1
" Thousand, ", " Million, ", " Billion, ", " Trillion, ", " Quadrillion, ",
" Quintillion, "};
public static String spell(int number) {
int rem, placeIndicator = 1;
boolean isNegative = false;
List<String> spelling = new ArrayList<String>();
if (number < 0) {
isNegative = true;
number = Math.abs(number);
}
while (number > 0) {
rem = number % 1000;
number = number / 1000;
spelling.add(suffixSpelling[placeIndicator]);
try {
spelling.add(spellBelow1000(rem));
} catch (SpellingException e) {
System.out.println(e.getMessage());
}
placeIndicator++;
}
StringBuilder sb = new StringBuilder();
if (isNegative) sb.append("Minus ");
for (int i = spelling.size() - 1; i >= 0; i--) {
sb.append(spelling.get(i));
}
return sb.toString();
}
private static String spellBelow1000(int number) throws SpellingException {
if (number < 0 || number >= 1000)
throw new SpellingException("Expecting a number between 0 and 999: " + number);
if (number < 20) {
// if number is a teen,
// find it in teen table and return its equivalent text (word).
return teenSpelling[number];
} else if (number < 100) {
// otherwise, if it is a cent,
// find the most (div) and least (rem) significant digits (MSD/LSD)
int div = (int) number / 10;
int rem = (int) number % 10;
if (rem == 0) {
// if LSD is zero, return the cent key word directly (like
// fifty).
return centSpelling[div-2];
} else {
// otherwise, return the text as cent-teen (like fifty-one)
return centSpelling[div-2] + "-" + teenSpelling[rem];
}
} else {
// otherwise, it is a mil;
// find it's MSD and remaining cent.
int div = number / 100;
int rem = (int) number % 100; // TODO will findbugs detect unnecessary (int)?
// Prepare the mil prefix:
String milText = teenSpelling[div] + " Hundred";
// decide whether to append the cent tail or not.
if (rem == 0) {
// if it does have a non-zero cent, that's it.
// return the mil prefix, for example three hundred:
return milText;
} else {
// otherwise, spell the cent and append it to mil prefix.
// (now, rem is a cent).
// For example, three Hundred and Sixty-Four:
return milText + " and " + spellBelow1000(rem);
}
}
}
}
Your expectation to find a bug in this line:
int rem = (int) number % 100; // TODO will findbugs detect unnecessary (int)?
is WRONG because the result of a % operation is not an integer in general.
In C and C++, the remainder operator accepts only integral operands, but in Java, it also accepts floating-point operands. This means statements such as double x = 8.2 % 4; are quite valid in Java and the result could be a non-integer value. (0.1999999999999993 in this case)
Please see the Java language specification here.
You seem to have a problem with findbugs configuration. I suggest using Findbugs via Sonar. It is much more easy to configure and you get checkstyle, pmd and a system for managing and resolving violations.
Sonar findbugs page
I think that the problem is that you misunderstanding what FindBugs does and what its capabilities are.
Basically, FindBugs parses each class to produce a parse-tree - an in-memory representation of the structure of the program. Then attempts to find places in the tree that match known patterns which represent incorrect or questionable programming. For example:
if (someString == "42") {
....
}
FindBugs will most likely tell you comparing strings using the '==' operator here is wrong. What it has done is look through the class for any expression node where the operator is '==' and one or both of the operands is a String. It will repeat this procedure for a large number of patterns that it has been programmed to detect and report. Some will be more complicated than this one, but basically, FindBug is only doing a form of structural pattern matching.
What FindBugs does not and cannot do is to understand what your program is actually supposed to do. So for example:
public boolean isOdd(int arg) {
return (arg % 2) == 0;
}
This is obviously incorrect to anyone who understands simple mathematics ... but FindBugs won't notice it. That is because FindBugs has no idea what the method is actually supposed to do. Furthermore, it is not capable of doing the elementary semantic analysis that is required to figure out that the code doesn't implement the math.
The reason I am doing this is because I need to do a presentation of find bugs and I need an application to generate some bugs to show how it works.
Maybe you need to cheat a bit:
Read the Findbugs documentation to understand the things that it is capable of finding.
Write some "toy" applications with bugs that you know Findbugs can find for you.
It is also worthwhile including examples that you know it won't find ... so that you can explain the limitations of Findbugs.
What findbugs does is to look for some common mistakes that could (and most probably would) lead to unexpected/unwanted behavior. Most of those errors are technical or wrong use of java and its API. A list of all findbugs checks can be found here In other words if you did something you don't wanted in a right way, findbugs would not detect it. In your code I can't see anything that would be detected by findbugs. The unnecessary cast you mentioned in your comments is not a findbugs rule because it doesn't change the behavior of your code. It is more of a style or efficiency error and would be detected by tools like checkstyle or PMD.
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());
}
}