Number Format Exception in java but format is true - java

List<Person> list=new ArrayList<Person>();
public List<Person> readFile(){
File file =new File("dosya.txt");
try {
FileReader fileReader=new FileReader(file);
BufferedReader reader=new BufferedReader(fileReader);
while(reader.readLine()!=null){
String personData= reader.readLine();
System.out.println(personData);
Person person=new Person();
person.setName(personData.substring(1,personData.indexOf("#")));
String sayı=personData.substring(personData.indexOf("#")+1,personData.indexOf("#",personData.indexOf("#")+1));
person.setMoney(Double.valueOf(sayı));
personData=personData.substring(personData.indexOf("#")+1);
System.out.println(personData);
person.setRate(Double.valueOf(personData.substring(0,3)));
personData=personData.substring(personData.indexOf("#")+1);
System.out.println(personData);
person.setNumber(Short.valueOf(personData));
list.add(person);
}
} catch (Exception e) {
e.printStackTrace();
}
This is my code and it seperate "fsyxaimvct wdyeyttuye#1528640,88#0,7#9"
this type of data and it gives mi error like that
java.lang.NumberFormatException: For input string: "2273370,68"
at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054)
at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.base/java.lang.Double.parseDouble(Double.java:549)
at java.base/java.lang.Double.valueOf(Double.java:512)
at FileProcess.readFile(FileProcess.java:19)
at Main.main(Main.java:7)
Why this cant turn 2273370,68 to double

Double.valueOf() doesn't 'do' locale - it parses specifically only numbers that use . as decimal separator. Your input string contains a comma which means it'll fail.
But, this code is essentially useless. You can't do currency with doubles - doubles are imprecise and will silently round. This is not what you want when working with currency.
The simplest solution is to store the 'atomic unit' for the currency. For dollars, store dollarcents. For bitcoin, store satoshis. For yen, store yen. For english pounds, store pennies. And so on. In a long, or if you must, a BigInteger.
Alternatively, use a library (joda-currency is a good one). You'll often hear advice to use BigDecimal but this is usually a bad idea (it's got all sorts of hairy complications; for example, You can't divide BigDecimals at all unless you really know what you are doing - and it's complicated to write code for them).
Parsing a string with e.g. a euro amount such as "-1234,58" in it can be parsed to the long -123458 using:
Pattern p = Pattern.compile("^(-?)(\\s*\\d*)(?:,(\\d{2}))?$");
var m = p.matcher("2273370,68");
long amount;
if (m.matches()) {
amount =
(m.group(1).equals("-") ? -1L : 1L) * (
100 * (m.group(2).isEmpty() ? 0 : Long.parseLong(m.group(2))) +
(m.group(3) != null ? Long.parseLong(m.group(3)) : 0L));
} else throw new NumberFormatException();
Any attempt to use Double.parseDouble will get you into that rounding trouble and you randomly lose or gain a cent. Run a bank like that and you might get into a wee bit of trouble :)

Related

Reading data and storing in array Java

