Can't understand how to solve noSuchElementException? - java

I'm trying to write a program to read a file called scores.txt where it prints out the ID of the student with the highest average across their courses along with their student ID.
This is what scores.txt looks like:
34 c081 c082 c083 c084
S2023 99 75 85 62
S2025 -1 92 67 52
S1909 100 83 45 -1
So basically, the 34 a the beginning is a 3 for the number of students and a 4 for the number of courses (yes, I know this is silly, but the file was provided for my task). The c numbers such as c081 are course codes at the school, and the s numbers such as s2023 are student numbers. The figures in the middle represent their scores, the -1 also means they weren't enrolled in the unit.
Anyway, so far I've written a MySchool class and a Student class, which I'll paste below:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class MySchool {
public static void main(String[] args) {
int numberOfStudents;
ArrayList<Student> allStudents = new ArrayList<Student>() ;
// grab first line only, and check if first target is integer, or string
try {
File scoresFile = new File("Scores.txt");
Scanner scoresFileReader = new Scanner(scoresFile);
String headerRow = scoresFileReader.nextLine();
numberOfStudents = headerRow.charAt(0);
while(scoresFileReader.hasNextLine()) {
for (int studentI = 0; studentI < numberOfStudents; studentI++) {
String studentText = scoresFileReader.nextLine();
System.out.println(studentText);
Student student = new Student(studentText);
allStudents.add(student);
}}
scoresFileReader.close();
} catch (FileNotFoundException e) {
System.out.println("An error occurred");
e.printStackTrace();
}
float highestAverage = 0;
String highestScoringStudentNumber = null;
for (Student student : allStudents) {
if (student.getAverageScore() > highestAverage) {
highestAverage = student.getAverageScore();
highestScoringStudentNumber = student.getStudentNumber();
}
}
System.out.println("Highest scoring student: " + highestScoringStudentNumber);
}
}
import java.util.ArrayList;
public class Student {
private String studentNumber;
private ArrayList<Integer> scores = new ArrayList<Integer>();
public Student(String studentText) {
String[] parts = studentText.split(studentText, ' ');
this.studentNumber = parts[0];
for (int i = 1; i < parts.length - 1; i++) {
scores.add(Integer.parseInt(parts[i + 1]));
}
}
public String getStudentNumber() {
return this.studentNumber;
}
public float getAverageScore() {
int sum = 0;
for (int i = 0; i <this.scores.size(); i++) {
sum += this.scores.get(i);
}
return sum / this.scores.size();
}
}
Basically I want to be able to have an object for students where they have their student number and their scores. This is so that I can give them an average.
However, it seems that I've done something wrong in reading the file in (Haven't ever done this before), because the String studentText = scoresFileReader.nextLine(); line throws me an error that states : Exception in thread "main" java.util.NoSuchElementException: No line found
at java.base/java.util.Scanner.nextLine(Scanner.java:1651)
at MySchool.main(MySchool.java:22)
If it's any help, the three student codes and their scores print out the way they should before I get this error.
Can anyone help me to get this up and running? I'm not sure how to resolve it
EDIT:
I've actually noticed the issue to be that somehow numberOfStudents is being set to 51 when there's no 51 in the data. Even if I run the code below, it prints the first value of headerRow confirming that it is 3, which is correct. The when I use the same code to assign it to numberOfStudents suddenly it's become 51 when it prints again?
import java.io.File; // Import the File class
import java.io.FileNotFoundException; // Import this class to handle errors
import java.util.ArrayList;
import java.util.Scanner; // Import the Scanner class to read text files
public class MySchool {
public static void main(String[] args) {
int numberOfStudents;
ArrayList<Student> allStudents = new ArrayList<Student>() ;
// grab first line only, and check if first target is integer, or string
try {
File scoresFile = new File("Scores.txt");
Scanner scoresFileReader = new Scanner(scoresFile);
String headerRow = scoresFileReader.nextLine();
System.out.println(headerRow.charAt(0));
numberOfStudents = headerRow.charAt(0);
System.out.println(numberOfStudents);
for (int studentI = 0; studentI < numberOfStudents; studentI++) {
String studentText = scoresFileReader.nextLine();
System.out.println(studentText);
Student student = new Student(studentText);
allStudents.add(student);
}
scoresFileReader.close();
} catch (FileNotFoundException e) {
System.out.println("An error occurred");
e.printStackTrace();
}
float highestAverage = 0;
String highestScoringStudentNumber = null;
for (Student student : allStudents) {
if (student.getAverageScore() > highestAverage) {
highestAverage = student.getAverageScore();
highestScoringStudentNumber = student.getStudentNumber();
}
}
System.out.println("Highest scoring student: " + highestScoringStudentNumber);
}
}

