Java command line console and switch - java

i have the following problem: i want to read in a String from the user, so far it works pretty well but everytime i press just "return" i get alway the following error:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.String.charAt(String.java:658)
at Shell.execute(Shell.java:20)
at Shell.main(Shell.java:55)
This would be the code:
private static void execute(BufferedReader stdin) throws IOException {
boolean quit = false;
Field test = new Field();
while (!quit) {
System.out.print("ch> ");
String input = stdin.readLine();
if (input == null) {
break;
}
String[] tokens = input.trim().split("\\s+");
tokens[0].toLowerCase();
char tmp = tokens[0].charAt(0);
switch (tmp) {
case 'n':
test.setPoints(null);
break;
case 'a':
test.add(new Point(Integer.parseInt(tokens[1]), Integer
.parseInt(tokens[2])));
break;
case 'r':
test.remove(new Point(Integer.parseInt(tokens[1]), Integer
.parseInt(tokens[2])));
break;
case 'p':
System.out.println(test);
break;
case 'c':
System.out.println(test.convexHull());
break;
case 'h':
System.out.println("");
break;
case 'q':
quit = true;
break;
default:
break;
}
}
}
Thanks for your help.

If you get an index out of bounds exception when accessing the 0th element, you string is probably empty. You need to add a check for this, checking for null is not enough.
By the way, when you write like this:
tokens[0].toLowerCase();
I highly suspect your tokens[0] remains unchanged. Since strings in java are immutable, toLowerCase will have to return a new string which only contains lower case character.

See whether your tokens array is populated with any strings after splitting because I think that is creating problem.

