【问题标题】:Why object of array from file has NumberFormatException in Java?为什么文件中的数组对象在 Java 中有 NumberFormatException?
【发布时间】:2020-10-03 04:15:11
【问题描述】:

我需要逐行读取 .txt 文件并将每一行存储到一个数组中。每个数组有 3 个元素,empId、name、salary,它们是 SalariedEmployee 类的字段。我的代码有一个 NumberFormatException,我不知道哪一步出错了。任何提示或帮助将不胜感激。谢谢。请不要关闭我的问题,我是 Java 的初学者。

异常信息:

Exception in thread "main" java.lang.NumberFormatException: For input string: "Kelsey"
at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054)
at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.base/java.lang.Double.parseDouble(Double.java:549)
at com.maoding.Hw3_Part2.main(Hw3_Part2.java:23)

.txt 文件:

1, Kelsey, 65000
2, Jake, 89000
3, Carlos, 105000
4, Clarence, 58000
5, Pacheco, 68000
6, Piotr, 120000
7, Adam, 47000
8, Yorst, 77000
9, Silas, 93000
10, Yapsiong, 85000

SaliedEmployee 类:

public class SalariedEmployee {
// instance variable
    public int empId;
    public String name;
    public double salary;

// constructor
    public SalariedEmployee(int empId, String name, double salary) {
        this.empId = empId;
        this.name = name;
        this.salary = salary;
}
// get methods
    public int getEmpId() {
        return empId;
}

    public String getName(){
        return name;
}

    public double getSalary(){
        return salary;
}

主类:

public class Hw3_Part2 {
    public static void main(String[] args) throws IOException {
        int empId;
        String name;
        double salary;

        String[] words;
        Scanner fileInput = new Scanner(new File("/Users/hw3_employees.txt"));
        while (fileInput.hasNextLine()) {
            words = fileInput.nextLine().split(",|\\s+");
       
            for (int i = 0; i < words.length; i++) {
                empId = Integer.parseInt(words[0]);
                name = words[1];
                salary = Double.parseDouble(words[2]);
                SalariedEmployee se = new SalariedEmployee(empId, name, salary);
                System.out.println(words);
                System.out.println(se);
            }
    }
}     

【问题讨论】:

  • 在 for 循环中设置断点,打开调试器,然后单步执行代码?
  • 哪一行产生错误。添加错误输出。
  • 感谢您的评论,我更新了异常消息。

标签: java file exception


【解决方案1】:

问题出在你的正则表达式上。

(",|\\s+") - 如果遇到逗号或空格,您将在此处拆分它。管道代表 OR。因此,您的数组实际上大于大小 3。

您需要将其拆分为逗号和空格的组合。所以,你的正则表达式应该是(",\\s+")。它必须是一个逗号,后跟一个空格。

【讨论】:

    【解决方案2】:

    错误是正则表达式模式,|\\s+。它与数组大小不匹配。 我已修改代码以将其更正为,\\s+,并添加了额外的步骤,以便代码不会打印类的哈希码而不是字符串。在 while 循环中也不需要 for loop

    这里是修改后的代码:

    class SalariedEmployee {
    // instance variable
        private int empId;
        private String name;
        private double salary;
    
    // constructor
        public SalariedEmployee(int empId, String name, double salary) {
            this.empId = empId;
            this.name = name;
            this.salary = salary;
        }
    // get methods
        public int getEmpId() {
            int e = this.empId
            return e;
        }
    
        public String getName(){
            String n = this.name;
            return n;
        }
    
        public double getSalary(){
            Double sal = this.salary;
            return sal;
        }
        
        @Override
        public String toString(){
            String s = this.getEmpId()+","+this.getName()+","+this.getSalary();
            return s;
        }
    }
    
    public class Stacktest{
        public static void main(String[] args) throws Exception {
            int empId;
            
            String name;
            double salary;
    
            String[] words;
            Scanner fileInput = new Scanner(new File("File Location here"));
            while (fileInput.hasNextLine()) {
                words = fileInput.nextLine().split(",\\s+");
                //System.out.println(Arrays.toString(words));
                    empId = Integer.parseInt(words[0]);
                    name = words[1].toString();
                    salary = Double.parseDouble(words[2]);
                    SalariedEmployee se = new SalariedEmployee(empId, name, salary);
                    System.out.println(Arrays.toString(words));
                    System.out.println(se.toString());
            }
        }
    }
    

