什么是 NumberFormatException,我该如何解决?

Posted

技术标签:

【中文标题】什么是 NumberFormatException,我该如何解决?【英文标题】:What is a NumberFormatException and how can I fix it? 【发布时间】:2017-02-12 11:35:26 【问题描述】:
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

【问题讨论】:

int first_value = Integer.parseInt(cards[index]); - 您试图将字符串解析为 int,但字符串为 "Ace of Clubs" 你少了一张卡片……国王是 13 岁,王后是 12 岁,杰克是 11 岁,只是说 ;) 你应该使用 if else 因为你不能拥有以 king 开头的卡片还有3。你为什么使用 52 的索引限制?你没有使用颜色。最后一件事,如果您尝试q,您将在结束前收到无效的回复消息。对于错误,一切都说了。 【参考方案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

换句话说,您尝试将"Ace of Clubs" 解析为int,这是Java 无法使用方法Integer.parseInt 完成的。 Java 提供了漂亮的堆栈跟踪,它可以准确地告诉您问题所在。您正在寻找的工具是 debugger,使用 breakpoints 可以让您在选定的时刻检查您的应用程序的状态

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

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 中的 Exception

异常是一个事件,它发生在一个事件的执行过程中 程序,这会破坏程序指令的正常流程。

-Documentation

Integer#parseInt中的构造函数和用法

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


public NumberFormatException (String s) 
    super (s);

它们对于理解如何阅读堆栈跟踪很重要。看看NumberFormatException是怎么从Integer#parseInt抛出来的:

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

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

throw NumberFormatException.forInputString(s); 

什么是NumberFormatException

抛出表明应用程序已尝试将字符串转换为其中一种数字类型,但该字符串没有适当的格式。

-Documentation

NumberFormatExceptionextendsIllegalArgumentException。它告诉我们它更专业IllegalArgumentException。实际上,它用于强调尽管参数类型正确(StringString 的内容不是数字(a,b,c,d,e,f 在 HEX 中被视为数字并且在需要时是合法的)。

我该如何解决? 好吧,不要修复它被抛出的事实。扔掉就好了。您需要考虑一些事项:

    我可以读取堆栈跟踪吗? 导致ExceptionStringnull 吗? 它看起来像一个数字吗? 是“我的字符串”还是用户的输入? 待续

广告。 1.

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

广告。 2.

当您看到 "For input string:" 和输入而不是 null不是 "null")时,这意味着您尝试将空引用传递给数字.如果您真的想将 is 视为 0 或任何其他数字,您可能会对我在 *** 上的另一篇文章感兴趣。它可用here。

解决意外nulls 的描述在 *** 线程What is a NullPointerException and how can I fix it? 上有很好的描述。

广告。 3.

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

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

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

另一种情况是,当数字有很多位时。它可能太大或太小而无法容纳intlong。你可能想试试new BigDecimal(&lt;str&gt;)

广告。 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.

【讨论】:

“黑桃 A” ???此外,在您的描述性错误详细信息中,我认为您的第二个 Integer.parseInt 的行号(615 到 580)有错字。 当我有时间的时候,我会专注于太大的数字,而不是 5 一个漂亮的答案。我想我应该更频繁地回答这个问题;-) @GhostCat 这就是我准备这个答案的原因 @OleV.V.当然!更新【参考方案2】:

什么是NumberFormatException

抛出此异常表示应用程序有 试图将 string 转换为其中一种数字类型,但是 string 没有适当的格式。

在您的情况下,根据您的堆栈跟踪,此异常是由Integer.parseInt(String) 引发的,这意味着提供的String 不包含可解析的integer。仍然根据堆栈跟踪,这是因为您尝试将 String "Ace of Clubs" 解析为一个整数,因为它不是 String 表示,所以它不能工作整数。

如何解决?

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

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

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

或者您可以先使用regular expression 来检查String matches 是否带有Integer,但这很容易出错,因为您很容易使用错误的regular expression


在您的情况下,应该使用更面向对象的方法而不是处理String,例如,您可以使用classenum 来表示您的卡片,而不是使用简单的String,因为它是正如您已经注意到的那样,更容易出错。

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

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

那么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]);
    

如果您需要洗牌阵列,您可以继续下一步(请注意,如果您决定使用 List 的卡片而不是阵列,只需使用 Collections.shuffle(list)

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

然后,您将能够通过cards[index].getRank().getValue() 直接访问您卡的价值,而无需冒险获得异常(如果您不使用正确的索引,则IndexOutOfBoundsException 除外)。

【讨论】:

我不同意你的论点,捕捉 NFE 是丑陋的。在大型系统中,当您可以假设用户将提供非数字输入,另一方面您希望保持日志干净时,最好捕获它并记录信息或抛出您自己的服务异常,而不是让整个堆栈跟踪以红色打印。 @xenteros 一般来说,捕获异常很慢,因为它需要构建调用堆栈来创建 Exception,这很昂贵,所以如果你可以避免它,但有时你就是不能躲开它。在这里,您可以使用我建议的真正的 OO 方法来避免它【参考方案3】:

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

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

【讨论】:

【参考方案4】:
java.lang.NumberFormatException 

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

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

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

【讨论】:

【参考方案5】:

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”作为参数传递。此方法需要一个表示为字符串的整数值,例如“4”,因此方法抱怨抛出 NumberFormatException,因为“梅花王牌”似乎根本不是整数。

【讨论】:

【参考方案6】:

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

我会建议以下两种选择之一:

    将卡片封装为名称(字符串)/值(整数)组合。使用值进行比较,使用名称向用户呈现信息。 Cards[] 然后变成卡片列表,而不是字符串。

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

【讨论】:

【参考方案7】:

让我陷入循环的第一件事(不是双关语)是当它需要为 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 很好地解释了这一点。

【讨论】:

【参考方案8】:
int first_value = Integer.parseInt(cards[index]); 

在编写上述语句时,您试图将“梅花王牌”解析为一个数字。

您可以使用以下方法测试是否有任何字符串可以解析为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)

【讨论】:

【参考方案9】:

异常出现在您的代码中,您可以在其中将字符串转换为整数:

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

【讨论】:

以上是关于什么是 NumberFormatException,我该如何解决?的主要内容,如果未能解决你的问题,请参考以下文章

创建短号码时出现 NumberFormatException

java.lang.NumberFormatException:对于输入字符串:“某事”

java.lang.NumberFormatException:对于输入字符串:“ 7001”。在WLST中,此错误的含义是什么,我该如何解决?

Java Servlet NumberFormatException

java.lang.NumberFormatException: multiple points错误问题

为啥“prepareCall”会抛出 NumberFormatException?