Your input String is empty if you pressed return change your code as follows to fix it.
while (!quit) {
System.out.print("ch> ");
String input = stdin.readLine();
if (input == null && input.length()<1) { //changed line!
break;
}
String[] tokens = input.trim().split("\\s+");

here is the problem
String input = stdin.readLine();
if (input == null) {
break;
}
here pressing "return" doesn't give you the null and your if condition fails.
code fails at below line
tokens[0].toLowerCase();

It is clear user input is empty string. Put empty string check before splitting it.
if (input == null && input.isEmpty()) {
break;
}

Related

How does returning a value work in a recursive method? [Java]

TLDR : java seems to only return the first value when the method is run. Am I wrong about this, or is there a workaround I'm not aware of [without resorting to loops] ?
My goal is to output the last value [boolean] from the return which gets assigned to the method, however I am unable to do it without a proper understanding of how return works.
Aim of the code is to return a boolean, from a simple choice [Y/N] by reading user input. If a wrong output [eg: "p","P","apples"] is given, the method should prompt the user again, until the right input is given.
This is what I started out with:
private Boolean nrCheck()
{
Scanner sc = new Scanner (System.in);
Boolean isNewRelease;
System.out.println("New Release [Y/N]? ");
String movieType = sc.nextLine();
switch (movieType)
{
case "Y" : case "y" : isNewRelease = true; break;
case "N" : case "n" : isNewRelease = false; break;
default : /*Try again*/ nrCheck(); break;
}
return isNewRelease;
}
Obviously this won't work, since the default case does not assign a value,
resulting in an Initialization error.
Attempted to fix this by assigning a default value, like this :
private Boolean nrCheck()
{
Scanner sc = new Scanner (System.in);
Boolean isNewRelease;
System.out.println("New Release [Y/N]? ");
String movieType = sc.nextLine();
switch (movieType)
{
case "Y" : case "y" : isNewRelease = true; break;
case "N" : case "n" : isNewRelease = false; break;
default : /*printTryagain*/ isNewRelease = null; nrCheck();break;
}
return isNewRelease;
}
This presents a new problem. For some reason, when I recall the method again, the return value is already set. I've tried to play around with the order of the code, and it doesn't really do much. My speculation is that once you recall the method, the return value is automatically set, and you cannot change it if set the first time.
And I am aware I could do this,
private Boolean nrCheck()
{
Scanner sc = new Scanner (System.in);
Boolean isNewRelease;
System.out.println("New Release [Y/N]? ");
String movieType = sc.nextLine();
do
{
switch (movieType)
{
case "Y" : case "y" : isNewRelease = true; break;
case "N" : case "n" : isNewRelease = false; break;
default : /*printTryagain*/ isNewRelease = null; nrCheck();break;
}
}
while (movieType.equalsIgnoreCase("Y") || movieType.equalsIgnoreCase("N"))
return isNewRelease;
}
But personally prefer not to unless I'm fully aware there isn't another solution, or there isn't a blatantly obvious error in my code. [Also want to extend this code to become a bit more general-purpose].
Ultimately, I want to be able to understand what mistake I have made, or if there isn't any, the limitations of return in this case, even if it means I have to scrap my code for a do-while loop.
You should return the value returned by the recursive call:
private boolean nrCheck()
{
Scanner sc = new Scanner (System.in);
System.out.println("New Release [Y/N]? ");
String movieType = sc.nextLine();
switch (movieType)
{
case "Y" : case "y" : return true;
case "N" : case "n" : return false;
default : return nrCheck();
}
}
If you ignore that value, there's no point in making the recursive call in the first place.
P.S., you can probably change the return type of the method to boolean, since it can never return null.
I don't think you even need recursion here, and it looks like you are understanding what it is used for incorrectly. Your third attempt with a do loop is the typical way you would poll a user for input:
private boolean nrCheck() {
Scanner sc = new Scanner (System.in);
boolean isNewRelease;
System.out.println("New Release [Y/N]? ");
menuRedirect(movieType); // don't know what this is doing...
do {
String movieType = sc.nextLine();
} while (!movieType.equalsIgnoreCase("Y") && !movieType.equalsIgnoreCase("N"));
// at this point, the movie type can only be y/Y/n/N
isNewRelease = movieType.equalsIgnoreCase("Y") ? true : false;
return isNewRelease;
}
Just Make Small Change In Your Method As Given Below
private Boolean nrCheck() {
Scanner sc = new Scanner(System.in);
Boolean isNewRelease = null;
//While loop here which break only if isNewRelease value is
//Non null(true or false)
while (isNewRelease == null) {
System.out.println("New Release [Y/N]? ");
String movieType = sc.nextLine();
menuRedirect(movieType);
switch (movieType) {
case "Y":
case "y":
isNewRelease = true;
break;
case "N":
case "n":
isNewRelease = false;
break;
default:
System.out.println("Try Again");
/*I removed recursive call which not required because recursive calls always creates new stack frames so it is recommenced that if we are going to use such calls we need to go with tail recursion.*/
isNewRelease = null;
break;
}
}
return isNewRelease;
}

Scanner returning an error for no reason?

I'm trying to do this line of code. I want it to take a String, if it is 1,2,3,4,5,6,7,8,9 or 10 to parse it into a int and then check if it is between 0 and 9 (after a -1). The issue is right after the scanner happens I get an error no matter what I do...
public void guessEnter() {
Scanner scan = new Scanner(System.in);
String guessXS;
String guessYS;
boolean pass1;
boolean pass2;
do{
do{
System.out.println("Enter a value for the column!");
guessXS = scan.nextLine();
switch(guessXS){
case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9":case "10":
System.out.println("TRUE");
pass1 = true;
break;
default:
System.out.println("FALSE");
pass1 = false;
break;
}
}while(pass1 == false);
do{
System.out.println("Enter a value for the row!");
guessYS = scan.nextLine();
switch(guessYS){
case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": case "10":
pass2 = true;
System.out.println("TRUE");
break;
default:
pass2 = false;
System.out.println("FALSE");
break;
}
}while(pass2 == false);
guessX = Integer.parseInt(guessXS) - 1;
guessY = Integer.parseInt(guessYS) - 1;
}while(guessX >= 0 && guessX <= 9 && guessY >= 0 && guessY <= 9);
}
Why this is happening is beyond me. I am fairly new to java and need this error sorted out.
The error is...
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:864)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
at shipLocation.xyInput(shipLocation.java:11)
at battleShipMain.main(battleShipMain.java:53)
Thanks for the help.
Even if the question has already been answered (the error was in a different class) and the provided code caused no error you maybe want to improve your code a bit. To make it easier to read and understand in case you have to change it later.
You could for example wrap the input and validation part in a method:
private int readIntBetweenMinAndMax(String msg, int min, int max) {
Scanner scanner = new Scanner(System.in);
System.out.println(msg);
int userInput;
do {
try {
userInput = Integer.parseInt(scanner.nextLine());
} catch (NumberFormatException e) {
System.err.println("Please enter a valid integer");
continue;
}
if (userInput > max || userInput < min) {
System.err.println("Please enter a integer between " + min + " and " + max);
continue;
}
return userInput;
} while (true);
}
The method above prints a provided string msg and then reads in an integer. It checks if the user input is an integer and if it's greater or equals than min and less or equals than max. In case one of the three conditions fails the method will print an error message and prompt the user for a new input until its correct.
Note: You could of course also include the "TRUE" and "FALSE" outputs if you want
So you would only have to call the method two times in your guessEnter method:
public void guessEnter() {
guessX = readIntBetweenMinAndMax("Enter a value for the column!", 1, 10) - 1;
guessY = readIntBetweenMinAndMax("Enter a value for the row!", 1, 10) - 1;
}
This would accept one, ten and any number between the them. And subtract one as you did in your code.
As a said, it's just a suggestion and I'm not sure if a got everything form your code right but I hope it helps (:

how to generate a random numbers for a credit card

I created a code to generate a random credit card number and I'm using this method to return a credit card number based in the user input. For some reason I am having a problem returning a value. Help please.
public String getIssuerCode(String issuerSymbol) {
String creditCardNumber = null;
for (int i = 0; i < 15; i++) {
switch (issuerSymbol) {
case ISSUER_MASTER_CARD:
creditCardNumber = generateMasterCard();
break;
case ISSUER_AMER_EXPRESS:
creditCardNumber = generateAmericanExpress();
break;
case ISSUER_VISA:
creditCardNumber = generateVisa();
break;
// System.out.println("error");
default:
break;
}
}
return creditCardNumber;
}
You have a couple of things going on here.
First and foremost, you have a simple typo in your code, as #brycem in his answer already told you. Secondly, it is possible that, after the for-loop and switch statements, creditCardNumber hasn't been initialized. This means that no value has been assigned to it. Now this may be impossible to happen, but your compiler doesn't know that. Thus, a simple fix is to assign it to null in the beginning:
public String getIssuerCode(String issuerSymbol) {
String creditCardNumber = null;
for (int i = 0; i < 15; i++) {
switch (issuerSymbol) {
case ISSUER_MASTER_CARD :
creditCardNumber = generateMasterCard();
break;
case ISSUER_AMER_EXPRESS :
creditCardNumber = generateAmericanExpress();
break;
case ISSUER_VISA:
creditCardNumber = generateVisa();
break;
default:
break;
}
}
return creditCardNumber;
}
Edit:
From your comment below I drew the conclusion that the class that has this method also has the issuerNumber. In this case, you should definitely do this:
public String getIssuerCode() {
String creditCardNumber = null;
for (int i = 0; i < 15; i++) {
switch (this.getIssuerSymbol()) {
case ISSUER_MASTER_CARD :
creditCardNumber = generateMasterCard();
break;
case ISSUER_AMER_EXPRESS :
creditCardNumber = generateAmericanExpress();
break;
case ISSUER_VISA:
creditCardNumber = generateVisa();
break;
default:
break;
}
}
return creditCardNumber;
}
The problem in your case is that there is one path in your program that might return an uninitialized String. If "issuerSymbol" is none of the three cases, you will fall in your "default case", which don't initialize your creditCardNumber variable.
The solution is to give a default value to the variable creditCardNumber at line 2:
public String getIssuerCode(String issuerSymbol) {
String creditCardNumber = null;
...
}
OR update your default case
switch (issuerSymbol) {
case ISSUER_MASTER_CARD :
creditCradNumber = generateMasterCard();
break;
case ISSUER_AMER_EXPRESS :
creditCardNumber = generateAmericanExpress();
break;
case ISSUER_VISA:
creditCardNumber = generateVisa();
break;
default:
creditCardNumber = "000-000-000";
break;
}
Feel free to put any value as the default value. Personnally "null" is a good candidate as it shows immediately that something wrong happened, but it might make you crash later on if don't handle it correctly. Therefore a safer choice could be any String value, like "000-000-000".
Yeah, well. In case you didn't notice by now, you simply mispelled "card" and wrote "crad".
Concretely, you created a variable String creditCradNumber; <- Notice the "Crad" instead of "Card".
But you spelled it differently in the return statement return creditCardNumber; <- NOW it's Card.
That's most likely your problem. Take another look at your code now and be sure to check your variable's name spelling now so it remains the same every time you want to use it. :)
Cheers.
Edit: As shown in other answers, your code ALSO has the problem of not initializing the String creditCardNumber if none of the cases are met on your switch. Initializing it to null:
String creditCardNumber = null;
or using a default case on your switch:
default:
creditCardNumber="000-000-000";
break;
may solve the problem.
Okay, just to debug your "null", you should try to add more debug lines:
public String getIssuerCode(String issuerSymbol) {
String creditCardNumber = null;
System.out.println(issuerSymbol);
switch (issuerSymbol) {
case ISSUER_MASTER_CARD:
System.out.println("Card was of type: " + ISSUER_MASTER_CARD);
creditCardNumber = generateMasterCard();
break;
case ISSUER_AMER_EXPRESS:
System.out.println("Card was of type: " + ISSUER_AMER_EXPRESS);
creditCardNumber = generateAmericanExpress();
break;
case ISSUER_VISA:
System.out.println("Card was of type: " + ISSUER_VISA);
creditCardNumber = generateVisa();
break;
default:
System.out.println("Card is NOT one of the expected type!");
break;
}
}
System.out.println("Generated credit card number is : " + creditCardNumber);
return creditCardNumber;
}
If you have "null", then you must see "Card is NOT one of the expected type!". If not, this means that there is a problem in your function generatedAmericanExpress() and this is what returns null.
You've used a variable named "creditCradNumber" when setting in several instances rather than "creditCardNumber".

