简体   繁体   English

什么是 NumberFormatException 以及如何修复它?

[英]What is a NumberFormatException and how can I fix it?

Error Message:
Exception in thread "main" java.lang.NumberFormatException: For input string: "Ace of Clubs"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at set07102.Cards.main(Cards.java:68)
C:\Users\qasim\AppData\Local\NetBeans\Cache\8.1\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 0 seconds)

My While Loop:我的 While 循环:

while (response != 'q' && index < 52) {
    System.out.println(cards[index]);
    int first_value = Integer.parseInt(cards[index]);
    int value = 0;
    //Add a Scanner
    Scanner scanner = new Scanner(System.in);
    System.out.println("Will the next card be higher or lower?, press q if you want to quit");
    String guess = scanner.nextLine();
    if(cards[index].startsWith("Ace")) { value = 1; }
    if(cards[index].startsWith("2")) { value = 2; }
    if(cards[index].startsWith("3")) { value = 3; }
    //checking 4-10
    if(cards[index].startsWith("Queen")){ value = 11; }
    if(cards[index].startsWith("King")){ value = 12; }
    if(guess.startsWith("h")){
        if(value > first_value){ System.out.println("You answer was right, weldone!"); } 
        else { System.out.println("You answer was wrong, try again!"); }
    } else if(guess.startsWith("l")){
        if(value < first_value) { System.out.println("You answer as right, try again!"); }
        else { System.out.println("You answer was wrong, try again!"); }
    } else { System.out.println("Your was not valid, try again!"); }
    scanner.close();            
    index++;
}//end of while loop
Error Message:
Exception in thread "main" java.lang.NumberFormatException: For input string: "Ace of Clubs"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at set07102.Cards.main(Cards.java:68)
C:\Users\qasim\AppData\Local\NetBeans\Cache\8.1\executor-snippets\run.xml:53: Java returned: 1

means:方法:

There was an error. We try to give you as much information as possible
It was an Exception in main thread. It's called NumberFormatException and has occurred for input "Ace of Clubs".
at line 65th of NumberFormatException.java which is a constructor,
which was invoked from Integer.parseInt() which is in file Integer.java in line 580,
which was invoked from Integer.parseInt() which is in file Integer.java in line 615,
which was invoked from method main in file Cards.java in line 68.

It has resulted in exit code 1

In other words, you tried to parse "Ace of Clubs" to an int what Java can't do with method Integer.parseInt .换句话说,您尝试将"Ace of Clubs"解析为int ,这是 Java 无法使用方法Integer.parseInt完成的。 Java has provided beautiful stacktrace which tells you exactly what the problem is. Java 提供了漂亮的堆栈跟踪,它可以准确地告诉您问题所在。 The tool you're looking for is debugger and using breakpoints will allow you to inspect the state of you application at the chosen moment.您正在寻找的工具是调试器,使用断点可以让您在选定的时刻检查应用程序的状态

The solution might be the following logic in case you want to use parsing :如果您想使用解析,解决方案可能是以下逻辑:

if (cards[index].startsWith("Ace")) 
    value = 1;
else if (cards[index].startsWith("King"))
    value = 12;
else if (cards[index].startsWith("Queen"))
    value = 11;
...
else {
    try {
        Integer.parseInt(string.substring(0, cards[index].indexOf(" "))); 
    } catch (NumberFormatException e){
        //something went wrong
    }
}

What is an Exception in Java? Java中的Exception是什么?

An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.异常是在程序执行期间发生的事件,它破坏了程序指令的正常流程。

- Documentation - 文档

Constructors and usage in Integer#parseInt Integer#parseInt中的构造函数和用法

static NumberFormatException forInputString(String s) {
    return new NumberFormatException("For input string: \"" + s + "\"");
}

public NumberFormatException (String s) {
    super (s);
}

They are important for understanding how to read the stacktrace.它们对于理解如何阅读堆栈跟踪很重要。 Look how the NumberFormatException is thrown from Integer#parseInt :看看NumberFormatException是如何从Integer#parseInt抛出的:

if (s == null) {
    throw new NumberFormatException("null");
}

or later if the format of the input String s is not parsable:或者如果输入String s的格式不可解析,则稍后:

throw NumberFormatException.forInputString(s); 

What is a NumberFormatException ?什么是NumberFormatException