The problem comes from the fact that you're actually reading an ASCII code of the char, not the value itself - '3' == 51. You need to convert the character to the correct value. The simpliest way is to use Character.getNumericValue(), eg.:
char c = headerRow.charAt(0);
numberOfStudents = Character.getNumericValue(c);

Related

Cannot work around ArithmeticException? / by zero?

I'm having trouble working around an ArithmeticException I'm getting from my getAverageScore() method in my Student class. I'm trying to write a program that reads the following text file scores.txt:
34 c081 c082 c083 c084
S2023 99 75 85 62
S2025 -1 92 67 52
S1909 100 83 45 -1
The c numbers such as c081 are course codes at the school, and the s numbers such as s2023 are student numbers. The figures in the middle represent their scores, the -1 also means they weren't enrolled in the unit.
I want to be able to write a program where I can give output as the student with the highest average across their classes, with that average and their student number. I want to be able to make sure the -1 values aren't included in that class average, so that if a student has one of those, their average is only calculated for the classes they did actually take.
This is the Student class:
import java.util.ArrayList;
public class Student {
private String studentNumber;
private ArrayList<Integer> scores = new ArrayList<Integer>();
public Student(String studentText) {
String[] parts = studentText.split(studentText, ' ');
this.studentNumber = parts[0];
for (int i = 1; i < parts.length - 1; i++) {
scores.add(Integer.parseInt(parts[i + 1]));
}
}
public String getStudentNumber() {
return this.studentNumber;
}
public float getAverageScore() {
int sum = 0;
int numberOfCoursesNotTaken = 0;
for (int i = 0; i <this.scores.size(); i++) {
if (i != -1) {
sum += this.scores.get(i);
System.out.println(sum);
} else {
numberOfCoursesNotTaken++ ;
System.out.println(numberOfCoursesNotTaken);
}
}
return sum / (this.scores.size() - numberOfCoursesNotTaken);
}
}
I'm calling this method from the following class:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class MySchool {
public static void main(String[] args) {
int numberOfStudents;
ArrayList<Student> allStudents = new ArrayList<Student>() ;
try {
File scoresFile = new File("Scores.txt");
Scanner scoresFileReader = new Scanner(scoresFile);
String headerRow = scoresFileReader.nextLine();
char c = headerRow.charAt(0);
numberOfStudents = Character.getNumericValue(c);
for (int studentI = 0; studentI < numberOfStudents; studentI++) {
String studentText = scoresFileReader.nextLine();
System.out.println(studentText);
Student student = new Student(studentText);
allStudents.add(student);
}
scoresFileReader.close();
} catch (FileNotFoundException e) {
System.out.println("An error occurred");
e.printStackTrace();
}
float highestAverage = 0;
String highestScoringStudentNumber = null;
for (Student student : allStudents) {
if (student.getAverageScore() > highestAverage) {
highestAverage = student.getAverageScore();
highestScoringStudentNumber = student.getStudentNumber();
}
}
System.out.println("Highest scoring student: " + highestScoringStudentNumber);
}
}
However, the return line of getAverageScore() in Student gives the following error: Exception in thread "main" java.lang.ArithmeticException: / by zero
at Student.getAverageScore(Student.java:34)
at MySchool.main(MySchool.java:42)
I thought I'd solved this issue using the numberOfCoursesNotTaken variable? Could anyone help me?
I really recommend removing invalid values as soon as they are found. You could replace your Student constructor by the following:
public Student(String studentText) {
String[] parts = studentText.split(" "); // previously (studentText, ' ')
this.studentNumber = parts[0];
for (int i = 1; i < parts.length - 1; i++) {
int score = Integer.parseInt(parts[i]); // NOT i+1
if (score >=0) this.scores.add(score);
}
}
While you are at it, you can greatly simplify your average-score calculation (now that there are no -1s):
public float averageScore() {
if (scores.isEmpty()) {
return 0; // avoids divide-by-zero
} else {
int total = 0;
for (int score : scores) total += score;
return total / (float) scores.size();
}
}
Student class -> getAverageScore : in the for loop, you're checking if i != -1, instead of if scores.get(i) != -1.