How to break out of loop when case is selected

I have a code that has 4 cases and I am trying to break the loop and if the 'f' case is chosen. and then choose from that case. When i try to do the if statement with the break over 30 errors but when I take it away the code is fine.
String one = "";
boolean yea = true;
Scanner sw = new Scanner(System.in);
while (yea == true)
{
System.out.print(MENU);
one = sw.next();
char choice = one.charAt(0);
switch(choice)
{
case 'f':
friendsList();
break;
case 'w':
wall();
break;
case 'p':
network();
break;
case 'q' :
yea = false;
break;
default:
System.out.println("Error: You have entered " + choice +
". Please try again");
}
}
if (case == 'f')
{
break;
}
}
You would use a Java label (see this code example named BreakWithLabelDemo.java) to tell your code where to break.
myloop:
while ( true ){
switch( choice ){
case 'f':
friendsList();
break myloop;
}
}
For your implementation, it would make sense to break on a specific case before even entering the switch statement. For example:
char choice = one.charAt(0);
if (choice == 'f') break;
switch(choice)
This seems to be a pretty simple way to exit the while loop without conflicting with the break statements of the switch statement.
Or if you still need to call the friendsList method when choice is 'f' you can move that if statement to after the switch statement.
Note: With this you should also remove the if statement at the bottom of your code example.
if (case == 'f')
What is case in this statement? You should replace that with choice.
if (choice == 'f')
you need to put if inside while loop.
String one = "";
boolean yea = true;
Scanner sw = new Scanner(System.in);
while (yea == true)
{
System.out.print(MENU);
one = sw.next();
char choice = one.charAt(0);
switch(choice)
{
case 'f':
friendsList();
break;
case 'w':
wall();
break;
case 'p':
network();
break;
case 'q' :
yea = false;
break;
default:
System.out.println("Error: You have entered " + choice +
". Please try again");
}
if (choice == 'f')
{
break;
}
}
The if statement should be moved inside of the while loop to be effective, and case inside the if statement should be changed to choice.
so
While(yea==true)
{
System.out.print(MENU);
one = sw.next();
char choice = one.charAt(0);
if(choice == 'F')
{
break;
}
switch(choice)
{
//cases
}
}

