从Java中读取文件和空指针异常

时间:2012-03-20 17:24:47

标签: java java.util.scanner

我对java很新,我遇到了一个我自己无法解决的问题。我用Google搜索了异常,但问题太具体了,据我所知,所以我发现自己在这里。这是我的问题。

我有一个名为Student的类,其中包含数据成员及其get / set方法:

private String studentNumber;
private String firstName;
private String lastName;
private int age;
private String gender;
private String country;

我创建了一个实例数组:

Student studentList[] = new Student(10);

我有一个数据库(文本文件)作为fallowing

081935 Cengiz rrrrr Male 21 Turkey
082935 Ayşe aaaaa Female 22 England
083935 Onur bbbbb Male 23 Germany
084935 Fatma ccccc Female 24 Cyprus
085935 Ali dddd Male 21 China
086935 Zehra eeee Female 22 Denmark
087935 Murat ffff Male 25 France
088935 Selin ggggg Female 26 Japan
086935 Cengiz hhhh Male 20 Korea
080935 Damla qqqqqq Female 19 Iran

我要做的是将所有这些信息传递给我的类实例,并尝试实现这一目标:

import java.io.*;
import java.util.Scanner;

public class StudentTracker  {

    private static int counter = 0;
    private static Student studentList[];

    public static void readFromFile() throws FileNotFoundException {
        File file = new File("Database.txt");
        Scanner scanner = new Scanner(new FileReader(file));
        try {
              while (scanner.hasNextLine()){
                processLine(scanner.nextLine());
              }
        } finally {
            scanner.close();
        }
    }


    public static void processLine(String line) {
        Scanner scanner = new Scanner(line);
        scanner.useDelimiter(" ");
        if (scanner.hasNext()) {
          studentList[counter].setStudentNumber(scanner.next());
          studentList[counter].setFirstName(scanner.next());
          studentList[counter].setLastName(scanner.next());
          studentList[counter].setGender(scanner.next());
          studentList[counter].setAge(Integer.parseInt(scanner.next()));
          studentList[counter].setCountry(scanner.next());      
          counter++;
        }
        else {
            System.out.println("Empty or invalid line. Unable to process.");
        }
      }

    public static void main(String[] args) throws FileNotFoundException {

        studentList = new Student[10];
        readFromFile();
        for(int i = 0; i < 10; i++) {
            System.out.printf(studentList[i].getStudentNumber(), " ",
                              studentList[i].getFirstName());

        }

    }

}

但它会导致以下错误:

Exception in thread "main" java.lang.NullPointerException
    at StudentTracker.processLine(StudentTracker.java:28)
    at StudentTracker.readFromFile(StudentTracker.java:16)
    at StudentTracker.main(StudentTracker.java:68)
顺便说一下,找不到像C-scanf这样的函数,它在第一个空格之前得到输入,所以我找到另一种方法从行中解析字符串

readFromFile()和processLine函数,但我不确定它们是否按预期工作。

提前谢谢

6 个答案:

答案 0 :(得分:6)

这一行:

studentList = new Student[10];

创建一个包含10个元素的数组。每个元素的值不是Student 对象;它是引用 - 并且该引用将为null,或者对Student对象(或兼容类型)的引用。每个元素都有一个空值来开始。

该行不会创建任何Student个对象

在设置属性之前,您需要创建Student的实例,例如

if (scanner.hasNext()) {
  studentList[counter] = new Student();
  studentList[counter].setStudentNumber(scanner.next());
  ...

或者:

if (scanner.hasNext()) {
  Student student = new Student();
  student.setStudentNumber(scanner.next());
  ... fill in the other properties ...
  studentList[counter] = student;
  ...

作为旁注,这一行:

private static Student studentList[];

......不是惯用声明。这是有效的,但大多数Java程序员更愿意看到:

private static Student[] studentList;

这样,所有类型信息都保存在一个地方。 (我还建议使用List<Student>代替,并将其传递给方法而不是使用静态变量,但让我们不要超越自己......)

答案 1 :(得分:2)

除了不初始化studentList中的元素外,还有

    if (scanner.hasNext()) {
      studentList[counter].setStudentNumber(scanner.next());
      studentList[counter].setFirstName(scanner.next());
      studentList[counter].setLastName(scanner.next());
      studentList[counter].setGender(scanner.next());
      studentList[counter].setAge(Integer.parseInt(scanner.next()));
      studentList[counter].setCountry(scanner.next());      
      counter++;
    }

您只检查scanner.hasNext()一次,然后多次致电scanner.next()。如果任何非空输入行的元素少于预期,则抛出NoSuchElementException

在每个字段分配之前OTOH检查hasNext()非常尴尬。另一种方法是使用String.split。这将生成String[],您可以在尝试初始化新学生对象之前检查其长度以确保所有字段都存在。

答案 2 :(得分:1)

您创建了一个Student数组,但从未将任何Student对象放入其中。

不是将它们设置为数组索引值,而是创建一个新对象,设置其属性,然后将其分配给数组索引。

for( ... ) {
 Student x= new Student();
 x.set...
 studentList[index]= x;
}

答案 3 :(得分:0)

在您的processLine中引用studentList [counter],但是您从未将新Student放入studentList [counter]中,因此您尝试在null上调用setStudentName。你应该把一个新学生放在学生列表中,然后使用它,或者使它更具可读性,做类似的事情

Student = new Student();
student.setThis( scanner.next());
student.setThat( scanner.next());
studentList[counter] = student;

答案 4 :(得分:0)

您应该粘贴第28行上获得异常的内容。有几件事需要检查:

  1. studentList[counter]是否为空?

  2. 检查scanner.hasNext()true后,您多次拨打scanner.next()。其中一个电话可以返回null吗?这可能不是根本原因,因为异常在堆栈上至少还有一个方法,但您仍可能需要检查代码。

答案 5 :(得分:0)

使用

Student studentList[] = new Student(10);

你只是创建一个大小为10的Student类型的数组。这个数组包含10个Student的引用,每个引用尚未定义(它将为null)。

在调用Student引用上的任何set方法之前,实例化像这样的对象

studentList[counter] = new Student();

所以你的代码可能会变成

if (scanner.hasNext()) {
        studentList[counter] = new Student();
        studentList[counter].setStudentNumber(scanner.next());