繁体   English   中英

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

[英]Reading From File in Java and Null Pointer Exception

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

我有一个名为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);

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

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函数,但是我不确定它们是否按预期工作。

先感谢您

这行:

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> ,并将其传递到方法中,而不要使用静态变量,但不要让自己超前...)

除了不初始化studentList的元素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[] ,您可以在尝试初始化新的Student对象之前检查其长度以确保所有字段都存在。

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

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

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

在您的processLine中,您引用的是StudentList [counter],但从未将新的Student放入studentList [counter]中,因此您尝试将setStudentName调用为null。 您应该将一个新学生放入库珀的studentList中,然后使用它,或者使其更具可读性,请执行以下操作

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

您应该粘贴第28行的内容,以获取异常。 需要检查的几件事:

  1. studentList[counter]是否为空?

  2. 在检查scanner.hasNext()true您要多次调用scanner.next() 这些调用之一可以返回null吗? 这在这里不能成为根本原因,因为异常会在堆栈上至少包含一个以上的方法,但是您仍然可能需要在代码中进行检查。

Student studentList[] = new Student(10);

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

在调用学生参考上的任何set方法之前,请实例化该对象

studentList[counter] = new Student();

所以你的代码可能会变得像

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM