繁体   English   中英

在循环内设置属性值时出现 java.lang.NullPointerException

[英]java.lang.NullPointerException when setting value of attributes within a loop

如果用户键入“end”,则在第二个输入“输入学生的名字”中尝试这样做,循环自动为数组中的每个 object 分配 id 和 name 的“null”属性和 0年龄和身份证,以及打破外环。 但是,我收到错误 java.lang.NullPointerException。 任何帮助,将不胜感激。

import java.util.*;


class Main {
    public static void main(String[] args) {
        Scanner myObj = new Scanner(System.in);
        System.out.println("Enter number of students");
        int numberof = myObj.nextInt();
        System.out.println("Number of students is " + numberof);
        Student Studentz[] = new Student[numberof];
        outerloop:
            for (int i = 0; i < numberof; ++i) {
                Studentz[i] = new Student();

                System.out.println("Enter first name of student " + (i + 1));
                Scanner myObj1 = new Scanner(System.in);

                String firstname = myObj1.nextLine();
                System.out.println("Firstname is: " + firstname);
                if (firstname.equals("end")) {
                    for (int g = i; g < numberof; ++g) {
                        Studentz[g].Setfirst("null");
                        Studentz[g].Setlast("null");
                        Studentz[g].Setage(0);
                        Studentz[g].Setid(0);
                    }
                    break outerloop;
                } else {
                    Studentz[i].Setfirst(firstname);

                    System.out.println("Enter last name of student " + (i + 1));
                    Scanner myObj2 = new Scanner(System.in);

                    String lastname = myObj2.nextLine();

                    System.out.println("Last name is: " + lastname);
                    Studentz[i].Setlast(lastname);;

                    System.out.println("Enter age of student " + (i + 1));
                    Scanner myObj3 = new Scanner(System.in);

                    int nazca = myObj3.nextInt();
                    System.out.println("Age is: " + nazca);
                    Studentz[i].Setage(nazca);


                    System.out.println("Enter ID of student " + (i + 1));
                    Scanner myObj4 = new Scanner(System.in);

                    int nazca1 = myObj4.nextInt();
                    System.out.println("ID is: " + nazca1);
                    Studentz[i].Setid(nazca1);

                }

                for (int c = 0; c < numberof; ++c) {
                    System.out.println(Studentz[c].Snake());
                }
            }
    }
}

public class Student {
    private String first;
    private String last;
    private int age;
    private int id;
    public int getid() {
        return
        this.id;
    }


    public void Studentss(String f, String l, int a, int i) {
        first = f;
        last = l;
        age = a;
        id = i;
    }
    public void Setfirst(String z) {
        this.first = z;
    }
    public void Setlast(String za) {
        this.last = za;
    }
    public void Setage(int zb) {
        this.age = zb;
    }
    public void Setid(int zc) {
        this.id = zc;
    }
    public String Snake() {
        String snek = "Name is " + this.first + " " + this.last + " , Age is " + this.age + " ,ID is " + this.id;
        return snek;
    }
}

您在这里失败了,因为您在初始化Studentz数组的所有元素之前尝试打印学生数据:

for (int c = 0; c < numberof; ++c) {
    System.out.println(Studentz[c].Snake());
}

您的代码也因同样的原因在这里失败:

for (int g = i; g < numberof; ++g) {
    Studentz[g].Setfirst("null");  // NPE - no Student created yet in the array

一些可能有用的提示:

遵循 Java 变量和方法名称的命名规则, Studentz应该是studentz ,即使对于您的 Arrays 也是如此。 我知道...你厌倦了阅读,但随着你的进步,你会看到它真的是多么有益。

如果可以,请不要使用多个Scanner对象,在您的用例中不需要这样做。 声明一台扫描仪 object 并坚持下去。 您这样做可能是因为您在nextInt( ) 方法之后使用了nextLine()方法,并且您发现它跳过了名字提示并提供了 Null 字符串 ("")。 发生这种情况是因为 nextInt() 方法在按下 Enter键时不使用换行符。 要解决此问题,您可以将代码行myObj.nextLine(); 直接下int numberof = myObj.nextInt(); 代码行:

int numberof = myObj.nextInt();
myObj.nextLine();  // Consume ENTER key hit

或者根本不使用nextInt()方法。 而是坚持使用nextLine()方法而不用担心消耗:

Scanner myObj = new Scanner(System.in);
int numberof = 0;
String val = "";
while (val.equals("")) {
    System.out.println("Enter number of students");
    val = myObj.nextLine();
    if (!val.matches("\\d+")) {
        System.err.println("Invalid number supplied!");
        val = ""; 
        continue;
    }
    numberof = Integer.parseInt(val);
}
System.out.println("Number of students is " + numberof);
Student[] studentz = new Student[numberof];

验证来自用户的任何输入(如上所示)总是一个好主意,即使它们处于for循环中。 给用户一个正确输入的机会,毕竟,错字确实会发生。

去掉外环: label。 事实上,如果可以的话,尽量避免使用它们……而且可以。 它只会在您可能需要一个相对罕见的场合。

至少在某种程度上,给你的变量起有意义的名字。 当您以后想在将来阅读旧代码时,这可以使您受益。

在您的Student class 中,您为自己创建了一个名为Studentss()的非常好的方法。 好吧,我认为它应该是一个构造函数,并为调用 Setter 方法节省大量代码条目。 毕竟,这主要是构造函数的用途。 您的 Student class 构造函数可能如下所示:

public Student(String firstName, String lastName, int age, int id) {
    this.first = firstName;
    this.last = lastName;
    this.age = age;
    this.id = id;
}

并被这样使用。 您会注意到,在外部for循环的每次迭代中,所有提示答案都放在变量中,然后在所有这些提示的末尾使用构造函数实例化一个学生 object,例如:

studentz[i] = new Student(firstname, lastname, age, id); 

这样做意味着不需要调用 Setter 方法。 进行 setter 调用没有任何问题,只是使用构造函数更容易。 如下所示:

Scanner myObj = new Scanner(System.in);

int numberof = 0;
String val = "";
while (val.equals("")) {
    System.out.println("Enter number of students");
    val = myObj.nextLine();
    if (!val.matches("\\d+")) {
        System.err.println("Invalid number supplied!");
        val = "";
        continue;
    }
    numberof = Integer.parseInt(val);
}
System.out.println("Number of students is " + numberof);

Student[] studentz = new Student[numberof];

for (int i = 0; i < numberof; ++i) {
    String firstname = "null";
    String lastname = "null";
    int age = 0;
    int id = 0;
    boolean exitOuterForLoop = false;

    // Student First Name Prompt:
    // (with option to End and default remaining to null's and 0's)
    while (firstname.equals("null")) {
        System.out.println("Enter first name of student " + (i + 1) + " (End to stop):");
        firstname = myObj.nextLine();
        if (firstname.equalsIgnoreCase("end")) {
            firstname = "null";
            //Make all remaining Student instances null and 0
            for (int g = i; g < numberof; ++g) {
                studentz[g] = new Student(firstname, lastname, age, id); // Use Student class constructor
            }
            exitOuterForLoop = true;
            break; // Exit this 'while' loop
        }
        // Validate first name (no numbers or crazy characters)
        if (!firstname.matches("(?i)[a-z']+")) {
            System.err.println("Invalid First Name! (" + firstname + ") Try Again...");
            firstname = "null";
        }
    }
    if (exitOuterForLoop) {
        break; // Exit this outer 'for' loop.
    }
    System.out.println("Firstname is: " + firstname);

    // Student Last Name Prompt
    while (lastname.equals("null")) {
        System.out.println("Enter last name of student " + (i + 1));
        lastname = myObj.nextLine();
        // Validate last name (no numbers or crazy characters)
        if (!lastname.matches("(?i)[a-z']+")) {
            System.err.println("Invalid Last Name! (" + lastname + ") Try Again...");
            lastname = "null";
        }
    }
    System.out.println("Last name is: " + lastname);

    // Student Age Prompt
    val = "";
    while (val.equals("")) {
        System.out.println("Enter age of student " + (i + 1));
        val = myObj.nextLine();
        // Validate age (digits 0 to 9 only)
        if (!val.matches("\\d+")) {
            System.err.println("Invalid Age Supplied! (" + val + ") Try Again...");
            val = "";
        }
    }
    age = Integer.parseInt(val);
    System.out.println("Student age is: " + age);

    // Student ID Prompt
    val = "";
    while (val.equals("")) {
        System.out.println("Enter ID of student " + (i + 1));
        val = myObj.nextLine();
        // Validate age (digits 0 to 9 only)
        if (!val.matches("\\d+")) {
            System.err.println("Invalid ID Supplied! (" + val + ") Try Again...");
            val = "";
        }
    }
    id = Integer.parseInt(val);
    System.out.println("Student ID is: " + id);

    studentz[i] = new Student(firstname, lastname, age, id); // Use Student class constructor
}

// Display the instances of Student contained within the 'studentz[]' array.
for (int c = 0; c < numberof; ++c) {
    System.out.println(studentz[c].toString());
}

snake()方法实际上只是另一个toString()方法,这并没有什么问题,但是您可能需要考虑使用StringBuilder class 来创建返回的字符串,而不是进行连接,例如:

public String snake() {
    return new StringBuilder("Name is ").append(this.first).append(" ").append(this.last)
                            .append(" , Age is ").append(this.age).append(" , ID is ")
                            .append(this.id).toString();
}

这里不是很重要,但如果您对许多大字符串进行大量连接,它可以为您节省 memory。

暂无
暂无

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

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