Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird behaviour with Scanner#nextFloat

Running the following in Eclipse initially caused Scanner to not recognize carriage returns in the console effectively blocking further input:

price = sc.nextFloat();

Adding this line before the code causes Scanner to accept 0,23 (french notation) as a float:

Locale.setDefault(Locale.US);

This is most probably due to regional settings in Windows XP Pro (French/Belgian). When the code is run again 0,23 is still accepted and entering 0.23 causes it to throw a java.util.InputMismatchException.

Any explanation as to why this is happening? Also is there a workaround or should I just use Float#parseFloat?

Edit: This demonstrates how Scanner behaves with different Locales (uncomment one of the lines at the beginning).

import java.util.Locale;
import java.util.Scanner;


public class NexFloatTest {

    public static void main(String[] args) {

        //Locale.setDefault(Locale.US);
        //Locale.setDefault(Locale.FRANCE);

        // Gives fr_BE on this system
        System.out.println(Locale.getDefault());

        float price;

        String uSDecimal = "0.23";
        String frenchDecimal = "0,23";

        Scanner sc = new Scanner(uSDecimal);

        try{
            price = sc.nextFloat();
            System.out.println(price);
        } catch (java.util.InputMismatchException e){
            e.printStackTrace();
        }

        try{
            sc = new Scanner(frenchDecimal);
            price = sc.nextFloat();
            System.out.println(price);
        } catch (java.util.InputMismatchException e){
            e.printStackTrace();
        }

        System.out.println("Switching Scanner to System.in");

        try{
            sc = new Scanner(System.in);
            System.out.println("Enter a float value");
            price = sc.nextFloat();
            System.out.println(price);
        } catch (java.util.InputMismatchException e){
            e.printStackTrace();
        }

        System.out.print("Enter title:");

        String title = sc.nextLine(); // This line is skipped

        System.out.print(title);
    }

}

Edit: This reproduces the issue where the Scanner is waiting for a float value but fails to trigger when you press return:

import java.util.Scanner;

public class IgnoreCRTest {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter a float value:");
        // On french Locale use , as the decimal separator
        float testFloat = sc.nextFloat();
        System.out.println(testFloat);
        //sc.skip("\n"); // This doesn't solve the issue
        sc.nextLine();
        System.out.println("Enter an integer value:");
        int testInt = sc.nextInt();
        System.out.println(testInt);
        // Will either block or skip here
        System.out.println("Enter a string value :");
        String testString = sc.nextLine();
        System.out.println(testString);
    }

}
like image 222
James P. Avatar asked Jan 16 '11 21:01

James P.


1 Answers

I wonder if you're not handling an end of line token appropriately. Often if you use Scanner#next###() (except for nextLine), and you reach an end of line token as when the user presses enter, if you don't handle the end of line token, it will prevent the Scanner object from working appropriately. To solve this, call Scanner#nextLine() when this token needs to be handled. If you post some of your code, we can see if this indeed is your problem and if my suggestion offers a solution.

edit: nope, you're not using System.in so this is not the problem. On the other hand, you do need to set the locale of the Scanner before accepting the French number. i.e.,

     sc = new Scanner(frenchDecimal);
     sc.useLocale(Locale.FRENCH);
     price = sc.nextFloat();
like image 85
Hovercraft Full Of Eels Avatar answered Sep 21 '22 13:09

Hovercraft Full Of Eels