How do I avoid StringIndexOutOfBoundsException when char has no value? - java

Sorry if the title made no sense but I did not know how to word it.
The problem:
I'm making a multiple choice quiz game that gets either a, b, c or d from the user. This is no problem if they do as they are told, however if they don't type anything and just hit enter I get a StringIndexOutOfBoundsException. I understand why this is happening, but I'm new to Java and can't think of a way to fix it.
What I have so far:
System.out.println("Enter the Answer.");
response = input.nextLine().charAt(0);
if(response == 'a')
{
System.out.println("Correct");
}
else if(response == 'b' || response == 'c' || response == 'd')
{
System.out.println("Wrong");
}
else
{
System.out.println("Invalid");
}
Of course the program will never make it past the second line of code if the user types nothing, because you can't take the charAt(0) value of an empty String. What I'm looking for is something that will check if the response is null, and if so ask go back and ask the question to the user again.
Thanks in advance for any answers.

You can use a do-while loop. Just replace
response = input.nextLine().charAt(0);
with
String line;
do {
line = input.nextLine();
} while (line.length() < 1);
response = line.charAt(0);
This will continue to call input.nextLine() as many times as the user enters a blank line, but as soon as they enter a non-blank line it will continue and set response equal to the first character of that non-blank line. If you want to re-prompt the user for the answer, then you could add the prompt to the inside of the loop. If you want to check that the user entered a letter a–d you could also add that logic to the loop condition.

Either handle the exception(StringIndexOutOfBoundsException) or break this statement
response = input.nextLine().charAt(0);
as
String line = input.nextLine();
if(line.length()>0){
response = line.charAt(0);
}
Exception Handling:
try{
response = input.nextLine().charAt(0);
}catch(StringIndexOutOfBoundsException siobe){
System.out.println("invalid input");
}

Simple:
Get the input initially as a String, and put it into a temporary String variable.
Then check the String's length.
then if > 0 extract the first char and use it.

In addition #HovercraftFullOfEels' (perfectly valid) answer, I'd like to point out that you can "catch" these exceptions. For example:
try {
response = input.nextLine().charAt(0);
} catch (StringIndexOutOfBoundsException e) {
System.out.println("You didn't enter a valid input!");
// or do anything else to hander invalid input
}
i.e. if a StringIndexOutOfBoundsException is encountered when executing the try-block, the code in the catch-block will be executed. You can read more about catching and handling exceptions here.

StringIndexOutofBoundException will occur in the following situation also.
Searching a string which is not available
Match with the string which is not available
for ex:
List ans=new ArrayList();
temp="and";
String arr[]={"android","jellybean","kitkat","ax"};
for(int index=0;index < arr.length;index++ )
if(temp.length()<=arr[index].length())
if(temp.equlsIgnoreCase((String)arr[``index].subSequence(0,temp.length())));
ans.add(arr[index]);
the following code is required to avoid indexoutofboundexception
if(temp.length()<=arr[index].length())
because here we are cheking the length of src string is equal or greater than temp .
if the src string length is less than it will through "arrayindexoutof boundexception"

Related

Is it OK to assign the input from Java Scanner to a variable inside the while loop condition?