Terminate Java Program on Ctrl+Z input from user

I have following code:
String inputString;
Scanner in = new Scanner(System.in);
while (true) {
System.out.print("jcp>");
inputString = in.nextLine();
String[] tokens = inputString.split(" ");
switch (tokens[0]) {
case "new":
createNewInstance(tokens);
break;
case "call":
callMethod(tokens);
break;
case "print":
Object obj = hashMap.get(tokens[1]);
print(obj);
break;
default:
System.out.println("Illegal command!");
break;
}
}
I simply want the program to break out of while loop when user hits ctrl+Z
nextLine() will throw NoSuchElementException when the stream has reached its end. Or you can use in.hasNextLine().
Ctrl+Z to exit the program would be bad, Ctrl+C|Ctrl+D already ends the program execution on terminal, so it would be good the same way you expect users to type in commands, tell them to type exit as the command to EXIT your program and shortcuts like x or e can be used instead of complete word.
How about following code,
String inputString;
Scanner in = new Scanner(System.in);
while (true) {
System.out.print("jcp>");
inputString = in.nextLine();
String[] tokens = inputString.split(" ");
switch (tokens[0]) {
case "n":
case "new":
createNewInstance(tokens);
break;
case "c":
case "call":
callMethod(tokens);
break;
case "p":
case "print":
Object obj = hashMap.get(tokens[1]);
print(obj);
break;
case "e":
case "x":
case "exit":
return;
default:
System.out.println("Illegal command!");
break;
}
}
If return; won't work you can replace that with System.exit(0);

Categories