NullPointerException when getting elements from Array [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 3 years ago.
I'm trying to print out the names of the employees and their department and location from a list of the names and id numbers and I keep getting the NullPointerException even though it prints all of the names and locations. It then stops the build and doesn't xecute the print department and print location methods.
I've tried re-doing the for loops and seeing if any one data point was the problem but it seems to happen if I do the loop for all of the Employee objects or if I just do one.
package homework5_parth_desai;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
/**
*
* #author Party Parth
*/
public class Homework5_Parth_Desai {
public static int emplIndex = -1;
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws FileNotFoundException {
File file = new File("acmeEgr.txt");
Scanner scan = new Scanner(file);
Employee[] emp = new Employee[50];
String s = "";
String t = "";
int r = 0;
while (scan.hasNextLine()) { //scans in file
emplIndex++;
emp[emplIndex] = new Employee();
if (scan.hasNextLine() == true) { //takes first line as first name, second as last naem and third as id number and tehn ccreates an object out of that
s = scan.nextLine();
}
if (scan.hasNextLine() == true) {
t = scan.nextLine();
}
if (scan.hasNextLine() == true) {
r = Integer.parseInt(scan.nextLine());
}
emp[emplIndex].Employee(s, t, r);
// TODO code application logic here
}
printAll(emp);
printDepartment("IT", emp);
printLocation("Auburn Hills", emp);
}
static void printAll(Employee[] ppl) {
for (int i = 0; i < ppl.length; i++) {
System.out.println(ppl[i].toString());
}
}
static void printDepartment(String title, Employee[] ppl) {
for (int i = 0; i < ppl.length; i++) {
if (title.equals(ppl[i].getDept())) {
System.out.println(ppl[i].getName() + " is in " + ppl[i].getLocation());
}
}
}
static void printLocation(String loc, Employee[] ppl) {
for (int i = 0; i < ppl.length; i++) {
if (loc.equals(ppl[i].getLocation())) {
System.out.println(ppl[i].getName() + " is in " + ppl[i].getDept());
}
}
}
}
Small exert of the .txt file:
Alexander
Seiber
10010
Zehua
Showalter
20010
Cassidy
Woodle
20030
Randall
Shaukat
10030
Pam
Korda
10020
Justin
Polito
20030
public static int emplIndex = -1;
Why is the index maintained as a static field? Don't do that.
Employee[] emp = new Employee[50];
The employee array has a fixed size of 50 elements, however
while (scan.hasNextLine()) {
this loop is based on the lines of the acmeEgr.txt file, which might be more than 50.
In that case, you'll get an ArrayOutOfBoundException first
emp[emplIndex] = new Employee();
or a NullPointerException after
emp[emplIndex].Employee(s, t, r);
Instead, if the lines are less then 50, this
for (int i = 0; i < ppl.length; i++) {
System.out.println(ppl[i].toString());
}
will still loop all the 50 elements, because
ppl.length = 50
Thus, this line
ppl[i].toString()
will throw a NullPointerException.
This is what happens if the elements are, for example, 40
System.out.println(ppl[0].toString());
System.out.println(ppl[1].toString());
System.out.println(ppl[2].toString());
System.out.println(ppl[3].toString());
...
System.out.println(ppl[40].toString()); // ppl[40] is null, NullPointerException!
ArrayList is a much easier array type to deal with. Try using it instead of a normal array, because then you don't have to deal with indexes.

Java read student records and calculate high low and average for each quiz

Update: Thank you so much for all your input! I figured out that my low returns all 0s because java initializes all integers 0 so I changed it to int lowScore [] = new int [] {100, 100, 100, 100, 100}. The problem with findAvg is that in main i created an array of student [40] but the file only contains 15 students, which is why I cannot use a.length to find average. I've added codes to count the number of lines.
I am working on an assignment about reading a txt file of student ID along with their 5 quiz scores. The assignment is asking to read those scores up to 40 students and calculate the high, low and average for each quiz.
Sample output:
Stud Quiz1 Quiz2 Quiz3 Quiz4 Quiz5
1234 90 100 90 98 80
1243 92 92 90 98 70
High Score: 92 100 90 98 80
Low Score: 90 92 90 98 70
Average Score: 91 96 90 98 75
I've created 4 classes: student class for ID and scores, statistics class to calculate high, low and average, util class for read file function, and driver class for the main.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;
class Student {
private int SID;
private int scores[] = new int[5];
public int getSID() {
return SID;
}
public void setSID(int sID) {
SID = sID;
}
public int getScores(int index) {
return scores[index];
}
public void setScores(int[] scores) {
this.scores = scores;
}
public void printSID() {
System.out.println(SID);
}
public void printScores() {
for (int x : scores) {
System.out.println(x);
}
}
}
class Statistics {
private final int[] lowscores = new int[5];
private final int[] highscores = new int[5];
private final float[] avgscores = new float[5];
public void findlow(Student[] a) {
for (Student stu : a) {
for (int i = 0; i < 5; i++) {
lowscores[i] = Math.min(lowscores[i], stu.getScores(i));
}
}
}
public void findhigh(Student[] a) {
for (Student stu : a) {
for (int i = 0; i < 5; i++) {
highscores[i] = Math.max(highscores[i], stu.getScores(i));
}
}
}
public void findavg(Student[] a) {
int[] sum = new int[5];
for (Student stu : a) {
for (int i = 0; i < 5; i++) {
sum[i] += stu.getScores(i);
avgscores[i] = sum[i] / a.length;
}
}
}
public void printLow() {
for (int x : lowscores) {
System.out.println("Low Score " + x);
}
}
public void printHigh() {
for (int x : highscores) {
System.out.println("High Score " + x);
}
}
public void printAvg() {
for (float x : avgscores) {
System.out.println("Average " + x);
}
}
}
class Util {
static Student[] readFile(String filename, Student[] stu) {
try {
FileReader file = new FileReader(filename);
BufferedReader buff = new BufferedReader(file);
int count = 0;
boolean eof = false;
while (!eof) {
String line = buff.readLine();
if (line == null)
break;
else {
System.out.println(line);
if (count > 0) {
StringTokenizer st = new StringTokenizer(line);
for (int i = 0; i < stu.length; i++) {
stu[i] = new Student();
}
stu[count - 1].setSID(Integer.parseInt(st.nextToken()));
int scores[] = new int[5];
int scoreCount = 0;
while (st.hasMoreTokens()) {
scores[scoreCount] = Integer.parseInt(st.nextToken());
scoreCount++;
stu[count - 1].setScores(scores);
}
}
}
count++;
}
buff.close();
} catch (IOException e) {
System.out.println("Error -- " + e.toString());
}
return stu;
}
}
public class Driver{
public static void main(String[] args) {
Student lab4[] = new Student[40];
lab4 = Util.readFile("C:\\lab4.txt", lab4);
Statistics statlab4 = new Statistics();
statlab4.findlow(lab4);
statlab4.findhigh(lab4);
statlab4.findavg(lab4);
statlab4.printLow();
statlab4.printHigh();
statlab4.printAvg();
}
}
The program reads an input file lab4.txt which includes 1 line of header and 15 lines of student records. The program runs but does not calculate the high low and average correctly. I know my calculation for average might be wrong; but I don't know why high and low don't work.
Please help me. Thank you!
For the find average, you shouldn't divide by a.length every iteration.
public void findavg(Student []a) {
int []sum = new int [5];
for(Student stu: a) {
for(int i=0; i<5; i++) {
sum[i] += stu.getScores(i);
}
}
for(int i=0; i<5; i++) {
avgscores[i] = sum[i] / a.length;
}
}
The min and max seems fine.
Not going to rewrite your code for you, just going to ask some questions because I think some people are still a bit confused about your purpose:
Is the purpose of the findAvg method to find the average of all the students marks for a particular test? Or to find the student's average mark for all of their tests?
Moving the Statistics class inside the methods of the Student class (as done by some of the other answers) would work if the latter is your goal, but I wouldn't mind keeping them separate if you're going for the former.
If you're trying to find the highest mark of a group of students, then I'd get them all into an Array or ArrayList and then try an ascending sort (or do them both at the same time).
public float avgCalculate(Student [] a, int testnumber){
float sum = 0.0f;
for (Student s: a){
sum = sum + s.getScores[testnumber];
}
float average = (sum / a.length);
return average;
}
Code is completely untested, so make sure it works and get back to me. It should calculate the average scores of a bunch of students (a) on a specific test (test number). Hopefully you can extrapolate the rest of the code (you may need to modify your other classes a bit etc.) For the highs and lows consider using the Arrays.sort() library method.
Since you've mentioned the Statistics class is required, I've taken another crack at your issue. And I see that when you calculate the highs and lows, the first loop is the students. Instead, make the first loop for the appropriate array, like so:
public void findLow(Student[] a) {
for (int i = 0; i < 5; i++)
for (Student stu : a)
lowScores[i] = Math.min(stu.getScore(i), lowScores[i]);
}
What this then does is:
for each low score you want to find:
for each student that took the quiz:
if this student's score is lower, set that as the lowest
Apply the same logic to your findHigh method.
For your findAvg method, as previously stated, don't divide in every iteration:
public void findAvg(Student[] a) {
for (int i = 0; i < 5; i++) {
for (Student s : a) {
avgScores[i] += s.getScore(i);
}
avgScores[i] /= a.length;
}
}

java.util.InputMismatchException error when scanning from a .txt file

I am creating a program where 2 classes are used. In one class, i create methods that are then called by the second class. All methods are contained in the first class and the 2nd class simply calls them and executes the code.
Class 1
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Student {
private Scanner scanner;
private String firstName;
private String lastName;
private int homeworkScore;
private int testScore;
private String letterGrade;
private int numberOfStudents;
public Student () {
String firstName = null;
String lastName = null;
int homeworkScore = 0;
int testScore = 0;
String letterGrade = null;
int numberOfStudents = 0;
}
public void openFile(){
try {
scanner = new Scanner(new File("grades.txt"));
} catch (FileNotFoundException e) {
System.out.println("Error opening file. Please make sure that you have a grades.txt file in the same folder as GradeCalculator.class");
System.exit(0);
}
}
public void setNumberOfStudents() {
System.out.println("It kinda works");
numberOfStudents = scanner.nextInt();
}
public void setFastName() {
fastName = scanner.next();
}
public void setLastName() {
lastName = scanner.next();
}
public void setHomeworkScore() {
int subAssignment = 0;
int assignment = 0;
for(int i = 1; i <= 21; i++) {
subAssignment = scanner.nextInt();
assignment += subAssignment;
}
homeworkScore = assignment;
}
Class 2
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class CourseGrade {
public static void main(String[] args) {
Student myStudent = new Student();
myStudent.openFile();
myStudent.setNumberOfStudents();
myStudent.setFirstName();
myStudent.setLastName();
myStudent.setHomeworkScore();
}
}
This is the error I get:
It kinda works
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Unknown Source)
at java.util.Scanner.next(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at Student.setHomeworkScore(Student.java:54)
at CourseGrade.main(CourseGrade.java:20)
...the "It kinda works" statement is just to see if it was calling the method correctly, which it looks like it is.
To my understanding, the error is telling me that it is reading the wrong type from the .txt file, but idk why that would be. Is it even reading the file correctly? Any type of help would be great, as I have been staring and messing with this code for hours!
Based on the error message, and where the error occurs, most likely you are trying to read an integer, but the actual data that you are reading is not a number.
You could verify this by changing your scanner.nextInt() to a scanner.next() and printing out the value that you actually get. Alternatively, you could add “error handling” of the form:
for(int i = 1; i <= 21; i++) {
if (scanner.hasNextInt()
subAssignment = scanner.nextInt();
else
throw new RuntimeException("Unexpected token, wanted a number, but got: " + scanner.next());
assignment += subAssignment;
}
According to the oracle java documentation, that exception is thrown, when the token doesn't fit the requested pattern (int) or is out of range.
If there's no more int in your file, that exception is thrown.
You could avoid that exception by checking if there's another int value to read with Scanners method hasNextInt.
For example:
for(int i = 1; i <= 21 && scanner.hasNextInt(); i++) {
subAssignment = scanner.nextInt();
assignment += subAssignment;
}
(if that doesn't solve your problem, you should also include your input file)

CS106A handout 6 Exception java.lang.NullPointerException

Got an Error with NullPointerException . (cs106A handout 6 - Name Count using hash map)
Debugger told me the problem located # String input variable. I got no idea how to solve it.
thanks for reading.
import acm.io.*;
import acm.program.*;
import acm.util.*;
import java.util.*;
import java.io.*;
import java.io.BufferedReader.*;
import java.lang.*;
public class NameCounts extends ConsoleProgram{
// hashmap
static HashMap<String,Integer> myUniq = new HashMap<String,Integer>();
static String input ;
static public void insertName(){
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while(true){
System.out.println("Enter name:");
// if keyboard input contain new unique name ,
// store it in the hashmap and count the value +1
input = br.readLine();
if(input.equals("")) break;
if( myUniq.containsKey(input) ==false){
Integer temp = myUniq.get(input);
temp = temp + 1;
myUniq.put(input,temp);
}
}
}
catch (IOException e){ };
}
// print and show every single hash map and count value
static public void releaseUnique(){
for(int i= 1 ; i < myUniq.size() ; i++){
System.out.println("Entry"+"[" + input + "]"+"has count"+myUniq.get(input));
}
}
public static void main (String[] args){
insertName();
releaseUnique();
}
}
I think you should change
if( myUniq.containsKey(input) ==false){
Integer temp = myUniq.get(input);
temp = temp + 1;
myUniq.put(input,temp);
}
to
if(myUniq.containsKey(input)) {
Integer temp = myUniq.get(input);
temp = temp + 1;
myUniq.put(input, temp);
} else {
myUniq.put(input, 1);
}

Categories

Resources