什么是NumberFormatException,我该如何修复它?Java 中的异常是什么?什么是NumberFormatException?

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

答案 1
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提供了漂亮的stacktrace,它准确地告诉你问题是什么。您要查找的工具是调试器,使用断点将允许您在所选时刻检查应用程序的状态"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在HEX中被认为是数字,并且在需要时是合法的)。IllegalArgumentExceptionStringString

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

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

广告1.

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

广告2.

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

解决意外的描述在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.
}

答案 2

什么是 ?NumberFormatException

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

在您的例子中,根据您的堆栈跟踪,此异常是由 Integer.parseInt(String) 引发的,这意味着提供的 不包含可解析的 。并且仍然根据堆栈跟踪,这是由于您尝试将“俱乐部王牌”解析为整数的事实,该整数无法工作,因为它不是整数的表示形式。StringintegerStringString

如何解决?

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

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

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

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


在你的例子中,应该使用一种更直观的方法而不是处理,例如,你可以使用a或an来表示你的卡,而不是使用简单,因为它更容易出错,因为你已经注意到了。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
}

然后将是 一个数组,而不是 一个 数组 ,并且可以初始化如下: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]);
    }
}

如果您需要随机播放您的卡阵列,则可以按下一步操作(请注意,如果您决定使用一张卡而不是数组,只需使用ListCollections.shuffle(list))

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

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