For example, like this.
while ((input = kb.nextInt()) != 0) {
if (input % 2 == 0) {
System.out.println("even");
} else {
System.out.println("odd");
}
instead of only checking the value of the input variable inside the condition and getting the number from Scanner inside the loop, like so:
while (input != 0) {
input = kb.nextInt();
...code here...
Just wondering if the first one is bad practice or anything like that.
Using nextInt() as part of a loop condition, while perfectly legal, can be problematic from the standpoint of dealing with errors arising from bad input. Actual humans sitting in front of a keyboard entering data (which the Scanner variable name kb seems to suggest is exactly what you're dealing with here) are notoriously unreliable in terms of their data entry quality, so bad input is something you should be prepared for.
nextInt() will throw an InputMismatchException exception if the next available input is not a valid representation of an integer. In order to catch and handle this exception, the nextInt() call must be executed inside of a try block. However, with the nextInt() being part of the control condition of the while loop, the only way to do that is to enclose the entire loop in the try block:
try {
while ((input = kb.nextInt()) != 0){
...
}
} catch (InputMismatchException ime){
...
}
Unfortunately, this means that any exception raised by nextInt() will kill the while loop. If you wanted to keep processing user inputs after an input error, you'd have to provide a means of starting the while loop over again, and keep starting it over until the "real" user-signaled end-of-input condition had been reached. You might be able to do it with a clunky workaround like this one:
boolean keepGoing = true;
while (keepGoing){
try {
while ((input = kb.nextInt()) != 0) {
...
}
keepGoing = false;
} catch (InputMismatchException ime) {
String junk = kb.next();
System.out.println("Didn't understand your input: " + junk);
System.out.println("Please type a valid integer");
}
}
But depending on what the ... code inside the loop was doing, this relatively simple workaround might be inadequate; you might need something even more complicated and unreadable.
But by moving the nextInt() call out of the control logic of the loop and into the loop body, you gain considerable flexibility in terms of your options for recovery from bad input. With nextInt() inside the loop body, you can now catch and handle any exception entirely within one iteration of the loop, without having to terminate the loop itself:
do {
try {
input = kb.next();
if (input != 0) {
...
}
} catch (InputMismatchedException ime) {
String junk = kb.next();
System.out.println("Didn't understand your input: " + junk);
System.out.println("Please type a valid integer");
}
} while (input != 0);
You'd also have the option of avoiding an exception altogether by using hasNextInt() to ensure that a valid input is present before trying to read it with nextInt():
for(;;) {
if (!kb.hasNextInt()) {
String junk = kb.next();
System.out.println("Didn't understand your input: " + junk);
System.out.println("Please type a valid integer");
} else {
input = kb.nextInt();
if (input == 0) {
break;
else {
...
}
}
}
The second one doesn't have the input defined for testing the condition input!=0 hence the first one is right but if you're going to use the second format I'd suggest to change the while loop to do-while loop.
Your two code samples are not equivalent and do different things (the second version probably doing not what you want it to do).
You would need another if (input != 0) inside the loop and assignment of input before the loop for the second version. Moving the assignment to the end and duplicating it before the loop is also a viable option:
input = kb.nextInt();
while (input != 0) {
if (input % 2 == 0) {
System.out.println("even");
} else {
System.out.println("odd");
}
input = kb.nextInt();
}
And the duplicated first and last line in this version is very likely the reason for the somewhat complicated code. This type of loop loop ((x = input()) != 0) can be seen in a lot of C code but is sometimes "required" in Java too when you want to reduce code-duplication when processing input. This is caused by the fact that nextInt returns a value and mutates the underlying state.

Checking user input with scanner

I am trying to implement a simulator that has certain commands the user can input.
One of these commands is "s" which when entered should step through one instruction of the assembly file. However there is another instruction with the format "s num" where the user can define just how many instructions they want to step through.
I check for this
if(input.equals("s"))
{
//check for num next
if(user.hasNextInt())
{
input = user.next();
step(Integer.parseInt(input), assembler);
}
else
{
step(1, assembler);
}
}
However the problem is if the user only enters "s" the scanner will wait for the next input rather than just calling step. My idea is if there is an int after the s was input then proceed with the num step, other wise just call step.
Any help is greatly appreciated!
I would split the input into two parts and then treat it. For example,
String input = user.nextLine();
String array[] = input.split(" ");
if(array.length<2){
//check for `s`
}else{
//check for `s num`
}
you could try this:
if(input.equals("s"))
{
step(1, assembler);
}
else if(input.startsWith("s") && input.length() > 2)
{
step(Integer.parseInt(input.substring(input.indexOf(" ")+1)), assembler);
}
If control were to go inside the else if block, the current solution assumes that there is always a number after the String s with a white space delimiter in between them, but you can go on further and do more validations if necessary.

Why does this While loop cycle twice?

I made this while loop that is supposed to fulfill functions for different shapes and after it fulfills the function for that shape, it will keep asking for shapes until the user types "Exit". I have only done Triangles so far so I just have some filler functions to fulfill to make sure that it loops correctly. The problem is, after I'm done with triangles, it will print the menu twice before asking for an input instead of just printing once. Can anyone explain this to me?
while(password){
System.out.println();
System.out.println("---Welcome to the Shape Machine---");
System.out.println("Available Options:");
System.out.println("Circles");
System.out.println("Rectangles");
System.out.println("Triangles");
System.out.println("Exit");
String option = keyboard.nextLine();
if(option.equals("Exit")){
System.out.println("Terminating the program. Have a nice day!");
return;
} else if(option.equals("Triangles")){
System.out.println("Triangles selected. Please enter the 3 sides:");
int sideA = 0;
int sideB = 0;
int sideC = 0;
do{
sideA = keyboard.nextInt();
sideB = keyboard.nextInt();
sideC = keyboard.nextInt();
if(sideA<0 || sideB<0 || sideC<0)
System.out.println("#ERROR Negative input. Please input the 3 sides again.");
} while(sideA<0 || sideB<0 || sideC<0);
if((sideA+sideB)<=sideC || (sideB+sideC)<=sideA || (sideA+sideC)<=sideB){
System.out.println("#ERROR Triangle is not valid. Returning to menu.");
continue;
} else {
System.out.println("good job!");
}
}
}
It might be that you are using keyboard.nextLine();. In your code outside the while loop make sure that you are always using .nextLine() and nothing else.
Reasoning: If you use .next(), it'll only consume one word so the next time you call .nextLine(), it'll consume the end of that line.
After you say sideC = keyboard.nextInt() the carriage return that you typed (after typing the number) is still in the input buffer. Then you print the menu and execute String option = keyboard.nextLine(); That command reads up to and including the first newline it finds, which is the newline that is still in the buffer.
So option is now a bare newline character, which does not match "Exit" or "Triangle", so it loops again and prints th menu again.
This problem is caused by left-over characters like space, carriage-return, newline, form-feed in the input buffer.
Since the next keyboard.nextLine() doesn't match any of given options (and since there is no "else" at the bottom of while loop to deal with this case), the control goes into next iteration, prints the options again. Based on surrounding context of processing of input, there are several good answers to address this problem on SO.
Since your intention is to skip over all blanks, carriage-returns, newlines, form-feeds till you get a valid string (option) again, the following code works best in a case like yours.
System.out.println();
System.out.println("---Welcome to the Shape Machine---");
//...
System.out.println("Exit");
String option = keyboard.nextLine();
keyboard.skip("[\\s]*");

Handle StringIndexOutOfBoundsException for string

try {
string = scan.nextLine().charAt(0);
} catch(StringIndexOutOfBoundsException siobe){
System.out.println("invalid input");
}
I am trying to use this code for handling exception for the string that i am getting from a text file. But i get an error saying try to change the actual string declaration to character. I am not sure how to handle this ?
But i get an error saying try to change the actual string declaration to character.
scan.nextLine().charAt(0) is a char so if string is a String (as implied by the compilation error you got), you can't assign a char to it.
If you need just the first character of the input line, you should store it in a char variable.
char first;
try {
first = scan.nextLine().charAt(0);
} catch(StringIndexOutOfBoundsException siobe){
System.out.println("invalid input");
}
Of course you can avoid the need to catch this exception if you test the length of the String before getting its first character :
char first;
String line = scan.nextLine();
if (line.length() > 0)
first = line.charAt(0);
else
System.out.println("invalid input");
Your compilation error is because String.charAt() returns a char, not a String. They're different types - and you need to be very clear about the difference between them. You could just change the variable to a char variable, renaming it at the same time - but that's a really bad way of checking whether or not a string is empty. Deliberately provoking an exception like this when you can just test it directly is a bad idea - any time you find yourself catching a specific RuntimeException, you should ask yourself whether there's a better way of avoiding it.
You should use String.isEmpty() or String.length() before trying to take the first character of it. For example:
String line = scan.nextLine();
if (line.isEmpty()) { // Or line.length() == 0
// Whatever you want to do for invalid input.
} else {
char firstChar = line.charAt(0);
// Use firstChar
}
Of course, if you don't actually need the first character, and you were just trying to detect empty strings, you can just use the first part of this, without the else.
The method charAt() as the name indicates returns character. So the compilation error was because you are trying to assign a character to the variable (in your case, string) of type String.
If your objective is to retrieve the next line from scanner object and check it's 0th index for character to look for exception, you can do something like below:
String string = null;
..
char c;
string = scan.nextLine();
try {
c = string.charAt(0);
} catch (StringIndexOutOfBoundsException siobe) {
//Exception handling
}
This way, you can continue to use the string that was read using nextLine() prior to the exception happened due to the call of charAt().
Hope this helps.

Converting a string input from user to a numeric (int) value.

I've been trying different methods for converting a user string input into an int I could compare and build an "if-then" statement. Every time I tried testing it, it just threw exception. Can anyone look at my Java code and help me find the way? I'm clueless about it (also a noob in programming). If I'm breaking any rules please let me know I'm new here. Thank you.
Anyway, here is the code:
System.out.println("Sorry couldn't find your user profile " + userName + ".");
System.out.println("Would you like to create a new user profile now? (Enter Y for yes), (Enter N for no and exit).");
try {
BufferedReader answer = new BufferedReader(new InputStreamReader(System.in));
String addNewUser = answer.readLine();
Character i = new Character(addNewUser.charAt(0));
String s = i.toString();
int answerInDecimal = Integer.parseInt(s);
System.out.println(answerInDecimal);
}
catch(Exception e) {
System.out.println("You've mistyped the answer.");
e.getMessage();
}
It seems like you are trying to convert the string (which should be a single character, Y or N) into its character value, and then retrieve the numerical representation of the character.
If you want to turn Y or N into their decimal representation, you have to perform a cast to int:
BufferedReader answer = new BufferedReader(new InputStreamReader(System.in));
String addNewUser = answer.readLine();
char i = addNewUser.charAt(0);
int integerChar = (int) i; //The important part
System.out.println(integerChar);
This will return the integer representation of the character that the user input. It may also be useful to call the String.toUpperCase() method in order to ensure that different inputs of Y/N or y/n do not give different values.
However, you could also do an if-else based upon the character itself, rather than converting it to an integer.
BufferedReader answer = new BufferedReader(new InputStreamReader(System.in));
String addNewUser = answer.readLine();
char i = addNewUser.toUpperCase().charAt(0);
if (i == 'Y') {
//Handle yes
} else if (i == 'N') {
//Handle no
} else {
System.out.println("You've mistyped the answer.");
}
I think you meant to ask them to Enter 0 for yes and 1 for No ? Maybe?
You're asking the user to type Y or N and then you're trying to parse that to an integer. That will always throw an exception.
EDIT -- As others have pointed out, if you want to continue to use Y or N, you should do something along the lines of
String addNewUser = answer.readLine();
if ( addNewUser.toLowerCase().startsWith("y") ) {
// Create new profile
}
parseInt is just for converting text numbers into integers: everything else gets a NumberFormatException.
If you want the decimal ASCII value of a character, just cast it to an int.
Use if (addNewUser.startsWith("Y") || addNewUser.startsWith("y")) { instead.
Or (as Mark pointed) if (addNewUser.toLowerCase().startsWith("y")) {.
BTW maybe look at Apache Commons CLI?
You cannot convert String to int, unless you know the String contains a valid integer.
Firstly, using the Scanner class for input is better, since its faster
and you don't need to get into the hassle of using streams, if you're
a beginner. This is how Scanner will be used to take input:
import java.util.Scanner; // this is where the Scanner class resides
...
Scanner sc = new Scanner(System.in); // "System.in" is the stream, you could also pass a String, or a File object to take input from
System.out.println("Would you like to ... Enter 'Y' or 'N':");
String input = sc.next();
input = input.toUpperCase();
char choice = sc.charAt(0);
if(choice == 'Y')
{ } // do something
else if(choice == 'N')
{ } // do something
else
System.err.println("Wrong choice!");
This code could also be shortened to one line (however you won't be
able to check a third "wrong choice" condition):
if ( new Scanner(System.in).next().toUpperCase().charAt(0) == 'Y')
{ } // do something
else // for 'N'
{ } // do something
Secondly, char to int conversion just requires an explicit type
cast:
char ch = 'A';
int i = (int)ch; // explicit type casting, 'i' is now 65 (ascii code of 'A')
Thirdly, even if you take input from a buffered input stream, you
will take input in a String. So extracting the first character from
the string and checking it, simply requires a call to the charAt()
function with 0 as a parameter. It returns a character, which can
then be compared to a single character in single quotes like this:
String s = in.readLine();
if(s.charAt(0) == 'Y') { } // do something
Fourthly, its a very bad idea to put the whole program in a try
block and catch Exception at the end. An IOException can be
thrown by the readline() function, and parseInt() could throw a
NumberFormatException, so you won't be able to handle the 2
exceptions separately. In this question, the code is small enough for
this to be ignored, but in practice, there will be many functions
that can throw exceptions, hence it becomes easy to lose track of exactly which function threw what exception and proper exception handling becomes quite difficult.

Categories