Thrown to indicate that the application has attempted to convert a string to one of the numeric types, but that the string does not have the appropriate format.抛出以指示应用程序已尝试将字符串转换为其中一种数字类型,但该字符串没有适当的格式。

- Documentation - 文档

NumberFormatException extends IllegalArgumentException . NumberFormatException extends IllegalArgumentException It tells us that it's more specialized IllegalArgumentException .它告诉我们它更专业IllegalArgumentException Indeed, it's used for highlighting that although, the argument type was correct ( String ) the content of the String wasn't numeric ( a,b,c,d,e,f are considered digits in HEX and are legal when needed ).实际上,它用于强调尽管参数类型是正确的( String ),但String的内容不是数字( a,b,c,d,e,f 在 HEX 中被视为数字,并且在需要时是合法的)。

How do I fix it?我如何解决它?
Well, don't fix the fact that it's thrown.好吧,不要修复它被抛出的事实。 It's good that it's thrown.扔掉就好了。 There are some things you need to consider:您需要考虑一些事项:

  1. Can I read the stacktrace?我可以阅读堆栈跟踪吗?
  2. Is the String which causes an Exception a null ?导致ExceptionStringnull吗?
  3. Does it look like a number?它看起来像一个数字吗?
  4. Is it 'my string' or user's input?是“我的字符串”还是用户的输入?
  5. to be continued未完待续

Ad.广告。 1. 1.

The first line of a message is an information that the Exception occurred and the input String which caused the problem.消息的第一行是发生异常的信息以及导致问题的输入String The String always follows : and is quoted ( "some text" ).字符串始终跟随:并被引用( "some text" )。 Then you become interested in reading the stacktrace from the end, as the first few lines are usually NumberFormatException 's constructor, parsing method etc. Then at the end, there is your method in which you made a bug.然后你开始对从最后读取堆栈跟踪感兴趣,因为前几行通常是NumberFormatException的构造函数、解析方法等。最后,你的方法中出现了错误。 It will be pointed out in which file it was called and in which method.将指出它是在哪个文件中调用的以及在哪个方法中调用的。 Even a line will be attached.甚至会附加一条线。 You'll see.你会看到的。 The example of how to read the stacktrace is above.上面是如何读取堆栈跟踪的示例。

Ad.广告。 2. 2.

When you see, that instead of "For input string:" and the input, there is a null ( not "null" ) it means, that you tried to pass the null reference to a number.当您看到,而不是"For input string:"和输入时,有一个null不是"null" ),这意味着您试图将 null 引用传递给一个数字。 If you actually want to treat is as 0 or any other number, you might be interested in my another post on StackOverflow.如果您真的想将 is 视为 0 或任何其他数字,您可能会对我在 StackOverflow 上的另一篇文章感兴趣。 It's available here .在这里可用。

The description of solving unexpected null s is well described on StackOverflow thread What is a NullPointerException and how can I fix it? StackOverflow 线程上很好地描述了解决意外null的描述什么是 NullPointerException 以及如何修复它? . .

Ad.广告。 3. 3.

If the String that follows the : and is quoted looks like a number in your opinion, there might be a character which your system don't decode or an unseen white space.如果:后面的String在您看来看起来像一个数字,则可能存在您的系统未解码的字符或看不见的空格。 Obviously " 6" can't be parsed as well as "123 " can't.显然" 6"不能被解析, "123 "也不能。 It's because of the spaces.这是因为空间。 But it can occure, that the String will look like "6" but actually it's length will be larger than the number of digits you can see.但它可能会发生, String看起来像"6" ,但实际上它的长度会大于您可以看到的位数。

In this case I suggest using the debugger or at least System.out.println and print the length of the String you're trying to parse.在这种情况下,我建议使用调试器或至少使用System.out.println并打印您尝试解析的String的长度。 If it shows more than the number of digits, try passing stringToParse.trim() to the parsing method.如果显示的位数超过位数,请尝试将stringToParse.trim()传递给解析方法。 If it won't work, copy the whole string after the : and decode it using online decoder.如果它不起作用,请复制:之后的整个字符串并使用在线解码器对其进行解码。 It'll give you codes of all characters.它会给你所有字符的代码。

There is also one case which I have found recently on StackOverflow , that you might see, that the input looks like a number eg "1.86" and it only contains those 4 characters but the error still exists.我最近在StackOverflow上发现了一种情况,您可能会看到,输入看起来像一个数字,例如"1.86" ,它只包含这 4 个字符,但错误仍然存​​在。 Remember, one can only parse integers with #Integer#parseInt#.请记住,只能使用#Integer#parseInt# 解析整数。 For parsing decimal numbers, one should use Double#parseDouble .对于解析十进制数,应该使用Double#parseDouble

