I'm confused the use of scanner.next()in JAVA - java

My intention is to print all characters in string. And I want to check if one character is "q" or "Q", just break the loop and end the program. Suppose I use "Hello World You" as input, the output can only be
World
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.Scanner.throwFor(Scanner.java:937)
at java.base/java.util.Scanner.next(Scanner.java:1478)
at tictactoe.ScannerDemo.main(ScannerDemo.java:22)
But if I comment that if statement, the output is correct, which is
Hello
World
K
So, I don't know why it happens and how to fix it ?
This is my code:
public class ScannerDemo {
public static void main(String[] args) {
String s = "Hello World K";
Scanner scanner = new Scanner(s);
while (scanner.hasNext()) {
//if I comment the if statement, the result is normal
if(scanner.next().equalsIgnoreCase("q")){
break;
}
System.out.println(scanner.next());
}
// close the scanner
scanner.close();
}
}

Have a look at scanner.hasNext() and how often you call scanner.next() which is 2x per call to hasNext(). Since next() returns the next element, the first call will return "Hello" and the second returns "World" as you've already noticed.
Now on the second iteration of the loop there's still a "next" element with the value "You" and that is returned by the call to next() in the if-statement. However the next call to next() breaks because there is no more input.
To fix that, call next() only once and keep a reference to the string:
while (scanner.hasNext()) {
String token = scanner.next();
if(token .equalsIgnoreCase("q")){
break;
}
System.out.println(token );
}
Btw, I want to check if one character is "q" or "Q" doesn't match your code as you're only checking entire strings. If this is intended behavior then you're ok but otherwise you'd need to use toCharArray() or charAt(index) to check individual characters (this might be weird though, e.g. if input was "may I ask a question: is this printed?" it would stop at "question").

Have a look at your code
while (scanner.hasNext()) {
//if I comment the if statement, the result is normal
if(scanner.next().equalsIgnoreCase("q")){
break;
}
System.out.println(scanner.next());
}
In the condition of the if statement you are calling next(). This is will not throw any exception cause it is already checked by hasNext() call. But later you are printing the token while not checked by the hasNext() call. Moreover the previous token is lost in the if condition during the next() call.
Try using ..
while (scanner.hasNext()) {
String nextToken = scanner.next();
if (nextToken.equalsIgnoreCase("q")) {
break;
}
System.out.println(nextToken);
}

you're calling next() twice without checking if there's a token left...
try
while (scanner.hasNext()) {
String nextValue = scanner.next();
if(nextValue.equalsIgnoreCase("q")){
break;
}
System.out.println(nextValue);
}

Related

How to ask user for ONLY one word string input and produce error prompt in a try-catch block

