How do I read input that could be an int or a double? [duplicate]
Asked Answered
P

4

6

I'm writing a program in which I need to take input from the keyboard. I need to take a number in, yet I'm not sure if it's an int or a double. Here's the code that I have (for that specific part):

import java.io.*;
import java.util.*;

//...
Scanner input  = new Scanner(System.in); 
int choice = input.nextInt();

I know I can get a String and do parseInt() or parseDouble(), but I don't know which one it'll be.

Paton answered 26/7, 2015 at 21:58 Comment(2)
Indeed, reading in a String would be best. Then, you'll need to verify that the given number is a number. If it contains a dot, or comma and the left and right part are numeric, then it is a double. Else if there is no dot or comma but the rest is numeric, it is an int. For checking if it is a double you can use this regex: "-?\\d+(\\.\\d+)?", for numbers you can use "[0-9]*".Namely
@Namely Of course, this regex pattern would only work reliably for a limited number of locales that format floating point numbers similar to the English one. And even in an English locale, integer data may contain grouping separators etc. which may lead to errors.Adjoin
A
3

Just use a double no matter what it is. There is no noticeable loss on using a double for integral values.

Scanner input = new Scanner(System.in); 
double choice = input.nextDouble();

Then, if you need to know whether you've gotten a double or not, you can check it using Math.floor:

if (choice == Math.floor(choice)) {
    int choiceInt = (int) choice);
    // treat it as an int
}

Don't mess with catching NumberFormatException, don't search the string for a period (which might not even be correct, for example if the input is 1e-3 it's a double (0.001) but doesn't have a period. Just parse it as a double and move on.

Also, don't forget that both nextInt() and nextDouble() do not capture the newline, so you need to capture it with a nextLine() after using them.

Antalya answered 26/7, 2015 at 22:56 Comment(1)
Thanks.The second block of code with the int statement you gave me was very simple and understandable, yet very helpful.Paton
F
5

Well, ints are also doubles so if you assume that everything is a double you will be OK with your logic. Like this:

import java.io.*;
import java.util.*;
Scanner input  = new Scanner(System.in); 
double choice = input.nextDouble();

It only get complex if you needed the input to be an integer for whatever reason. And then, parseInt() to test for int would be just fine.

Flatways answered 26/7, 2015 at 22:2 Comment(1)
Although I agree with your answer, I feel that your first sentence is a bit misleading. Sure an integer value can [usually] be represented in a double type, but I wouldn't say that an int is a double. Not only do they have different memory footprints (int uses 4 bytes, while double uses 8 bytes) the way that they actually store the value is a bit different. This is completely irrelevant to OP and your answer definitely would work for him/her, but I just wanted to leave this here for future readers. Luckily casting from double to int is painless if the value truly is an integer.Addi
A
3

Just use a double no matter what it is. There is no noticeable loss on using a double for integral values.

Scanner input = new Scanner(System.in); 
double choice = input.nextDouble();

Then, if you need to know whether you've gotten a double or not, you can check it using Math.floor:

if (choice == Math.floor(choice)) {
    int choiceInt = (int) choice);
    // treat it as an int
}

Don't mess with catching NumberFormatException, don't search the string for a period (which might not even be correct, for example if the input is 1e-3 it's a double (0.001) but doesn't have a period. Just parse it as a double and move on.

Also, don't forget that both nextInt() and nextDouble() do not capture the newline, so you need to capture it with a nextLine() after using them.

Antalya answered 26/7, 2015 at 22:56 Comment(1)
Thanks.The second block of code with the int statement you gave me was very simple and understandable, yet very helpful.Paton
K
0

You could try using the floor function to check if it is a double. In case you don't know, the floor function basically cuts off any decimal numbers. So you can compare the number with and without the decimal. If they are the same, then the number can be treated as an integer, otherwise a double (assuming you don't need to worry about large numbers like longs).

String choice = input.nextLine();

if (Double.parseDouble(choice) == Math.floor(Double.parseDouble(choice)) {
    //choice is an int
} else {
    //choice is a double
}
Kassandrakassaraba answered 26/7, 2015 at 22:4 Comment(2)
Oh, I just got the method from the question and didn't realize it wasn't in the String class. Fixed, thanks. @AntalyaKassandrakassaraba
I've removed my downvote, but it's not necessary to call parseDouble twice.Antalya
L
0

What I would do is get String input, and parse it as either a double or an integer.

String str = input.next();
int i = 0;
double d = 0d;
boolean isInt = false, isDouble = false;

try {
    // If the below method call doesn't throw an exception, we know that it's a valid integer
    i = Integer.parseInt(str);
    isInt = true
}catch(NumberFormatException e){
    try {
        // It wasn't in the right format for an integer, so let's try parsing it as a double
        d = Double.parseDouble(str);
        isDouble = true;
    }catch(NumberFormatException e){
        // An error was thrown when parsing it as a double, so it's neither an int or double
        System.out.println(str + " is neither an int or a double");
    }
}

// isInt and isDouble now store whether or not the input was an int or a double
// Both will be false if it wasn't a valid int or double

This way, you can ensure that you don't lose integer precision by just parsing a double (doubles have a different range of possible values than integers), and you can handle the cases where neither a valid integer or double was entered.

If an exception is thrown by the code inside the try block, the code in the catch block is executed. In our case, if an exception is thrown by the parseInt() method, we execute the code in the catch block, where the second try-block is. If an exception os thrown by the parseDouble() method, then we execute the code inside the second catch-block, which prints an error message.

Lebanon answered 26/7, 2015 at 22:24 Comment(1)
I'm not the downvoter, but: Integer.parseInt does a lot less than Scanner.nextInt (or the double version) in terms of dealing with Locale- and NumberFormat- issues. (i.e.: it does nothing at all and just throws if it encounters anything that is not a numeric ASCII char)Adjoin

© 2022 - 2024 — McMap. All rights reserved.