I am writing a program which will allow users to reserve a room in a hotel (University Project). I have got this problem where when I try and read data from the file and store it in an array I receive a NumberFormatException.
I have been stuck on this problem for a while now and cannot figure out where I am going wrong. I've read up on it and apparently its when I try and convert a String to a numeric but I cannot figure out how to fix it.
Any suggestions, please?
This is my code for my reader.
FileReader file = new FileReader("rooms.txt");
Scanner reader = new Scanner(file);
int index = 0;
while(reader.hasNext()) {
int RoomNum = Integer.parseInt(reader.nextLine());
String Type = reader.nextLine();
double Price = Double.parseDouble(reader.nextLine());
boolean Balcony = Boolean.parseBoolean(reader.nextLine());
boolean Lounge = Boolean.parseBoolean(reader.nextLine());
String Reserved = reader.nextLine();
rooms[index] = new Room(RoomNum, Type, Price, Balcony, Lounge, Reserved);
index++;
}
reader.close();
This is the error message
This is the data in my file which I am trying to read:
Change your while loop like this
while (reader.hasNextLine())
{
// then split reader.nextLine() data using .split() function
// and store it in string array
// after that you can extract data from the array and do whatever you want
}
You're trying to parse the whole line to Integer. You can read the whole line as a String, call
.split(" ")
on it. This will split the whole line into multiple values and put them into an array. Then you can grab each item from the array and parse separately as you intended.
Please avoid posting screenshots next time, use proper formatting and text so someone can easily copy your code or test data to IDE and reproduce the scenario.
Use next() instead of nextLine().
With Scanner one must use hasNextLine, nextLine, hasNext, next, hasNextInt, nextInt etcetera. I would do it as follows:
Using Path and Files - the newer more general classes i.o. File.
Files can read lines, here I use Files.lines which gives a Stream of lines, a bit like a loop.
Try-with-resources: try (AutoCloseable in = ...) { ... } ensures that in.close() is always called implicitly, even on exception or return.
The line is without line ending.
The line is split into words separated by one or more spaces.
Only lines with at least 6 words are handled.
Create a Room from the words.
Collect an array of Room-s.
So:
Path file = Paths.get("rooms.txt");
try (Stream<String> in = Files.lines(file)) {
rooms = in // Stream<String>
.map(line -> line.split(" +")) // Stream<String[]>
.filter(words -> words.length >= 6)
.map(words -> {
int roomNum = Integer.parseInt(words[0]);
String type = words[1];
double price = Double.parseDouble(words[2]);
boolean balcony = Boolean.parseBoolean(words[3]);
boolean lounge = Boolean.parseBoolean(words[4]);
String reserved = words[5];
return new Room(roomNum, type, price, balcony, lounge, reserved);
}) // Stream<Room>
.toArray(Room[]::new); // Room[]
}
For local variables use camelCase with a small letter in front.
The code uses the default character encoding of the system to convert the bytes in the file to java Unicode String. If you want all Unicode symbols,
you might store your list as Unicode UTF-8, and read them as follows:
try (Stream<String> in = Files.lines(file, StandardCharsets.UTF_8)) {
An other issue is the imprecise floating point double. You might use BigDecimal instead; it holds a precision:
BigDecimal price = new BigDecimal(words[2]);
It is however much more verbose, so you need to look at a couple of examples.

Converting String to BigDecimal When String Contains 'e' Java

Note: I have asked this question when I was a newbie to programming in java. I have got the solution for the same; back then itself. Editing to make it clear for other readers.
Input Format: Input is in string format. In our case we assume to convert the strings that contains only digits to BigDecimal, rest of them can be ignored.
Eg: We expect 1e4 -> BigDecimal value to be passed as "10000". So, the inputs which
contains alphabets or any other special characters can be be ignored to convert.
Reason for the requirement: We need to search few columns in the DB based on the search text and retrieve rows on matching criteria. Lets say columns name(VarChar column), price(Decimal column), type (VarChar column). So, if the search text can be converted to BigDecimal we will search if text matches any of the columns else if it can't be converted to BigDecimal we will search if the text matches other two columns.
Without analysing the input further I have blindly converted the search text to BigDecimal.
Example: if the name in DB is 1e3 and price is 10000 and if search text is 1e4, then the converted BigDecimal value of 1e4 will be matched to 10000 and will fetch the row.
Initial Code of converting to BigDecimal:
BigDecimal textToBigDecimal = null;
try
{
textToBigDecimal = new BigDecimal(searchText);
}
catch (NumberFormatException ignored)
{
}
if (textToBigDecimal == null)
{
//criteria handling code.
}
else
{
//criteria handling code.
}
Skipped the criteria constructed code. Added try-catch because, the input can be a pure string also. Based on that criteria construction differs.
Modified Code:
BigDecimal textToBigDecimal = null;
try
{
if (!searchText.contains("e") && !searchText.contains("E"))
{
textToBigDecimal = new BigDecimal(searchText);
}
}
catch (NumberFormatException ignored)
{
}
if (textToBigDecimal == null)
{
//criteria handling code.
}
else
{
//criteria handling code.
}
Note: If any further doubts pls comment on the question. I have posted this question expecting to find a default java method that converts only the strings that contains digits only to BigDecimal and throws exception for rest of the strings.
If you want exception to be thrown for strings like '45e57', you can use for example Long.parseLong("43e57") before constructing BigDecimal. It will throw NumberFormatException

Double.parseDouble not accounting for locale [duplicate]

I want to convert some numbers which I got as strings into Doubles, but these numbers are not in US standard locale, but in a different one. How can I do that?
Try java.text.NumberFormat. From the Javadocs:
To format a number for a different Locale, specify it in the call to getInstance.
NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
You can also use a NumberFormat to parse numbers:
myNumber = nf.parse(myString);
parse() returns a Number; so to get a double, you must call myNumber.doubleValue():
double myNumber = nf.parse(myString).doubleValue();
Note that parse() will never return null, so this cannot cause a NullPointerException. Instead, parse throws a checked ParseException if it fails.
Edit: I originally said that there was another way to convert to double: cast the result to Double and use unboxing. I thought that since a general-purpose instance of NumberFormat was being used (per the Javadocs for getInstance), it would always return a Double. But DJClayworth points out that the Javadocs for parse(String, ParsePosition) (which is called by parse(String)) say that a Long is returned if possible. Therefore, casting the result to Double is unsafe and should not be tried!
Thanks, DJClayworth!
NumberFormat is the way to go, but you should be aware of its peculiarities which crop up when your data is less than 100% correct.
I found the following usefull:
http://www.ibm.com/developerworks/java/library/j-numberformat/index.html
If your input can be trusted then you don't have to worry about it.
Just learning java and programming. Had similar question. Found something like this in my textbook:
Scanner sc = new Scanner(string);
double number = sc.nextDouble();
The book says that a scanner automatically decodes what's in a String variabel and that the Scanner class automatically adapts to the language of the set Locale, system Locale being the default, but that's easy to set to something else.
I solved my problem this way. Maybe this could work for the above issue instead of parsing?
Addition: The reason I liked this method was the fact that when using swing dialouge boxes for input and then trying to convert the string to double with parse I got a NumberFormatException. It turned out that parse exclusively uses US-number formatting while Scanner can handle all formats. Scanner made the input work flawlessly even with the comma (,) decimal separator. Since the most voted up answer uses parse I really don't see how it would solve this particular problem. You would have to input your numbers in US format and then convert them to your locale format. That's rather inconvenient when ones numeric keybord is fitted with a comma.
Now you're all free to shred me to pieces ;)
You use a NumberFormat. Here is one example, which I think looks correct.
Use NumberFormat.getNumberInstance(Locale)
This should be no problem using java.text.DecimalFormat.
Do you know which locale it is? Then you can use
DecimalFormat format = DecimalFormat.getInstance(theLocale);
format.parse(yourString);
this will even work for scientific notations, strings with percentage signs or strings with currency symbols.
Here is how you use parseDouble to convert a String to a Double:
doubleExample.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class doubleExample {
public static void main(String[] args) {
Double myDouble = new Double("0");
System.out.println("Please enter a number:");
try
{
//get the number from console
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
myDouble = Double.parseDouble(br.readLine());
}
//if invalid value was entered
catch(NumberFormatException ne)
{
System.out.println("Invalid value" + ne);
System.exit(0);
}
catch(IOException ioe)
{
System.out.println("IO Error :" + ioe);
System.exit(0);
}
System.out.println("Double value is " + myDouble);
}
}

Java - Ideas to turn strings into numbers (RegEx/Parsing/etc.)?

I'm reading in from a file, and the input is like this:
Description (1.0,2.0) (2,7.6) (2.1,3.0)
Description2 (4,1)
...
Description_n (4,18) (8, 7.20)
I want to be able to take the numbers inside parentheses and use turn them from strings into numbers so that I can do mathematical operations of them. Right now, to simplify things, my code only reads in the first line and then splits it based on spaces:
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(new File("filename.txt")));
//reader reads in the first line
String firstLine = reader.readLine();
//splits into an array of ["Description","(1.0,2.0)","(2,7.6)","(2.1,3.0)"]
String[] parts = first.split(" ");
//now I want to store 1.0, 2, and 2.1 in one array as ints and 2.0, 7.6, and 3.0 in another int array
} catch (Exception e) {
System.exit(0);
}
What are some ways I can store the numbers inside parentheses into two separate arrays of ints (see comment above)? Should I use regular expressions to somehow capture something of the form "( [1-9.] , [1-9.] )" and then pass those into another function that will then separate the first number in the pair from the second and then convert them both into integers? I'm new to regular expression parsing in Java, so I'm not sure how to implement this.
Or is there a simply, better way to do this?
This stores the numbers into Double-arrays (not two-dimensional arrays, arrays of Double objects), since some have .#. int-arrays would eliminate the post decimal part.
It uses the regex \b([\d.]+)\b to find each number within each paren-group, adding each to an ArrayList<Double>. Note that it assumes all input is perfect (nothing like (bogus,3.2). The list is then translated into an array of Double objects.
This should give you a good start towards your goal.
import java.util.Arrays;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
<P>{#code java DoubleInParenStringsToArrays}</P>
**/
public class DoubleInParenStringsToArrays {
public static final void main(String[] ignored) {
String input = "(1.0,2.0) (2,7.6) (2.1,3.0)";
String[] inputs = input.split(" ");
//"": Dummy string, to reuse matcher
Matcher mtchrGetNums = Pattern.compile("\\b([\\d.]+)\\b").matcher("");
for(String s : inputs) {
ArrayList<Double> doubleList = new ArrayList<Double>();
mtchrGetNums.reset(s);
while(mtchrGetNums.find()) {
//TODO: Crash if it's not a number!
doubleList.add(Double.parseDouble(mtchrGetNums.group(0)));
}
Double[] doubles = doubleList.toArray(new Double[doubleList.size()]);
System.out.println(Arrays.toString(doubles));
}
}
}
Output:
[C:\java_code\]java DoubleInParenStringsToArrays
[1.0, 2.0]
[2.0, 7.6]
[2.1, 3.0]
How to parse per item:
Double.parseDouble("your string here");
As for the storing, I didnt get the pattern you want to store your values. What's the reason why you want 1.0, 2, and 2.1 in 1 array and 2.0, 7.6, and 3.0 to another?
Just do Integer.parseInt(string), or Double.parseDouble(string), then add those to the array. I'm not really 100% sure what you're asking, though.
I would use a String Tokenizer.But need more information and thought for full impl.
This is your line : "Description (1.0,2.0) (2,7.6) (2.1,3.0)"
First thing - can there be cases without parenthesis? Will there always be sets f 2,2,2 numbers ?
Do you want to take care of errors at each number or just skip the line or skip processing if there is an error (like number of numbers does not match?).
Now you need a data structure to hold numbers. You could make a class to hold each individual element in a seperate property if each number has a distinct meaning in the domain or have an array list or simple array if you want to treat them as a simple list of numbers. If a class one sample (incopmplete):
class LineItem{
}
Now to actually break up the string there are many ways to do it. Really depends on the quality of data and how you want to deal with possible errors
One way is find the first opening parenthesis( take rest of string and parse out using a String Tokenizer.
Something like:
int i = str.indexOf("(");
String s2 = str.substring(i);
StringTokenizer st = new StringTokenizer(s2, "() ,";//parenthesis, comma and space
ArrayList<Double> lineVals1 = new ArrayList<Double>();
ArrayList<Double> lineVals1 = new ArrayList<Double>();
int cnt = 0;
while(st.hasMoreTokens()){
cnt++;//use this to keep count of how many numbers you got in line and raise error if need be
String stemp = st.nextToken();
if(isNumeric(stemo)){
if(cnt % 2 == 1){
lineVals1.add(Double.parseDouble(stemp));
}else{
lineVals2.add(Double.parseDouble(stemp));
}
}else{
/raise error if not numberic
}
}
public static boolean isNumeric(String str)
{
NumberFormat formatter = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
formatter.parse(str, pos);
return str.length() == pos.getIndex();
}

Conversion of string numbers into comma seperated string numbers in Android

I am currently working on an Android project where we use string numbers with many digits in it.
So I want to know whether there is a way to convert the string numbers for e.g 1000000000 into comma separated string numbers for e.g(1,00,00,00,000) in Indian Locale format.
I got the US locale format string conversion but I want Indian locale format.
I would use format("% ,d", number) method of Format class, ensuring that I initialize the Formatter object with the appropriate locale (which I believe is en_IN for Indian).
Having said that, it would be easier for people to help you if you posted code on how you are doing it for US locale in the first place.
Ref : Formatting a Number Using a Custom Format
private String getFormatedData(String unformatedData) {
if(unformatedData != null) {
try {
//unformatedData.replaceAll(",", "");
Double result = Double.valueOf(unformatedData);
DecimalFormat myFormatter = new DecimalFormat("###,##0.00");
//DecimalFormat myFormatter = new DecimalFormat("#,###,###");
//If you don't want to show .00 format
return myFormatter.format(result);
} catch (NumberFormatException e) {
return unformatedData;
}
} else {
return "0.00";
}
}
Use this method.
I think you have to modify this method if you don't need .00 value. Let me work on it.
I think that you need to use NumberFormat so you can make a general case using current Locale settings of the user.
And I think that this is your current situation:
If you are formatting multiple numbers, it's more efficient to get the format and use it multiple times so that the system doesn't have to fetch the information about the local language and country conventions multiple times.
NumberFormat nf = NumberFormat.getInstance();
for (int i = 0; i < a.length; ++i) {
output.println(nf.format(myNumber[i]) + "; ");
}
The answer given by Pankaj Kumar gives the output in US format not in Indian Format.
If you want in US format it can be easily done by following code:
NumberFormat.getNumberInstance(Locale.US).format(35634646)
As shown here: Converting Integer to String with comma for thousands
To get the string with commas in Indian Format you can try this manual code
public String round(String d)
{
ArrayList<Integer> commas=new ArrayList<Integer>();
String output=null;
char[] preDecimal=d.split("[.]")[0].toCharArray();
int i=preDecimal.length-3;
System.out.println(i);
while(i>0)
{
commas.add(i);
i-=2;
}
StringBuilder sb=new StringBuilder();
for(i=0;i<preDecimal.length;i++)
{
sb.append(preDecimal[i]);
if(commas.contains(i+1))
sb.append(",");
}
output=sb.toString();
return output;
}

Categories

Resources