什么是 NumberFormatException,如何修复它?

What is a NumberFormatException and how can I fix it?

提问人:Qasim Imtiaz 提问时间:10/4/2016 最后编辑:xenterosQasim Imtiaz 更新时间:8/29/2022 访问量:129665

问:

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)

我的 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
Java 数组 while-loop numberformatexception

评论

8赞 khelwood 10/4/2016
int first_value = Integer.parseInt(cards[index]);- 您正在尝试将字符串解析为 int,但该字符串是 ."Ace of Clubs"
1赞 AxelH 10/12/2016
你错过了一张卡......金是13岁,女王是12岁,杰克是11岁,只是说;)您应该使用 if else,因为您不能有以 和 开头的卡。为什么使用索引限制 52 ?您没有使用颜色。最后一件事,如果您尝试,您将在结束前收到一条无效的应答消息。对于错误,一切都说了。king3q

答:

6赞 Vivek G 10/4/2016 #1

看起来像是字符串数组,您正在尝试转换为整数cards[]Ace of Clubs

int first_value = Integer.parseInt(cards[index]);
50赞 xenteros 10/4/2016 #2
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

方法:

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

换句话说,您尝试解析为 Java 无法用方法执行的操作。Java 提供了漂亮的堆栈跟踪,可以准确地告诉您问题所在。你要找的工具是调试器,使用断点可以检查应用程序在所选时刻的状态"Ace of Clubs"intInteger.parseInt

如果要使用解析,解决方案可能是以下逻辑:

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

什么是 Java 中的异常

异常是在执行 程序,这会扰乱程序指令的正常流程。

-文档

构造函数和用法Integer#parseInt

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

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

它们对于了解如何读取堆栈跟踪非常重要。看看它是如何抛出的:NumberFormatExceptionInteger#parseInt

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

如果输入的格式不可解析,则稍后:String s

throw NumberFormatException.forInputString(s); 

什么是 NumberFormatException

引发以指示应用程序已尝试将字符串转换为数值类型之一,但该字符串没有适当的格式。

-文档

NumberFormatException extends IllegalArgumentException.它告诉我们它更专业。事实上,它用于强调,尽管参数类型是正确的(),但内容不是数字(a,b,c,d,e,f在十六进制中被视为数字,并且在需要时是合法的)。IllegalArgumentExceptionStringString

我该如何解决?
好吧,不要修复它被抛出的事实。它被扔掉是件好事。您需要考虑以下几点:

  1. 我可以读取堆栈跟踪吗?
  2. 是导致一个?StringExceptionnull
  3. 它看起来像一个数字吗?
  4. 是“我的字符串”还是用户的输入?
  5. 未完待续

广告 1.

消息的第一行是发生异常的信息以及导致问题的输入。String 始终跟在后面并用引号 () 括起来。然后你就会对从最后读取堆栈跟踪感兴趣,因为前几行通常是 的构造函数、解析方法等。最后,是你犯了一个错误的方法。将指出它是在哪个文件中调用的,以及在哪个方法中调用的。甚至还会附上一条线。你会知道的。上面是如何读取堆栈跟踪的示例。String:"some text"NumberFormatException

广告 2.

当您看到,而不是输入,有一个(不是“null”)时,这意味着您试图将 null 引用传递给一个数字。如果你真的想把 is 当作 0 或任何其他数字,你可能会对我在 StackOverflow 上的另一篇文章感兴趣。它可在此处获得。"For input string:"null

解决意外 s 的描述在 StackOverflow 线程上有很好的描述 什么是 NullPointerException 以及如何修复它?.null

广告 3.

如果 后面的 和 在您看来看起来像一个数字,则可能存在您的系统无法解码的字符或看不见的空格。显然不能被解析,也不能被解析。这是因为空间。但它可能会发生,看起来,但实际上它的长度会大于你可以看到的位数。String:" 6""123 "String"6"

在这种情况下,我建议使用调试器,或者至少打印您尝试解析的长度。如果它显示的位数超过位数,请尝试传递给解析方法。如果它不起作用,请在 之后复制整个字符串并使用在线解码器对其进行解码。它会给你所有字符的代码。System.out.printlnStringstringToParse.trim():

我最近还发现了一种情况,您可能会看到,输入看起来像一个数字,例如 它只包含这 4 个字符,但错误仍然存在。请记住,只能使用 #Integer#parseInt# 解析整数。要解析十进制数,应使用 。StackOverflow"1.86"Double#parseDouble

另一种情况是,当数字有很多位数时。可能是太大或太小而无法容纳或.您可能想尝试 .intlongnew BigDecimal(<str>)

广告 4.

最后,我们来到了我们同意的地方,即我们无法避免用户将“abc”作为数字字符串键入的情况。为什么?因为他可以。在幸运的情况下,这是因为他是一个测试人员,或者只是一个极客。在糟糕的情况下,是攻击者。

我现在能做什么?好吧,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.
}

评论

0赞 Abhineet 10/12/2016
“黑桃A”???此外,在您的描述性错误详细信息中,我认为第二个 Integer.parseInt 的行号(615 到 580)有一个拼写错误。
1赞 xenteros 10/13/2016
当我有时间时,我会把重点放在第 5 点的太大数字上。
2赞 GhostCat 12/2/2017
一个美丽的答案。我想我应该更频繁地接近这个问题;-)
1赞 xenteros 12/2/2017
@GhostCat 这就是我准备这个答案的原因
1赞 xenteros 4/24/2018
@OleV.V.确定!更新
11赞 Nicolas Filotto 10/12/2016 #3

