问题 Scanner#nextFloat的奇怪行为


在Eclipse中运行以下操作最初导致Scanner无法识别控制台中的回车,从而有效阻止了进一步的输入:

price = sc.nextFloat();

在代码之前添加此行会导致Scanner接受0,23(法语表示法)作为浮点数:

Locale.setDefault(Locale.US);

这很可能是由于Windows XP Pro(法语/比利时语)中的区域设置。当代码再次运行时,仍然接受0,23,输入0.23会导致它抛出一个 java.util.InputMismatchException

有关为什么会发生这种情况的任何解释?还有一个解决方法或我应该使用 Float#parseFloat

编辑:这演示了扫描程序如何使用不同的语言环境(在开头取消注释其中一行)。

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);
    }

}

编辑:这将重现扫描程序正在等待浮动值但在按下返回时无法触发的问题:

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);
    }

}

12444
2018-01-16 21:33


起源

你能给出一个可执行的例子,显示你正在运行的代码的实际序列并显示问题吗? - Michael Borgwardt
当然。我会在几分钟内添加一些代码。 - James P.


答案:


我想知道你是否没有适当地处理行尾令牌。通常,如果您使用Scanner#next ###()(nextLine除外),并且当用户按Enter键时您到达行尾令牌,如果您不处理行结束令牌,则会阻止扫描程序对象从适当的工作。要解决此问题,请在需要处理此令牌时调用Scanner#nextLine()。如果你发布了一些代码,我们可以看看这确实是你的问题,如果我的建议提供了解决方案。

编辑:不,你没有使用System.in所以这不是问题。另一方面,您需要在接受法语号码之前设置扫描仪的语言环境。即,

     sc = new Scanner(frenchDecimal);
     sc.useLocale(Locale.FRENCH);
     price = sc.nextFloat();

13
2018-01-16 21:51



如果不调用useLocale(...),将使用默认的Locale构建Scanner。 OP的默认语言环境是法语。 - robert_x44
谢谢你的回复,但不好意思我错过了。他在哪里声明默认语言环境是法语? - Hovercraft Full Of Eels
谢谢。设置扫描仪的区域设置可以解决问题(我想使用US十进制)。有关导致在修改过的代码中跳过nextLine的原因的任何想法?此外,由于Locale已设置,我无法重现扫描器似乎接受文本但无法识别回车的问题。 - James P.
@hovercraft在关于他的println的评论中(Locale.getDefault()) - robert_x44
@james当你调用sc.nextFloat()时它不会从缓冲区中删除换行符,所以你对sc.nextLine()的下一次调用返回一个空行(如@hovercraft解释的那样 - + 1!)解决方法是调用在sc.nextFloat()之后的sc.nextLine()并忽略其输出 - robert_x44