Почему ArrayList не инициируется? Java
Так было создано свойство класса Students:
ArrayList<Integer> marks;
Далее оно появляется только в методе того же класса:
private static Students createStudent(){
Scanner in = new Scanner(System.in);
var st = new Students();
out.print("Введите имя учащегося: ");
st.name=in.next();
out.print("Введите фамилию учащегося: ");
st.surname= in.next();
out.print("Введите номер и букву класса учащегося: ");
st.numClass = in.next();
out.print("Введите возраст учащегося: ");
st.age = in.nextInt();
in.nextLine();
out.print("Введите оценки учащегося(через пробел): ");
String marks = in.nextLine();
String[] marksAsStr=marks.split(" ");
st.marks = new ArrayList<Integer>(marksAsStr.length);
for (int i = 0; i < marksAsStr.length; i++){
st.marks.set(i, Integer.parseInt(marksAsStr[i])); // Во время работы программы здесь появляется исключение: Index 0 out of bounds for length 0
}
int sum = 0;
for(int i : st.marks) sum += i; // st.marks is always empty
st.gpa = (double) sum /st.marks.size(); // division by zero
out.print("Введите классного руководителя учащегося: ");
st.classroomTeacher = in.next();
out.println("Студент был добавлен в эл. дневник");
return st;
}
Хотя я задал размер массива(st.marks = new ArrayList(marksAsStr.length)), он все же остается пустым. Так в чем проблема?
Ответы (1 шт):
Сходная проблема была описана почти двумя годами раньше в вопросе Создать ArrayList<Integer> с фиксированной длиной Java, и в принципе её решение описано в комментарии @insolor:
st.marks = new ArrayList<Integer>(marksAsStr.length);создаст пустой список с заданной ёмкостью (НЕ размером!), для которого вызов методаList::set(int index, E element)для замены элемента по указанному индексу не будет иметь смысла, пока в список не добавлены какие-то элементы- для добавления элементов в пустой список нужно использовать методы:
List::add(E element), чтобы добавлять элементы в конец спискаList::add(int index, E element), чтобы добавлять элементы по указанному индексу, например,list.add(0, elem)всегда будет добавлять элементы в начало списка.
Также хотелось бы обратить внимание на другие возможные проблемы в приведённом коде:
- Смешанный ввод с использованием
Scanner::next/Scanner::nextLine, в частности ввод имени / фамилии при помощиScanner::nextпредполагает, что имя и фамилия в общем случае состоят из ровно одного слова. - Использование прямого присваивания полям объекта, вместо использования хотя бы сеттеров:
Foo foo = new Foo();
foo.setBar("bar");
foo.setBaz(123);
Хотя лучше было бы использовать конструктор с указанием всех полей:
private static String readString(Scanner in, String msg) {
out.print(msg);
return in.nextLine();
}
private static Student createStudent(){
Scanner in = new Scanner(System.in);
String name = readString(in, "Введите имя учащегося: ");
String surname = readString(in, "Введите фамилию учащегося: ");
String numClass = readString(in, "Введите номер и букву класса учащегося: ");
int age = Integer.parseInt(readString(in, "Введите возраст учащегося: "));
// сканер строки оценок
Scanner inMarks = new Scanner(readString(in, "Введите оценки учащегося(через пробел): "));
List<Integer> marks = new ArrayList<>();
double total = 0d;
while (inMarks.hasNextInt()) {
int mark = inMarks.nextInt();
marks.add(mark);
total += mark;
}
// для пустого списка вернуть 0
double gpa = marks.isEmpty() ? 0d : total / marks.size();
String teacher = readString(in, "Введите имя классного руководителя учащегося: ");
out.println("Данные введены верно, студент будет добавлен в эл. дневник");
return new Student(name, surname, numClass, age, marks, gpa, teacher);
}
Или же использовать шаблон Строитель (Builder), в котором дополнительно были бы инкапсулированы обработка оценок и вычисление средней оценки:
public static class StudentBuilder {
private String name, surname, numClass, teacher;
private int age;
private List<Integer> marks;
public StudentBuilder name(String name) { this.name = name; return this;}
public StudentBuilder surname(String surname) { this.surname = surname; return this;}
public StudentBuilder numClass(String numClass) { this.numClass = numClass; return this;}
public StudentBuilder teacher(String teacher) { this.teacher = teacher; return this;}
public StudentBuilder age(String age) { this.age = Integer.parseInt(age); return this;}
public StudentBuilder marks(String marks) {
this.marks = Arrays.stream(marks.split(" "))
.map(Integer::valueOf)
.toList();
return this;
}
private double gpa() {
return null == marks ? 0d : marks.stream().mapToInt(Integer::intValue).average().orElse(0d);
}
public Student build() {
return new Student(name, surname, numClass, age, marks, gpa(), teacher);
}
}
private static Student createStudent(){
Scanner in = new Scanner(System.in);
Student student = new StudentBuilder()
.name(readString(in, "Введите имя учащегося: "))
.surname(readString(in, "Введите фамилию учащегося: "))
.numClass(readString(in, "Введите номер и букву класса учащегося: "))
.age(readString(in, "Введите возраст учащегося: "))
.marks(readString(in, "Введите оценки учащегося(через пробел): "))
.teacher(readString(in, "Введите имя классного руководителя учащегося: "))
.build();
out.println("Данные введены верно, студент будет добавлен в эл. дневник");
return student;
}