    通常,当您打印对象时,会在内部调用toString()。它返回classname, @ which refers to string and a hashcode of the location。为了克服这个问题,您需要覆盖现有的toString() 方法并发送实际的字符串值。

    覆盖 toString() 之前的输出

    [Ljava.lang.String;@6a5fc7f7
    stacktest.SalariedEmployee@3b6eb2ec
    [Ljava.lang.String;@1e643faf
    stacktest.SalariedEmployee@6e8dacdf
    [Ljava.lang.String;@7a79be86
    stacktest.SalariedEmployee@34ce8af7
    [Ljava.lang.String;@b684286
    stacktest.SalariedEmployee@880ec60
    [Ljava.lang.String;@3f3afe78
    stacktest.SalariedEmployee@7f63425a
    [Ljava.lang.String;@36d64342
    stacktest.SalariedEmployee@39ba5a14
    [Ljava.lang.String;@511baa65
    stacktest.SalariedEmployee@340f438e
    [Ljava.lang.String;@30c7da1e
    stacktest.SalariedEmployee@5b464ce8
    [Ljava.lang.String;@57829d67
    stacktest.SalariedEmployee@19dfb72a
    [Ljava.lang.String;@17c68925
    stacktest.SalariedEmployee@7e0ea639
    
    

    toString() 覆盖后的输出

    [1, Kelsey, 65000]
    1,Kelsey,65000.0
    [2, Jake, 89000]
    2,Jake,89000.0
    [3, Carlos, 105000]
    3,Carlos,105000.0
    [4, Clarence, 58000]
    4,Clarence,58000.0
    [5, Pacheco, 68000]
    5,Pacheco,68000.0
    [6, Piotr, 120000]
    6,Piotr,120000.0
    [7, Adam, 47000]
    7,Adam,47000.0
    [8, Yorst, 77000]
    8,Yorst,77000.0
    [9, Silas, 93000]
    9,Silas,93000.0
    [10, Yapsiong, 85000]
    10,Yapsiong,85000.0
    

    最好将类变量设置为私有并使用公共 getter 和 setter 方法来访问这些类变量。(我这么说是因为您提到您是 java 初学者)。我对代码中的私有变量使用了公共 getter。

    【讨论】:

    • 非常感谢,@vicki。学习压倒一切真是太好了。我的输出现在符合预期。
    【解决方案3】:

    您的问题是对方法 split() 的调用中的正则表达式。

    我将尝试解释调试过程,而不仅仅是发布答案。每个程序员都需要学习如何调试他的代码。也可以参考How to Debug Small Programs

    因为我无法通过本网站的功能向您展示如何在您的 IDE 中使用调试器,所以我将介绍一个替代过程,即插入打印到标准输出(通常是计算机屏幕)的方法.

    由于错误消息告诉您您的程序正在尝试将 Kelsey 解析为数字,这应该表明 words 数组可能不是您期望的那样。因此您需要显示words 的实际值。这就是下面代码的作用。

    public static void main(String[] args) throws IOException {
        int empId;
        String name;
        double salary;
    
        String[] words;
        Scanner fileInput = new Scanner(new File("/Users/hw3_employees.txt"));
        while (fileInput.hasNextLine()) {
            words = fileInput.nextLine().split(",|\\s+");
            System.out.println("words.length = " + words.length); // Added this line
            for (int i = 0; i < words.length; i++) {
                System.out.printf("words[0] = ^%s^%n", words[0]); // Added this line
                empId = Integer.parseInt(words[0]);
                name = words[1];
                System.out.printf("words[1] = ^%s^%n", words[1]); // Added this line.
                salary = Double.parseDouble(words[2]);
                System.out.printf("words[2] = ^%s^%n", words[2]); // Added this line.
                SalariedEmployee se = new SalariedEmployee(empId, name, salary);
                System.out.println(words);
                System.out.println(se);
            }
        }
    }
    

    这是我运行上述代码时得到的输出。

    words.length = 5
    words[0] = ^1^
    words[1] = ^^
    Exception in thread "main" java.lang.NumberFormatException: For input string: "Kelsey"
        at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054)
        at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
        at java.base/java.lang.Double.parseDouble(Double.java:549)
    
    • 首先,我看到words 包含五个元素而不是三个。
    • 我将^ 符号添加到要显示的字符串中,因为它可以帮助我查看值中是否有空格。因此我看到words[1] 是一个空字符串。

    在这个阶段,你应该意识到你需要改变正则表达式。要知道将其更改为什么,请查看 javadoc 中的方法 split()。它有一个指向 java.util.regex.Pattern 类的链接,它解释了 java 正则表达式引擎的工作原理。然后尝试做实验。编写一个单独的程序。硬编码文本文件中的一行字符串,然后查看不同正则表达式的结果,直到找到正确的。

    现在,我要告诉你解决问题的一种方法是拆分单独的逗号,然后trim每个“单词”。

    public static void main(String[] args) throws IOException {
        int empId;
        String name;
        double salary;
    
        String[] words;
        Scanner fileInput = new Scanner(new File("/Users/hw3_employees.txt"));
        while (fileInput.hasNextLine()) {
            words = fileInput.nextLine().split(",");
            System.out.println("words.length = " + words.length);
            for (int i = 0; i < words.length; i++) {
                System.out.printf("words[0] = ^%s^%n", words[0]);
                empId = Integer.parseInt(words[0].trim());
                name = words[1];
                System.out.printf("words[1] = ^%s^%n", words[1]);
                salary = Double.parseDouble(words[2].trim());
                System.out.printf("words[2] = ^%s^%n", words[2]);
                SalariedEmployee se = new SalariedEmployee(empId, name, salary);
                System.out.println(words);
                System.out.println(se);
            }
        }
    }
    

    现在输出是。

    words.length = 3
    words[0] = ^1^
    words[1] = ^ Kelsey^
    words[2] = ^ 65000^
    [Ljava.lang.String;@49c2faae
    SalariedEmployee@20ad9418
    words[0] = ^1^
    words[1] = ^ Kelsey^
    words[2] = ^ 65000^
    [Ljava.lang.String;@49c2faae
    SalariedEmployee@31cefde0
    words[0] = ^1^
    words[1] = ^ Kelsey^
    words[2] = ^ 65000^
    [Ljava.lang.String;@49c2faae
    SalariedEmployee@439f5b3d
    words.length = 3
    words[0] = ^2^
    words[1] = ^ Jake^
    words[2] = ^ 89000^
    [Ljava.lang.String;@1d56ce6a
    SalariedEmployee@5197848c
    words[0] = ^2^
    words[1] = ^ Jake^
    words[2] = ^ 89000^
    [Ljava.lang.String;@1d56ce6a
    SalariedEmployee@17f052a3
    words[0] = ^2^
    words[1] = ^ Jake^
    words[2] = ^ 89000^
    [Ljava.lang.String;@1d56ce6a
    SalariedEmployee@2e0fa5d3
    words.length = 3
    words[0] = ^3^
    words[1] = ^ Carlos^
    words[2] = ^ 105000^
    [Ljava.lang.String;@5010be6
    SalariedEmployee@685f4c2e
    words[0] = ^3^
    words[1] = ^ Carlos^
    words[2] = ^ 105000^
    [Ljava.lang.String;@5010be6
    SalariedEmployee@7daf6ecc
    words[0] = ^3^
    words[1] = ^ Carlos^
    words[2] = ^ 105000^
    [Ljava.lang.String;@5010be6
    SalariedEmployee@2e5d6d97
    words.length = 3
    words[0] = ^4^
    words[1] = ^ Clarence^
    words[2] = ^ 58000^
    [Ljava.lang.String;@238e0d81
    SalariedEmployee@31221be2
    words[0] = ^4^
    words[1] = ^ Clarence^
    words[2] = ^ 58000^
    [Ljava.lang.String;@238e0d81
    SalariedEmployee@377dca04
    words[0] = ^4^
    words[1] = ^ Clarence^
    words[2] = ^ 58000^
    [Ljava.lang.String;@238e0d81
    SalariedEmployee@728938a9
    words.length = 3
    words[0] = ^5^
    words[1] = ^ Pacheco^
    words[2] = ^ 68000^
    [Ljava.lang.String;@21b8d17c
    SalariedEmployee@6433a2
    words[0] = ^5^
    words[1] = ^ Pacheco^
    words[2] = ^ 68000^
    [Ljava.lang.String;@21b8d17c
    SalariedEmployee@5910e440
    words[0] = ^5^
    words[1] = ^ Pacheco^
    words[2] = ^ 68000^
    [Ljava.lang.String;@21b8d17c
    SalariedEmployee@6267c3bb
    words.length = 3
    words[0] = ^6^
    words[1] = ^ Piotr^
    words[2] = ^ 120000^
    [Ljava.lang.String;@533ddba
    SalariedEmployee@246b179d
    words[0] = ^6^
    words[1] = ^ Piotr^
    words[2] = ^ 120000^
    [Ljava.lang.String;@533ddba
    SalariedEmployee@7a07c5b4
    words[0] = ^6^
    words[1] = ^ Piotr^
    words[2] = ^ 120000^
    [Ljava.lang.String;@533ddba
    SalariedEmployee@26a1ab54
    words.length = 3
    words[0] = ^7^
    words[1] = ^ Adam^
    words[2] = ^ 47000^
    [Ljava.lang.String;@3d646c37
    SalariedEmployee@41cf53f9
    words[0] = ^7^
    words[1] = ^ Adam^
    words[2] = ^ 47000^
    [Ljava.lang.String;@3d646c37
    SalariedEmployee@5a10411
    words[0] = ^7^
    words[1] = ^ Adam^
    words[2] = ^ 47000^
    [Ljava.lang.String;@3d646c37
    SalariedEmployee@2ef1e4fa
    words.length = 3
    words[0] = ^8^
    words[1] = ^ Yorst^
    words[2] = ^ 77000^
    [Ljava.lang.String;@306a30c7
    SalariedEmployee@b81eda8
    words[0] = ^8^
    words[1] = ^ Yorst^
    words[2] = ^ 77000^
    [Ljava.lang.String;@306a30c7
    SalariedEmployee@68de145
    words[0] = ^8^
    words[1] = ^ Yorst^
    words[2] = ^ 77000^
    [Ljava.lang.String;@306a30c7
    SalariedEmployee@27fa135a
    words.length = 3
    words[0] = ^9^
    words[1] = ^ Silas^
    words[2] = ^ 93000^
    [Ljava.lang.String;@46f7f36a
    SalariedEmployee@421faab1
    words[0] = ^9^
    words[1] = ^ Silas^
    words[2] = ^ 93000^
    [Ljava.lang.String;@46f7f36a
    SalariedEmployee@2b71fc7e
    words[0] = ^9^
    words[1] = ^ Silas^
    words[2] = ^ 93000^
    [Ljava.lang.String;@46f7f36a
    SalariedEmployee@5ce65a89
    words.length = 3
    words[0] = ^10^
    words[1] = ^ Yapsiong^
    words[2] = ^ 85000^
    [Ljava.lang.String;@25f38edc
    SalariedEmployee@1a86f2f1
    words[0] = ^10^
    words[1] = ^ Yapsiong^
    words[2] = ^ 85000^
    [Ljava.lang.String;@25f38edc
    SalariedEmployee@3eb07fd3
    words[0] = ^10^
    words[1] = ^ Yapsiong^
    words[2] = ^ 85000^
    [Ljava.lang.String;@25f38edc
    SalariedEmployee@506c589e
    

    现在您可以从代码中删除“调试”语句。

    请注意,如果您在打印SalariedEmployee 对象时想要一个“人类可读”的字符串,您需要覆盖方法toString(),但这将是一个不同的问题。随意问另一个问题:-)

    【讨论】:

    • 非常感谢@Abra。调试技巧非常有用。阅读您的具体解释真是太好了。
    猜你喜欢
    • 2020-01-20
    • 2017-04-06
    • 2014-12-09
    • 2010-11-23
    • 1970-01-01
    • 2014-05-14
    • 1970-01-01
    • 2012-10-09
    • 2019-03-01
    相关资源
    最近更新 更多