0

So I spent some time studying up on util.Scanner thanks to some feedback here. The statement that stuck with me the most was found in this post on How to use java.util.Scanner to correctly...

You will probably never actually see Scanner used in professional/commercial line of business apps because everything it does is done better by something else. Real world software has to be more resilient and maintainable than Scanner allows you to write code. Real world software uses standardized file format parsers and documented file formats, not the adhoc input formats that you are given in stand alone assignments.

So, I looked up some other options for getting user input and decided to use BufferedReader. What I'm trying to accomplish is to get the user to tell the program whether they would like to continue playing the game or not, to have the program repeat the question until given valid input (Y/N), and to have the program continue or terminate as a result of the answer.

Three related questions:

Is BufferedReader a better option than Scanner?

Is there an option that better addresses this task? What is it, if so?

Is it appropriate to have the method call itself to create a "loop" if the answer does not fit the criteria?

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class RageGame {

public static void main(String[] args) throws IOException  {

    char playAgain = 'Y';

    // Loop game until user decides they are done.
    do { 
        playAgain = playRage();

    } while (playAgain == 'Y');

    //Quit message      
    System.out.println("Thanks for playing Rage!");

}

public static char playRage() throws IOException {

    return playAgain();
}
public static char playAgain() throws IOException{
    char answer;

    BufferedReader kb = new BufferedReader(new InputStreamReader(System.in));

    //Ask the user if they want to continue and set their response to upper case.
    System.out.println("Do you wish to play again? (y/n)");
    answer = (char) Character.toUpperCase(kb.read());

    //Check if answer fits criteria
        if (answer != 'Y' && answer != 'N') {
            System.out.println("Sorry, " + answer + " is not a valid answer.");
            return playAgain();

        }else {
        return answer;


        }
    }
}
  • 2
    You shouldn't be closing a Scanner that was created with System.in, since it will close System.in, and you didn't open that. The rule is, you should close everything that you open, but *only* things that you open. – David Conrad Sep 24 '18 at 17:40
  • Use a `try with resources` block. – Nicholas K Sep 24 '18 at 17:40
  • And I also suggest you follow the Java Naming Conventions: class names always start with uppercase. – MC Emperor Sep 24 '18 at 17:46
  • @DavidConrad understood! I saw this answer when I was researching the Resource not closed error originally, but didn't really understand it. I think it's because I was only shown how to create the scanner using System.in. I will do some more research on how to create a scanner. Thanks! – OverlordOfSalt Sep 24 '18 at 17:52

2 Answers2

1

The short answer is: Don't close it.

Your Scanner is using the stream System.in. System.in is not a resource acquired by your program (you didn't open the stream), so you shouldn't close it. Someone else is in charge of closing that.

If you find the warning annoying, you can probably silence it.

Let's suppose that your scanner takes input from a file and not System.in, then you need to call close after the last time you need it:

answer = Character.toUpperCase(kb.next().charAt(0)); 
kb.close();

If you are afraid of forgetting to call close, just use a try-with-resources block and it will close it for you!

try (Scanner kb = new Scanner(some other source)) {
    System.out.println("Do you wish to play again? (y/n)");
    answer = Character.toUpperCase(kb.next().charAt(0)); 
} // this will always close the scanner
Sweeper
  • 213,210
  • 22
  • 193
  • 313
-1

On a alternative note, if you would like to close the scanner, you can wrap the System.in inside a CloseShieldInputStream. Your scanner would use a Proxy Stream. If you are interested take a look at http://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/input/CloseShieldInputStream.html

Vinnie
  • 452
  • 5
  • 24