什么是?NumberFormatException

引发此异常以指示应用程序具有 尝试将 A 转换为数值类型之一,但 没有适当的格式。stringstring

在您的例子中,根据您的堆栈跟踪,此异常是由 Integer.parseInt(String) 引发的,这意味着提供的不包含可解析的 .仍然根据堆栈跟踪,这是由于您试图将“Ace of Clubs”解析为一个整数,因为它不是整数的表示,因此无法工作。StringintegerStringString

如何解决?

最简单和通用的方法是捕获异常NumberFormatException

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

它会起作用,但捕获异常很慢,因为它需要构建调用堆栈来创建成本高昂的调用堆栈,所以如果你能避免它,那就去做吧。此外,您需要正确管理异常,这并不总是显而易见的。Exception

或者你可以先用 a 来检查是否与 an 匹配,但它很容易出错,因为你很容易使用错误的 .regular expressionStringIntegerregular expression


在你的例子中,应该使用更多的OO方法而不是处理,例如,你可以使用a或an来表示你的卡片,而不是使用simple,因为它更容易出错,正如你已经注意到的那样。StringclassenumString

因此,如果您决定为您的卡使用专用类,您的代码可以是:

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

对于牌的花色和等级,我们可以使用,因为现有的等级和花色数量有限。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
}

然后是一个数组 而不是 的数组 ,并且可以初始化为 next:cardsCardString

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

如果您需要洗牌,您可以按照下一步进行(请注意,如果您决定使用 a of cards 而不是 array 只需使用ListCollections.shuffle(list))

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

然后,您将能够直接访问您的卡的价值,而无需冒获得异常的风险(除非您没有使用适当的索引)。cards[index].getRank().getValue()IndexOutOfBoundsException

评论

0赞 xenteros 10/13/2016
我不同意你的论点,即捕捉 NFE 是丑陋的。在大型系统中,当您可以假设用户将提供非数字输入,而另一方面,您希望保持日志干净时,最好捕获它并记录信息或抛出您自己的服务异常,而不是让整个堆栈跟踪以红色打印。
3赞 Nicolas Filotto 10/13/2016
@xenteros一般来说,捕获异常很慢,因为它需要构建调用堆栈来创建成本高昂的异常,所以如果你可以避免它,那就去做,但有时你就是无法避免它。在这里,您可以通过使用真正的 OO 方法来避免它,这就是我建议的Exception
1赞 thekodester 10/18/2016 #4

让我陷入循环的第一件事(没有双关语的意思)是,当它需要为 0-52 时,您将值限制为 1-13。此外,根据您的逻辑,该值总是更高。更好的方法是使用数字生成器。这是我使用数字生成器(或 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++;
}
}

至于 NumberFormatException,我相信 Nicolas Filotto 很好地解释了这一点。

1赞 Anands23 10/18/2016 #5

异常出现在您的代码中,您将 String 转换为 Integer :

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

其中,您将字符串作为“Ace of Clubs”传递,该字符串无法转换为整数,因此会引发数字格式异常。您可以使用,

try {
     ....
     // Your Code
     ....
    }
catch(NumberFormatException e)
{
    e.getMessage();  //You can use anyone like printStackTrace() ,getMessage() to handle the Exception
}
2赞 Andrew Tofelt 10/19/2016 #6

无法将字符串转换为数字的表示。NumberFormatExceptionInteger.parseInt()

我建议以下两个选项之一:

  1. 将卡片封装为 name(string)/value(int) 组合。使用值进行比较,使用名称向用户显示信息。 然后变成卡片列表,而不是字符串。Cards[]

  2. 自己解析字符串。这可能更容易,因为您已经用位完成了。您可以将它们移动到一个名为(或其他)的函数中,并使用该函数而不是 .if(cards[index].startsWith("Ace")) { value = 1; }CardToInt()Integer.parseInt()

3赞 Rajesh Gopu 10/19/2016 #7
java.lang.NumberFormatException 

当您尝试解析某些不是 Number 字符串的输入时发生。

在你的情况下,你试图将一个字符串(没有数字)解析为整数。 因为它是不可能的 发生 NumberFormatException 异常。

int first_value = Integer.parseInt(cards[index]);//cards[index] value should be //number string "123" not "abc"
1赞 roopaliv 10/19/2016 #8
int first_value = Integer.parseInt(cards[index]); 

在编写上述语句时,您正在尝试将“Ace of Clubs”解析为一个数字。

您可以使用以下方法来测试是否可以将任何字符串解析为 Integer:

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

关于您的问题,什么是 NumberFormatException :抛出它以指示应用程序已尝试将字符串转换为数值类型之一,但字符串没有适当的格式。(参考 -http://docs.oracle.com/javase/7/docs/api/java/lang/NumberFormatException.html)

3赞 jmlotero 10/19/2016 #9

NumberFormatException 是 Java 对你说“我试图将 String 转换为 int 但无法做到”的方式。

在异常跟踪中,您可以读取

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)

基本上,这意味着在代码的第 68 行,您调用 Integer.parseInt 方法,将“Ace of Clubs”作为参数传递。此方法需要一个表示为 String 的整数值,例如“4”,因此该方法抱怨抛出 NumberFormatException,因为“Ace of Clubs”看起来根本不是整数。