EDIT: I figured it out! I got rid of the try-catch block because it just didn't work the way I wanted it to. The code below is my final one. Thank you to everyone who responded to this question.
I am trying to code a to-do list program. One function of this program is to search for the entries inside the string array. The user should only input a ONE WORD keyword so if the user inputs more than one word or none, a prompt should show telling the user to try again. The code I've written so far is inside a try-catch statement. Using next() scanner only takes the first word and disregards the rest when inputting a multiple-word keyword, instead of producing an Exception. Here is my code for it:
case 2:
String searchKeyword;
int success = 0;
while(success==0) {
System.out.print(">> Enter 1 keyword: ");
searchKeyword = sc.nextLine();
String splitSearchKeyword[] = searchKeyword.split(" ");
if (splitSearchKeyword.length == 1) {
if(Quinones_Exer2.searchToDoList(searchKeyword, todoList)==-1) {
System.out.println(">> No item found with that keyword!");
System.out.println();
}
else {
System.out.println(">> Found one item!");
System.out.println("("+(Quinones_Exer2.searchToDoList(searchKeyword, todoList)+1)+")"+" "+todoList[Quinones_Exer2.searchToDoList(searchKeyword, todoList)]);
System.out.println();
}
success++;
}
else {
System.out.println(">> Please input a single word keyword!");
System.out.println();
}
}
break;
}```
Use Scanner.nextLine() then split the supplied string. If the length of array is greater than 1 or the supplied string is empty then issue an invalid entry message and have the User enter the string over again:
while(tries2 == 0) {
searchKeyword = "";
while (searchKeyword.isEmpty()) {
System.out.println("Enter 1 keyword: ");
searchKeyword = sc.nextLine().trim();
if (searchKeyword.isEmpty() || searchKeyword.split("\\s+").length > 1) {
System.out.println("Invalid Entry! {" + searchKeyword
+ "You must supply a single Key Word!");
searchKeyword = "";
}
}
tries2++;
// ... The rest of your code ...
}
From the docs of Scanner.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.
You would need to call next() again to get the the rest of the input.
Much simpler would be to use Scanner.nextLine() to get entire line and then use String.split() with whatever delimiter you are using to get an array of all inputted keywords.
Edit: Scanner.next(pattern) may do what you are looking for. It throws InputMismatchException if the input does not match provided pattern(regex). Example:
scanner.next("^[a-zA-Z]+$")
This requires the entire line to consist of lower and/or upper case letters and nothing else.

Read text and add to list

I am working on a method that takes a scanner as a parameter, and the values of the text file should be added to the doublyLinkedList. Right now the method is working fine but i have an issue where if it encounters a string in the text file, it stops. I want it in such a way that i skip over any line that has a string i tried using the nextLine() but it didnt work.
public static void addList(Scanner input, DoublyLinkedList list){
Number data=null;
if(input.hasNextLine()){
if(input.hasNextInt()){
data=input.nextInt();
list.addEnd(data);
parseScanner(input, list);
}
else if(input.hasNext()){
input.hasNext();
}
}
}
I think in.hasNext() should be input.hasNext()
I think you should use hasNextInt() method of the scanner. If this method will return false, you can just read string and then again try to read int.
if (input.hasNextInt()) {
// read int
} else {
input.nextLine(); // skip line that is not a number
}

Can Scanner.next() return null or empty string?

I'm learning Java coming from other programming languages (Js, C and others..)
I'm wondering if under any circumstances the Scanner.next() method could return (without throwing) an invalid string or less than one character (ie. null or empty string ""). I'm used to double-check user input for any possible unexpected/invalid value, but I wanted to know if testing for null and myString.length() < 1 is always unnecessary or could be useful/needed.
I'm asking in particular when reading from the commandline and System.in, not from other Streams of Files. Can I safely get the first character with myString.charAt(0) from the returned value when reading normally from the terminal input (ie. no pipes and no files, straight from terminal and keyboard)?
I searched the Java SE 9 API Docs and couldn't find mentions about possibly unexpected return values. In case anything goes wrong with input it should just throw an Exception, right?
Example (part of main method without imports):
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter a selection (from A to E): ");
String res = keyboard.next();
if (res == null || res.length() < 1) {
// Unnecessary if?
}
Scanner#next can never return null and if the user enters an empty string or a string containing whitespaces only then the method will block and wait for input to scan.
Therefore the if condition is redundant and is not needed at all.
Scanner.next can never return null by looking at its source code. From Scanner.next code
while(true){
...
if (token != null) {
matchValid = true;
skipped = false;
return token;
}
...
}
It can throw NoSuchElementException if no more tokens are available or IllegalStateException if the scanner is closed according to the docs. So your checks are redundant.
Given the following input:
a b c
d e
f
g
The breakdown below shows how a certain sequence of calls to a Scanner object, , will read the above input:
A call to scan.next(); returns the next token, a.
A call to scan.next(); returns the next token, b.
A call to scan.nextLine(); returns the next token, c. It's important to note that the scanner returns a space and a letter, because it's reading from the end of the last token until the beginning of the next line.
A call to scan.nextLine(); returns the contents of the next line, d e.
A call to scan.next(); returns the next token, f.
A call to scan.nextLine(); returns everything after f until the beginning of the next line; because there are no characters there, it returns an empty String.
A call to scan.nextLine(); returns g.

java Bug or feature - Why is this not throwing an exception

Consider the following java code which opens a file, reads all of the data, then tries to read one more line.
public static void main ( String[] argv) {
FileInputStream inFile = null;
try {
inFile = new FileInputStream("DemoRead.txt");
}
catch ( FileNotFoundException ex) {
System.out.println("Could not open file "+ ex.getMessage());
System.exit(0);
}
Scanner inputStream = new Scanner( inFile);
while ( inputStream.hasNext()) {
System.out.println( inputStream.nextLine());
}
System.out.println(inputStream.nextLine());
inputStream.close();
}
I would expect that the final inputStream.nextLine() would throw an exception as there is nothing else to read.
Indeed if I change the while loop to:
while ( true) {
System.out.println ( inputStream.nextLine());
}
It does throw an exception as expected.
This is not making any sense to me. Any insight would be appreciated.
hasNext() can return false before the end of the file if there are no more tokens left. This is the case when there are only delimiters left at the end of the file.
Compare this with hasNextLine(). If you're using nextLine() then the condition should be hasNextLine(). hasNext() is used with next().
1stly 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.But in case of while loop we always get true.
2ndly in case of nextLine()--Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.
Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.
so,in case of while(true) we are getting always true and at certain point the nextLine() method finds no line separator so gives exception, but in case of while(hasNext()) method it returns false when there is no token in the file so loop breaks so no Exception comes..
Hope this may help you out.

Not asking for input after the while loop starts again

My program is to enter a substring and return all the books based upon the search.i want to ask the user again to search again from the same records.The code is not asking for the user input for the second time.Kindly help
boolean runnable=true;
while(runnable)
{
System.out.println("\n\nInput Books you wish for search");
String search;
search=br.nextLine();
System.out.println("\n\nBooks by your search");
for(int i=0;i<noOfrecords;i++)
{
if(books[i].toLowerCase().contains(search.toLowerCase()))
{
System.out.println(books[i]);
}
}
System.out.println("\n\nMore Books");
for(int i=0;i<noOfrecords;i++)
{
if(!(books[i].toLowerCase().contains(search.toLowerCase())))
{
System.out.println(books[i]);
}
}
System.out.println("do you wish to search again from the same records?? (y/n)");
char searchagain=br.next().charAt(0);
if(searchagain!='y')
{
runnable=false;
}
else if(searchagain=='y')
{
runnable=true;
}
}
I am sure that you have an extra unconsumed new line character in your buffer. Consume it by adding a line at the end of the while loop after else-if
else if(searchagain=='y')
{
runnable=true;
}
br.nextLine();
When you hit enter after keying the first input, Scanner.nextLine() advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. so, the line seperator \n is still in the buffer, which is been consumed while iterating the loop for the second time.we need to consume it purposefully by invoking br.nextLine(); at the end of the while loop and leave the new line character \n in air and go for second loop for fresh input. This will make it to stop and get the input for the second time.
Let me explain you in a simple way. Your program asks for
Input Books you wish for search
Now, you give Effective Java and press enter. This would become
EffectiveJava\n
\n (unconsumed char) in the end of your input will not be consumed by br.nextLine(). So, we need to explicitly get rid of it at the end of while loop. so, that \n will not be consumed by the br.nextLine() during the second loop and it will ask for your input
Because you are not able to read single character from console - System.in because new bytes are available in stream after Enter key is pressed.
Can be useful:
http://sourceforge.net/projects/javacurses/
http://jline.sourceforge.net/
I made little changes in your code.
public void searchMethod(List<String> books){
Scanner scanner = new Scanner(System.in);
System.out.println("\n\nInput Books you wish for search");
//this code is executed when books is null, so first time you can invoke that method passing as argument simply null.
if(books == null){
while(scanner.hasNext())
books.add(scanner.nextLine());
}
System.out.println("\n\nBooks by your search");
for(String book : books)
{
if(book.toLowerCase().contains(search.toLowerCase()))
{
System.out.println(book);
}
}
System.out.println("\n\nMore Books");
for(String book:books)
{
if(!(book.toLowerCase().contains(search.toLowerCase())))
{
System.out.println(book);
}
}
System.out.println("do you wish to search again from the same records?? (y/n)");
char searchagain=scanner.nextLine();
if(!searchagain.equals("y"))
{
return;
}
else if(searchagain.equals("y"))
{
searchMethod(books);
}
}
}
change next().charAt(0) to nextLine().charAt(). it will work.i think reason for this is next() sperates the token by spaces and read the token one by one from the buffer and stay at the line. when next() reaches the end of line and if u call nextLine(), then nextLine() encounter the end of line and nextLine() return blank line.
char searchagain = br.next().charAt(0);
to
char searchagain = br.nextLine().charAt(0);

Categories

Resources