public static ArrayList<Student> readStudentRecords(String fileName) throws FileNotFoundException {
Scanner input = new Scanner(new FileInputStream(fileName));
ArrayList<Student> students = new ArrayList<Student>();
input.useDelimiter(",");
String firstName, lastName, id, email, hashPW;
int maxCredits = 0;
while (input.hasNextLine()) {
try {
input.nextLine();
firstName = input.next();
lastName = input.next();
id = input.next();
email = input.next();
hashPW = input.next();
maxCredits = input.nextInt();
Student student = new Student(firstName, lastName, id, email, hashPW, maxCredits);
students.add(student);
} catch (IllegalArgumentException e) {
System.out.println("Illegal Argument Exception");
input.next();
} catch (NoSuchElementException e) {
System.out.println("No Such Element Exception");
input.next();
}
}
input.close();
return students;
}
I am creating a program that reads a text file that lists a students first name, last name, id, email, hashed password, and max credits. Each line of the text file has a full suite of each element seperated by commas. I want the program to read the file, create a student object from each line (I have created and tested the Student class, including all getters and setters), and arrange the student objects in an array list. The program is getting looped at NoSuchElementException, and is only reading the first line of the text file, and ignoring the next 9. I'm not sure what exact format my try-catch statement should be in to ensure that it will not infinitely loop.
The first line in your try block reads the available line and then throws it away:
while (input.hasNextLine()) {
try {
input.nextLine();
...
The reason you are getting the exception is that you throw away the line you just checked is there and then continue trying to read from input, whether or not there is anything after the line you just trashed.
You should do one of these:
Capture that line and parse it (rather than calling input.next() or input.nextInt() in the following lines); or
Eliminate the call to input.nextLine() and hope that each line properly conforms to the layout you expect; or
Replace your entire while loop with calls to a csv parsing utility (as #Scary Wombat suggests in a comment).
with Scanner you need to check if there is a next line with hasNextLine()
so the loop becomes
while(sc.hasNextLine()){
str=sc.nextline();
//...
}
this code this depends on whether the input is properly formatted
You're calling nextLine() and it's throwing an exception when there's no line, exactly as the javadoc describes. It will never return null
The other answers look right to me. Just to add some more that hasn't already been said:
When catching an exception, make sure not to swallow it (that is ignore it) by just printing out that information. If anything, you're losing information that the e.printStackTrace() would have exposed, that is tell you exactly on which line it's failing on.
The actual error that you have is because the scanner is using , as the delimiter, and so that means the last value will be something like 10\n (if 10 is the max credits for a row). You could get around this by doing something like: String[] words = scanner.nextLine().split(","); instead of processing it word by word with the scanner.
Related
This is the program
public class bInputMismathcExceptionDemo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
boolean continueInput = true;
do {
try {
System.out.println("Enter an integer:");
int num = input.nextInt();
System.out.println("the number is " + num);
continueInput = false;
}
catch (InputMismatchException ex) {
System.out.println("Try again. (Incorrect input: an integer is required)");
}
input.nextLine();
}
while (continueInput);
}
}
I know nextInt() only read the integer not the "\n", but why should we need the input.nextLine() to read the "\n"? is it necessary?? because I think even without input.nextLine(), after it goes back to try {}, the input.nextInt() can still read the next integer I type, but in fact it is a infinite loop.
I still don't know the logic behind it, hope someone can help me.
The reason it is necessary here is because of what happens when the input fails.
For example, try removing the input.nextLine() part, run the program again, and when it asks for input, enter abc and press Return
The result will be an infinite loop. Why?
Because nextInt() will try to read the incoming input. It will see that this input is not an integer, and will throw the exception. However, the input is not cleared. It will still be abc in the buffer. So going back to the loop will cause it to try parsing the same abc over and over.
Using nextLine() will clear the buffer, so that the next input you read after an error is going to be the fresh input that's after the bad line you have entered.
but why should we need the input.nextLine() to read the "\n"? is it necessary??
Yes (actually it's very common to do that), otherwise how will you consume the remaining \n? If you don't want to use nextLine to consume the left \n, use a different scanner object (I don't recommend this):
Scanner input1 = new Scanner(System.in);
Scanner input2 = new Scanner(System.in);
input1.nextInt();
input2.nextLine();
or use nextLine to read the integer value and convert it to int later so you won't have to consume the new line character later.
Also you can use:
input.nextInt();
input.skip("\\W*").nextLine();
or
input.skip("\n").nextLine();
if you need whitespaces before line
I have file with the below data
A,8,43
B,7,42,
C,9,34
I am using the below code to read the data
Scanner input = new Scanner(new File("D:\\test.txt"));
input.useDelimiter(",|\n");
while(input.hasNext()) {
String name = input.next();
int age = input.nextInt();
int height = input.nextInt();
When I am executing the program I am getting InputMisMatch exception,
Please suggest what is mistake.
At end of second line you have , and line separator (I am assuming \n) This means you have empty element between these two delimiters.
So in third iteration
String name = input.next();
int age = input.nextInt();
int height = input.nextInt();
input.next(); is consuming "", which means input.nextInt() will try to consume C.
To solve this problem you can set delimiter to be combination of one or more commas and line separators like
input.useDelimiter("(,|\n)+");
To improve your code even farther instead of \n you can use \\R added in Java 8 (or \r|\n in earlier versions) to handle all line separators, because currently you don't consider \r as delimiter so it can be treated as valid token.
So better solution would be using
input.useDelimiter("(,|\\R)+"); //for readability
or even
input.useDelimiter("[,\r\n]+");
The problem lies at the use of the useDelimiter method. This method accepts a regular expression as a parameter. You can't just say ,|\n to mean "comma or new line". There are rules.
What you should pass in is "[,\\n]+". This means "one or more characters in the following set: [comma, new line character]".
With the regex that you are passing currently, ,|\n, it means that the delimiter should be either , or \n, but not both. So when it encounters the second line:
B,7,42,
this is what happens:
next reads "B"
nextInt reads "7"
nextInt reads "42"
next reads an empty string that is between the "," and the new line.
nextInt now tries to read the next token "C", which it can't.
EXCEPTION!
I would do things differently -- use one Scanner to parse each line of the File and use a 2nd Scanner nested within the while loop to extract tokens or data from the lines obtained from the first Scanner. For example:
String filePath = "D:\\test.txt";
File file = new File(filePath);
// use try-with-resources
try (Scanner input = new Scanner(file)) {
while (input.hasNextLine()) {
String line = input.nextLine();
Scanner lineScanner = new Scanner(line);
lineScanner.useDelimiter("\\s*,\\s*"); // get comma and any surrounding whitespace if present
String name = "";
int age = 0;
int height = 0;
if (lineScanner.hasNext()) {
name = lineScanner.next();
} // else ... throw exception?
if (lineScanner.hasNextInt()) {
age = lineScanner.nextInt();
} // else ... throw exception?
if (lineScanner.hasNextInt()) {
height = lineScanner.nextInt();
} // else ... throw exception?
// use name, age, height here
System.out.printf("%s %s %s%n", name, age, height);
lineScanner.close(); // don't waste resources -- return them
}
} catch (IOException e) {
e.printStackTrace();
}
I'm new to Java and I'm trying to read data from a .txt file. I've implemented a Scanner object 'in' Scanner in=new Scanner("file.txt"); and then down the code a while loop to traverse through the content of the file.There are multiple rows of data in the file and in each row there are three strings (security number ,First name ,Last name : 01 Thomas Anderson)
while(in.hasNext()){
String ss = in.next();
String FName=in.next();
String LName=in.next();
System.out.printf("SSN: %s, FirstName: %s, LastName: %s \n",ss,FName,LName);
}
So, what does the hasNext() method do? Does it look for end of the row or for the last row in the file or.... ?
Please elaborate on the working of the above snippet (mentioning the next() method too).
I do recommend looking at the Javadoc, but I'll explain it for you as simple as I can.
Basically, the hasNext() method returns true if the given document contains another string. Hence why the snippet will loop if said document has another string. Once there are no more Strings in the entire document, hasNext() returnsfalse.
Here's an example of the next() method:
String myString = myScanner.next();
This makes myString equal to the next string in the given document.
Javadoc says:
hasNext
public boolean hasNext()
Returns true if this scanner has another token in its input. This
method may block while waiting for input to scan. The scanner does not
advance past any input.
next
public String next()
Finds and returns the next complete token from this scanner. A
complete token is preceded and followed by input that matches the
delimiter pattern. This method may block while waiting for input to
scan, even if a previous invocation of hasNext() returned true.
To read all your file rows you'll have to check if there are tokens every line. Then you call 3 times the next method since you know there will be 3 tokens per line:
import java.io.File;
import java.util.Scanner;
public class FLoader {
public void load(String path) {
Scanner in = null;
try {
in = new Scanner(new File(path));
while (in.hasNext()) {
String ss = in.next();
String FName = in.next();
String LName = in.next();
System.out.printf("SSN: %s, FirstName: %s, LastName: %s \n", ss, FName, LName);
}
} catch (Exception e) {
System.err.println("Loading file failed");
e.printStackTrace();
System.exit(-1);
}
}
}
I will admit, this is a school assignment... But I simply cannot figure out what I am doing wrong.
I have a hash table with an insert function. The following code is supposed to take a line of data from System.in in the format "Long String" (i.e. "32452 John"). The first token must be a Long for the ID number, and it must be followed by a String token for the name. When I run the program and I get to the portion where this must be executed (It is in a switch statement), I entered 'a' and hit enter. The command line immediately reads "Invalid value." (note: not VALUES, as that would mean it hit the nested if statement. It won't let me type in any data. Thank you in advance!
System.out.println("Enter ID and Name.");
//temp to take in the next line entered by the user
//inScan is the Scanner for System.in
temp = inScan.nextLine();
//Create Scanner for the line
Scanner tempScan = new Scanner(temp);
if(tempScan.hasNextLong()){
thisID = tempScan.nextLong();
if((tempScan.hasNext()) && (thisID>0)){
thisName = tempScan.next();
//The data will only be inserted if both segments of data are entered
myTable.insert(new Student(thisID, thisName));
}else{
System.out.println("Invalid values.");
}
}else{
System.out.println("Invalid value.");
}
Why do you need the second Scanner?
Example
String input = scanner.nextLine();
String[] tokens = input.split(" ");
Long id = Long.parseLong(tokens[0]);
String name = tokens[1];
And if you wanted to add your validation:
String input = scanner.nextLine();
if(input.contains(" ")) {
// You know there's a space in it.
String[] tokens = input.split(" ");
if(tokens.length == 2) {
// You know it's a value, followed by a space, followed by a value.
if(tokens[0].matches("[0-9]+")) {
// You know it only contains numbers.
Long id = Long.parseLong(tokens[0]);
}
}
}
I've not run it, but i guess your problem is that when you enter the text 'a' and hit enter, this line is false:
if(tempScan.hasNextLong()){
as you haven't entered a number. hence why it drops to the next block. If you enter something numerical first, i suspect your code with work. you probably need to add a 'while' loop around it, to run until it gets a number.
You already have a Scanner which reads from System.in, there's no need for another one. The second one you've made is a scanner for a String, which will never have a nextLong as it has nothing to scan after your String.
I won't write any code for you as this is homework, but stick to your original scanner when checking for user input instead.
I'm getting the error
the local variables name and password may not have been initialized,
for the if-statement. These errors go away if I change the second string in parentheses to something in quotes, or if I set the variables to 0, but then I would also need to change them to int and I need them to be String.
I'm trying to compare the username and password from a text file to a newly input username and password. The program should also quit after 3 bad attempts so I probably put the System.out.println("Goodbye!"); in the wrong place too.
public static void main(String[] args) {
int numberOfAttempts = 1;
String fileName = "logins.txt";
Scanner inputStream = null;
String name, password, line, secondname;
String secondpassword;
do
{
System.out.println("Please enter your username: ");
Scanner keyboard = new Scanner(System.in);
secondname = keyboard.nextLine();
System.out.println("Please enter your password: ");
secondpassword = keyboard.nextLine();
try
{
inputStream = new Scanner(new File(fileName));
}
catch(FileNotFoundException e)
{
System.out.println("Error opening the file " +
fileName);
System.exit(0);
}
while (inputStream.hasNextLine())
{
line = inputStream.nextLine();
}
if ((name.equalsIgnoreCase(secondname))&&
(password.equalsIgnoreCase(secondpassword)))
{System.out.println("Welcome!");
numberOfAttempts = 4;
}
else
System.out.println("Invalid. Please try again.");
numberOfAttempts++;
}
while ( numberOfAttempts <4);
System.out.println("Goodbye!");
inputStream.close();
}
}
You never initialize name and password, so of course you'll get this error.
You initialize secondname and secondpassword, but your condition checks name and password which are not initialized.
In JAVA methods, any local variable must be initialized first it can be used. In your case you are trying to compare the name & password in your code are never initialized or assigned a value.. It will be a good idea to initialize your strings either as NULL or empty string such as "" or any desired value.
You have a bunch of problems.
The errors are caused by the fact that you never assign any values to the variables "name" and "password", but you then check to see if those variables match the secondname and secondpassword variables you do read. Because name and password never get any values at all, the comparison can't possibly be what you intend, so the compiler flags it as an error.
You can make the error go away by assigning name and password to some values when you declare them, but your program still isn't going to work correctly, because no matter what value you assign, it probably won't be the thing that the user of your program would want to be comparing against.
Presumably your intent is to read the value of name and password from the input file you've opened and read in, but in fact you aren't doing anything with the values in that file except immediately throwing them away. Look at the loop
while(inputStream.hasNextLine()) {
line = inputStream.nextLine();
}
This loop will read in every line from the file, but as soon as you read one line, you throw away whatever you read into the line variable because you have to reuse that variable to read the next line, which you'll also throw away immediately. At the end of the loop, you'll have saved the last line from the file into line, but the rest of the program doesn't use the line variable either.
You need to put some logic inside that loop to read whatever you wanted to read from the file, store it in the name and password variables, and then you'll have some hope that when you do the equalsIgnoreCase stuff that you'll actually be comparing variables that have some meaning to your program.