Another situation is, when the number has many digits.另一种情况是,当数字有很多位时。 It might be, that it's too large or too small to fit int or long .可能是它太大或太小而无法容纳intlong You might want to try new BigDecimal(<str>) .您可能想尝试new BigDecimal(<str>)

Ad.广告。 4. 4.

Finally we come to the place in which we agree, that we can't avoid situations when it's user typing "abc" as a numeric string.最后,我们达成了共识,我们无法避免用户将“abc”作为数字字符串键入的情况。 Why?为什么? Because he can.因为他可以。 In a lucky case, it's because he's a tester or simply a geek.在幸运的情况下,这是因为他是一名测试人员,或者只是一个极客。 In a bad case it's the attacker.在糟糕的情况下,它是攻击者。

What can I do now?我现在能做什么? Well, Java gives us try-catch you can do the following:那么,Java 为我们提供了try-catch ,您可以执行以下操作:

try {
    i = Integer.parseInt(myString);
} catch (NumberFormatException e) {
    e.printStackTrace();
    //somehow workout the issue with an improper input. It's up to your business logic.
}

What is a NumberFormatException ?什么是NumberFormatException

This exception is thrown to indicate that the application has attempted to convert a string to one of the numeric types, but that the string does not have the appropriate format.引发此异常以指示应用程序已尝试将string转换为其中一种数字类型,但该string没有适当的格式。

In your case, according to your stack trace this exception was thrown by Integer.parseInt(String) which means that the provided String does not contain a parseable integer .在您的情况下,根据您的堆栈跟踪,此异常是由Integer.parseInt(String)引发的,这意味着提供的String不包含可解析的integer And still according to the stack trace, it is due to the fact that you tried to parse the String " Ace of Clubs " as an integer which cannot work as it is not the String representation of an integer.仍然根据堆栈跟踪,这是由于您尝试将StringAce of Clubs ”解析为无法工作的整数,因为它不是整数的String表示形式。

How to fix it?如何解决?

The simplest and generic way is to catch the exception NumberFormatException最简单通用的方法是捕获异常NumberFormatException

int value = -1;
try {
    value = Integer.parseInt(myString);
} catch (NumberFormatException e) {
    // The format was incorrect
}

It will work but catching an exception is slow because it needs to build the call stack to create the Exception which is costly, so if you can avoid it do it.它会起作用,但捕获异常很慢,因为它需要构建调用堆栈来创建开销很大的Exception ,所以如果你能避免它就这样做。 Moreover you will need to manage the exception properly which is not always obvious.此外,您将需要正确管理异常,这并不总是显而易见的。

Or you could use a regular expression to check first if the String matches with an Integer but it is quite error prone as you could easily use a wrong regular expression .或者,您可以先使用regular expression检查String是否与Integer matches ,但这很容易出错,因为您很容易使用错误的regular expression


In your case, a more OO approach should be used instead of dealing with String , for example you could use a class or an enum to represent your cards instead of using simple String because it is much more error prone as you have already noticed.在您的情况下,应该使用更面向对象的方法而不是处理String ,例如,您可以使用classenum来表示您的卡片,而不是使用简单的String ,因为您已经注意到它更容易出错。

So if you decide to use a dedicated class for your card, your code could be:因此,如果您决定为您的卡使用专用类,您的代码可能是:

public class Card {

    private final Rank rank;
    private final Suit suit;

    public Card(final Rank rank, final Suit suit) {
        this.rank = rank;
        this.suit = suit;
    }

    public Rank getRank() {
        return this.rank;
    }

    public Suit getSuit() {
        return this.suit;
    }
}

For the suit and the rank of a card, we can use an enum since there are limited amounts of existing ranks and suits.对于卡片的花色和等级,我们可以使用enum ,因为现有的等级和花色数量有限。

public enum Rank {
    ACE(1), TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6), SEVEN(7), HEIGHT(8),
    NINE(9), TEN(10), JACK(11), QUEEN(12), KING(13);

    private final int value;

    Rank(final int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }
}

public enum Suit {
    SPADE, HEART, DIAMOND, CLUB
}

Then cards would be an array of Card instead of an array of String , and could be initialized as next:那么cards将是一个Card数组而不是String数组,并且可以如下初始化:

Rank[] ranks = Rank.values();
Suit[] suits = Suit.values();
Card[] cards = new Card[ranks.length * suits.length];
for (int i = 0; i < ranks.length; i++) {
    for (int j = 0; j < suits.length; j++) {
        cards[i * suits.length + j] = new Card(ranks[i], suits[j]);
    }
}

If you need to shuffle your array of cards, you can proceed as next (please note that if you decide to use a List of cards instead of an array simply use Collections.shuffle(list) )如果你需要洗牌你的卡片数组,你可以继续下一步(请注意,如果你决定使用卡片List而不是数组,只需使用Collections.shuffle(list)

List<Card> allCards = Arrays.asList(cards);
Collections.shuffle(allCards);
allCards.toArray(cards);

Then you will be able to access directly to the value of your card with cards[index].getRank().getValue() without taking the risk to get an exception (except an IndexOutOfBoundsException if you don't use a proper index).然后,您将能够使用cards[index].getRank().getValue()直接访问您的卡的值,而无需冒险获得异常(如果您不使用正确的索引,则IndexOutOfBoundsException除外)。

看起来cards[]String数组,您正在尝试将Ace of Clubs转换为Integer

int first_value = Integer.parseInt(cards[index]);
java.lang.NumberFormatException 

occurs when you are trying to parse some input which not a Number string.当您尝试解析一些不是数字字符串的输入时发生。

In your case your trying to parse a string (which not has number )as Integer.在您的情况下,您尝试将字符串(没有数字)解析为整数。 As its not possible NumberFormatException exception occured.因为它不可能发生 NumberFormatException 异常。

int first_value = Integer.parseInt(cards[index]);//cards[index] value should be //number string "123" not "abc"

A NumberFormatException is the way Java has to say you "I tried to convert a String to int and I could not do it". NumberFormatException 是 Java 必须告诉您“我试图将 String 转换为 int 但我做不到”的方式。

In your exception trace you can read在您的异常跟踪中,您可以阅读

Exception in thread "main" java.lang.NumberFormatException: For input string: "Ace of Clubs"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at set07102.Cards.main(Cards.java:68)

Basically, it means that at the line 68 of your code you call to the Integer.parseInt method passing "Ace of Clubs" as paremeter.基本上,这意味着在代码的第 68 行调用 Integer.parseInt 方法,将“Ace of Clubs”作为参数传递。 This method expects a integer value represented as String, eg "4", so method complains throwing a NumberFormatException because "Ace of Clubs" does not seem a integer at all.此方法需要一个表示为字符串的整数值,例如“4”,因此该方法抱怨抛出 NumberFormatException,因为“Ace of Clubs”似乎根本不是整数。

A NumberFormatException means that Integer.parseInt() couldn't translate the string into a number. NumberFormatException意味着Integer.parseInt()无法将字符串转换为数字。

I would suggest one of two options:我会建议以下两种选择之一:

  1. Encapsulate cards as a name(string)/value(int) combo.将卡片封装为名称(字符串)/值(整数)组合。 Use the value to do comparisons, and the name to present info to the user.使用值进行比较,使用名称向用户呈现信息。 Cards[] then becomes a list of cards, not strings. Cards[]然后变成卡片列表,而不是字符串。

  2. Parse the strings yourself.自己解析字符串。 Which may be easier, since you've already done it with the if(cards[index].startsWith("Ace")) { value = 1; }这可能更容易,因为您已经使用if(cards[index].startsWith("Ace")) { value = 1; } if(cards[index].startsWith("Ace")) { value = 1; } bits. if(cards[index].startsWith("Ace")) { value = 1; }位。 You can move those into a function called CardToInt() (or whatever), and use that function instead of Integer.parseInt() .您可以将它们移动到一个名为CardToInt() (或其他)的函数中,并使用该函数而不是Integer.parseInt()

The very first thing that threw me for a loop (no pun intended) was you were limiting the value to 1-13 when it needs to be 0-52.让我陷入循环的第一件事(不是双关语)是当它需要为 0-52 时,您将值限制为 1-13。 Also with your logic the value was always be higher.同样根据您的逻辑,价值总是更高。 A better approach is with a number generator.更好的方法是使用数字生成器。 Here is my code using a number generator (or Java Random):这是我使用数字生成器(或 Java Random)的代码:

public static void main(String[] args) {

String[] cards = { "Ace of Clubs", "1 of Clubs", "2 of Clubs",
        "3 of Clubs", "4 of Clubs", "5 of Clubs", "6 of Clubs",
        "7 of Clubs", "8 of Clubs", "9 of Clubs", "10 of Clubs",
        "Queen of Clubs", "King of Clubs", "Ace of Diamonds",
        "1 of Diamonds", "2 of Diamonds", "3 of Diamonds",
        "4 of Diamonds", "5 of Diamonds", "6 of Diamonds",
        "7 of Diamonds", "8 of Diamonds", "9 of Diamonds",
        "10 of Diamonds", "Queen of Diamonds", "King of Diamonds",
        "Ace of Hearts", "1 of Hearts", "2 of Hearts", "3 of Hearts",
        "4 of Hearts", "5 of Hearts", "6 of Hearts", "7 of Hearts",
        "8 of Hearts", "9 of Hearts", "10 of Hearts",
        "Queen of Hearts", "King of Hearts", "Ace of Spades",
        "1 of Spades", "2 of Spades", "3 of Spades", "4 of Spades",
        "5 of Spades", "6 of Spades", "7 of Spades", "8 of Spades",
        "9 of Spades", "10 of Spades", "Queen of Spades",
        "King of Spades" };

Scanner scanner = new Scanner(System.in);
Random rand = new Random();
String response = "";
int index = 0;
int value = 0;  
while (!response.equals("q") && index < 52) {

    // set next card value based on current set of cards in play
    if (cards[index].endsWith("Clubs")) {
        value = rand.nextInt(12);
    }
    if (cards[index].endsWith("Diamonds")) {
        value = rand.nextInt(12) + 13;
    }
    if (cards[index].endsWith("Hearts")) {
        value = rand.nextInt(12) + 26;
    }
    if (cards[index].endsWith("Spades")) {
        value = rand.nextInt(12) + 39;
    }

    // display card too user (NOTE: we use the random number not the index)
    System.out.println("Card is: " + cards[value]);

    // ask user what well the next card be
    System.out.println("Will the next card be higher or lower?, press q if you want to quit");
    response = scanner.nextLine();

    // display if user was right (NOTE: compared the random number to the current index)
    // ignore incorrect response and just continue
    if ((value > index && response.startsWith("h")) || (value < index && response.startsWith("l"))) {
        System.out.println("You answer was right, well done!");
    } else {
        System.out.println("You answer was wrong, try again!");
    }

    // continue loop
    index++;
}
}

As for the NumberFormatException I believe Nicolas Filotto did a good job explaining that.至于 NumberFormatException,我相信 Nicolas Filotto 很好地解释了这一点。

int first_value = Integer.parseInt(cards[index]); 

while writing the above statement, you are trying to parse "Ace of Clubs" as a number.在编写上述语句时,您正试图将“Ace of Clubs”解析为一个数字。

you can use the following method to test if any string can be parsed as Integer:您可以使用以下方法测试是否可以将任何字符串解析为整数:

boolean tryParseInt(String value) {  
     try {  
         Integer.parseInt(value);  
         return true;  
      } catch (NumberFormatException e) {  
         return false;  
      }  
}

Regarding your question, what is NumberFormatException : It is thrown to indicate that the application has attempted to convert a string to one of the numeric types, but that the string does not have the appropriate format.关于您的问题,什么是 NumberFormatException :抛出它表明应用程序已尝试将字符串转换为其中一种数字类型,但该字符串没有适当的格式。 (ref - http://docs.oracle.com/javase/7/docs/api/java/lang/NumberFormatException.html ) (参考 - http://docs.oracle.com/javase/7/docs/api/java/lang/NumberFormatException.html

The Exception comes in your code, where you convert the String to an Integer :异常出现在您的代码中,您可以在其中将 String 转换为 Integer :

int first_value = Integer.parseInt(cards[index]);

where you pass a String as "Ace of Clubs" which is not possible to convert as integer,so it throws Number Format Exception.您将字符串作为“梅花王牌”传递,该字符串无法转换为整数,因此会引发数字格式异常。 You can use,您可以使用,

try {
     ....
     // Your Code
     ....
    }
catch(NumberFormatException e)
{
    e.getMessage();  //You can use anyone like printStackTrace() ,getMessage() to handle the Exception
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM