Using try-with-resources with System.in [duplicate] - java

This question already has answers here:
Close Scanner without closing System.in
(3 answers)
Closed 2 years ago.
So my IDE is complaining if I don't enclose the Scanner in a try with block, but if I do it this way instead of closing it when it's supposed to close (once win = true), it closes the System.in stream, how do I prevent that?
public final void turn() {
System.out.println("Enter your next move!");
try (Scanner keyboard = new Scanner(System.in)) {
final String move = keyboard.nextLine();
if (move.isEmpty()) {
won = true;
return;
}
if (!validateFormat(move)) {
System.out.println("Invalid format, try again.");
return;
}
String[] moveAr;
try {
moveAr = move.split(",");
} catch (PatternSyntaxException e) {
System.out.println(e.getMessage());
return;
}
try {
validFields(moveAr);
} catch (InvalidTurnException e) {
System.out.println(e.getMessage());
return;
}
final char colour = spielFeld.getField(getColumn(moveAr[0].charAt(0)),Character.getNumericValue(moveAr[0].charAt(1)) - 1).getColour();
for (final String string : moveAr) {
final int line = Character.getNumericValue(string.charAt(1)) - 1;
final int column = getColumn(string.charAt(0));
spielFeld.cross(column,line);
final int columni = getColumn(string.charAt(0));
if (spielFeld.columnCrossed(columni)) {
points += crossedValues(string.charAt(0));
}
}
if (spielFeld.colourComplete(colour)) {
points += COLOUR_POINTS;
coloursCrossed++;
}
if (coloursCrossed >= 2) {
won = true;
}
}
System.out.println("Momentane Punkte: " + points);
}

I would recommend against having multiple Scanner objects wrapping around the same input stream. (in this case, System.in) The reason for this is because Scanners may consume and buffer data from the underlying stream. This means that in some cases data can be lost. You can read more about it in this question.
You might be able to get away with it here, in which case you should just not close the Scanner object by not wrapping it in a try-with-resources. In that case, you can suppress the warning with #SuppressWarnings("resource"). However, this is bad practice.
Instead, I'd recommend creating a single global Scanner object that wraps around System.in, and then passing it to this method as a parameter instead of creating a new scanner in each method that requires input.

how do I prevent that?
Don't close the Scanner object, i.e. don't use try-with-resources on a Scanner that is wrapping System.in.
Instead, accept the warning and hide it, since it's a special exception to the normal "resource" rules:
#SuppressWarnings("resource")
Scanner keyboard = new Scanner(System.in);
FYI: I'm using Eclipse IDE, and it "Surround with try-with-resources" is only the first option for fixing the warning:

Related

How to develop the code to save more than word in the selected file?

The goal of my program is to give the user the opportunity to add something in a new or old file.
Because of my code the user can add only one word to the file.
I wrote down where the problem is.
I do not know how to make the saving of the words in the file unlimited.
I tried with a for loop... Unfortunately it did not make any sense.
public class AddAndSave {
private static Scanner scanner = new Scanner(System.in);
private static Formatter formatter = null;
private static Scanner reader;
public static void main(String args[]) {
System.out.println("In which file do you want to add?");
String fileName = scanner.next();
File myFile = new File("C://Meine Dateien// " + fileName + ".txt");
if (myFile.exists() == true) {
try {
reader = new Scanner(myFile);
String fileContent = "";
while (reader.hasNext() == true) {
fileContent = fileContent + reader.next();
}
formatter = new Formatter(myFile);
formatter.format("%s", fileContent + " ");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
try {
formatter = new Formatter(myFile);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("What do you want to add?");
String newInput = scanner.next();//hier is the problem
formatter.format("%s", newInput);
System.out.println();
System.out.println("Finish! Thank you for using our programm!");
formatter.close();
}
}
Your problem is the fact that you are utilizing the wrong Scanner method for retrieving String line data from both file and User.
Use the Scanner#nextLine() method instead of the Scanner#next() method and use it in conjunction with the Scanner#HasNextLine() method in your while loop condition (instead of the Scanner#hasNext() method):
String newInput = scanner.nextLine();
Use the Scanner#nextLine() method where you prompt for a file name and prompt for what to add to file!. Also use it within your while loop for reading the file (in conjuction with the Scanner#hasNextLine() method). Carefully read about the differences between all these methods!
Scanner#hasNext() and Scanner#next() methods are more geared towords Token (word) based situations (one word at a time) whereas the Scanner#hasNextLine() and Scanner#nextLine() methods are used for entire string lines. This is what I believe you really want.
Other Notes:
You may want to remove the white-space after your last forward slashes (//):
"C://Meine Dateien// " + fileName + ".txt";
unless of course you want t0 add a white-space at the beginning of every every name for every file created by your application.
When using boolean variables in conditions such as those in if statements, you can just use:
if (myFile.exists()) { // IF true
instead of:
if (myFile.exists() == true) { // IF true
and:
if (!myFile.exists()) { // IF false
instead of:
if (myFile.exists() == false) { // IF false
Either way works just fine but you will later find that the shorter way is less prone to errors due to typo's and I think it's easier to read but that's just my opinion.
Don't forget to close your file reader. Use Try With Resources to take care of this sort of thing for you with regards to both your reader and writer.

Read and Write to a file

I am having to make a gui project for my CSIS class and I am having trouble with the read and Write I am using. I am making a game where you battle stuff and after you beat five of them it shows a message saying "YOU WIN". Every time you win a battle, I have it write the number of wins to a file so if you were to close the game you can continue when it is opened again. Here is the code that i have Written - this is my read method.
private static int read()
{
int returnValue = 0;
try(Scanner reader = new Scanner("wins.txt"))
{
while(reader.hasNextLine())
{
String read = reader.nextLine();
returnValue = Integer.parseInt(read);
}
}
catch(NullPointerException e)
{
System.out.println("No such File! Please Try Again! " + e.getMessage());
}
return returnValue;
and this is my Write method.
private static void write(int wins)
{
try(Formatter writer = new Formatter("wins.txt");)
{
writer.format("%d", wins);
}
catch (FileNotFoundException e)
{
System.out.println("File not Found!!");
}
}
the only thing that is in the wins.txt file is the number that the Write method writes into it. so i win once then the file will have "1" and if i win twice then it will have "2"
Whenever I run the program, it throws a NumberFormatException. I am not sure why it is doing this because I am parseing the String that that reader reads into an int.
The problem is that this code...
Scanner reader = new Scanner("wins.txt")
... constructs a Scanner with the literal text "wins.txt", not the contents of the file "wins.txt".
To read a file with a Scanner, the easiest way for you is probably to construct it using a File object...
Scanner reader = new Scanner(new File("wins.txt"))
There are some other changes you will need to make to your code to get it to work from this point, but this should cover the major issue.

Java is giving me an error of "java.io.ioexception is never thrown in body of corresponding try statement"

So I am making a program that renders pictures from .ppm files. I have got another version working but have now moved on to the other part which is reading multiple images from the same document and to basically use this to animate it with a small delay inbetween switching pictures, and then the following error has come up and am completely stumped by it:
java.io.ioexception is never thrown in body of corresponding try statement
Any help would be much appreciated.
public void renderAnimatedImage(){
String image = UI.askString("Filename: ");
int keepingCount =0; //Variables
int numCount = 1;
try{
Scanner fileScan = new Scanner(image); // making scanners
Scanner scan = new Scanner(image);
File myFile = new File(image); //making files
File myFile2 = new File(image);
int num = 0;
while(scan.hasNextLine()){
String Line = scan.nextLine();
Scanner keywordSc = new Scanner (Line);
while(keywordSc.hasNext()) {
String Keyword = keywordSc.next();
if (Keyword.equals("P3")) {
num++;
}
else { break; }
}
}
while (keepingCount< numCount) {
this.renderImageHelper(scan); // calling upon an earlier method which works.
keepingCount++;
}
}
catch(IOException e) {UI.printf("File failure %s \n", e); }
}
It means the code you're writing inside your try/catch is never throwing an IOException, which makes the clause unnecessary. You can just remove it and keep your code without it.
I bet that you think there could be an IOException because of this line:
Scanner fileScan = new Scanner(image); // making scanners
But that line is not doing what you think it does. Since image is a String this will use the Scanner(String) constructor. But that constructor treats its argument as a string to be scanned, not the name of a file to be scanned.
Hence new Scanner(image) is not doing any I/O and is not declared as throwing an IOException.
And the rest of the code in the block won't throw IOException either. The Scanner next / hasNext methods that you are using will throw a different exception if there is an I/O error while reading. (Check the javadocs.)
Also, you seem to be misunderstanding what File is / does.
File myFile = new File(image); //making files
The comment is incorrect. That does not make a file.
Actually, it makes a File object which is an in-memory representation of a filename / pathname. Creating a File object doesn't cause a file to be created in the file system. (Again, check the javadocs.)

File I/O Java prompt

I had a quick questions about prompting and accepting a file name, then making the file-text a scanner object.
I want the program to prompt the user to enter the name of a file, until he gets one which exists, then for the file-text to be used as a scanner object.
This is the code I have so far, it works to the point where I exit the while {} loop, but then when I try and process the scanner item like while (input.hasNextLine()) { it gives me an error saying it can't find the scanner item.
It's probably a silly mistake, but I just cannot seem to get it.
The whole code is below:
import java.io.*;
import java.util.*;
public class PersonalityTest {
public static void main(String[] args) throws FileNotFoundException {
boolean isFile = false;
Scanner sc = new Scanner(System.in);
System.out.print("Input file name? ");
String fileName = sc.next();
File inputFile = new File(fileName);
while (isFile == false) {
if (inputFile.exists()) {
Scanner input = new Scanner(inputFile);
isFile = true;
}
}
while(input.hasNextLine()) {
}
}
The scope of the input variable is local to the while (isFile == false) block. Declare it outside otherwise it won't be visible.
For the first part "I want the program to prompt the user to enter the name of a file, until he gets one which exists": Move this code:
Scanner sc = new Scanner(System.in);
System.out.print("Input file name? ");
String fileName = sc.next();
File inputFile = new File(fileName);
into a method and call it inside the while (isFile == false) block before the exists check (the method should return with the file or make the variable visible in the block by some other means).
You can't access input outside the if statement, sice the compiler is not sure, it will pass the test, you can do this:
Scanner sc = new Scanner(System.in);
Scanner input = null;
boolean isFile = false;
while (isFile == false){
System.out.print("Input file name? ");
String fileName = sc.next();
File inputFile = new File(fileName);
if (inputFile.exists()){
input = new Scanner(inputFile);
isFile = true;
}
}
But will throw a NullPointerException if it is null.
I changed the code a little bit, that way, it will not exceed if the file doesn't exist.
The Scanner input is local to your if statement. Your while (input.hasNextLine()) { statement will not work because of that. The Java compiler will treat input as a separate Scanner object and that is where the problems crop up, because to the Java compiler, the input that you are trying to use does not exist.
I would follow MouseEvent's suggested code as it does not run into the problem mentioned above.
The other answers have addressed your immediate question, but I want to point out a couple of other problems with your code:
The way that you are checking to see if the file can be opened is flawed. A better way to write the code is to attempt to open the file ... and retry when there is an exception. For example:
Scanner input = null;
do {
System.out.print("Input file name? ");
String fileName = sc.next();
File inputFile = new File(fileName);
try {
input = new Scanner(inputFile);
} catch (IOException ex) {
System.out.println("Cannot open: " + ex.getMessage());
}
} while (input == null);
Why is this better than calling File.exists()?
There are lots of reasons why you might be able to open a file. It might not exist at all. It might be a directory or a special file that can't be opened as a file. The application might not have permission. The file might be on a remote mounted file system and the remote mount might have just died.
There is a small time gap between the File.exists() call (and any others that you might make) and actually opening the file. In that time gap, it is possible that something to your program could do something to make the file unopenable; e.g. it could change its permissions or delete it.
The second problem is that your code potentially leaks a file descriptor because the scanner is not closed. In your specific application (as written) this doesn't matter because you are going to exit the application immediately after using the scanner. But if your weren't ... and this code was called lots of times ... you could find that you are unable to open files after a bit.
The correct way to deal with this would be to write your code something like this:
public static void main(String[] args) {
try (Scanner input = openInput()) {
while (input.hasNextLine()) {
// do stuff
}
}
}
This uses Java 7's new "try with resource" syntax, that ensures that the resource is closed when the try statement completes. (You can do the same thing in pre-Java 7 using a try / finally, but the code is a bit more cumbersome.)

taking integer input in java

I am actually new to java programming and am finding it difficult to take integer input and storing it in variables...i would like it if someone could tell me how to do it or provide with an example like adding two numbers given by the user..
Here's my entry, complete with fairly robust error handling and resource management:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Simple demonstration of a reader
*
* #author jasonmp85
*
*/
public class ReaderClass {
/**
* Reads two integers from standard in and prints their sum
*
* #param args
* unused
*/
public static void main(String[] args) {
// System.in is standard in. It's an InputStream, which means
// the methods on it all deal with reading bytes. We want
// to read characters, so we'll wrap it in an
// InputStreamReader, which can read characters into a buffer
InputStreamReader isReader = new InputStreamReader(System.in);
// but even that's not good enough. BufferedReader will
// buffer the input so we can read line-by-line, freeing
// us from manually getting each character and having
// to deal with things like backspace, etc.
// It wraps our InputStreamReader
BufferedReader reader = new BufferedReader(isReader);
try {
System.out.println("Please enter a number:");
int firstInt = readInt(reader);
System.out.println("Please enter a second number:");
int secondInt = readInt(reader);
// printf uses a format string to print values
System.out.printf("%d + %d = %d",
firstInt, secondInt, firstInt + secondInt);
} catch (IOException ioe) {
// IOException is thrown if a reader error occurs
System.err.println("An error occurred reading from the reader, "
+ ioe);
// exit with a non-zero status to signal failure
System.exit(-1);
} finally {
try {
// the finally block gives us a place to ensure that
// we clean up all our resources, namely our reader
reader.close();
} catch (IOException ioe) {
// but even that might throw an error
System.err.println("An error occurred closing the reader, "
+ ioe);
System.exit(-1);
}
}
}
private static int readInt(BufferedReader reader) throws IOException {
while (true) {
try {
// Integer.parseInt turns a string into an int
return Integer.parseInt(reader.readLine());
} catch (NumberFormatException nfe) {
// but it throws an exception if the String doesn't look
// like any integer it recognizes
System.out.println("That's not a number! Try again.");
}
}
}
}
java.util.Scanner is the best choice for this task.
From the documentation:
For example, this code allows a user to read a number from System.in:
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
Two lines are all that you need to read an int. Do not underestimate how powerful Scanner is, though. For example, the following code will keep prompting for a number until one is given:
Scanner sc = new Scanner(System.in);
System.out.println("Please enter a number: ");
while (!sc.hasNextInt()) {
System.out.println("A number, please?");
sc.next(); // discard next token, which isn't a valid int
}
int num = sc.nextInt();
System.out.println("Thank you! I received " + num);
That's all you have to write, and thanks to hasNextInt() you won't have to worry about any Integer.parseInt and NumberFormatException at all.
See also
Java Tutorials/Essential Classes/Basic I/O/Scanning and Formatting
Related questions
How do I keep a scanner from throwing exceptions when the wrong type is entered? (java)
How to use Scanner to accept only valid int as input
Other examples
A Scanner can use as its source, among other things, a java.io.File, or a plain String.
Here's an example of using Scanner to tokenize a String and parse into numbers all at once:
Scanner sc = new Scanner("1,2,3,4").useDelimiter(",");
int sum = 0;
while (sc.hasNextInt()) {
sum += sc.nextInt();
}
System.out.println("Sum is " + sum); // prints "Sum is 10"
Here's a slightly more advanced use, using regular expressions:
Scanner sc = new Scanner("OhMyGoodnessHowAreYou?").useDelimiter("(?=[A-Z])");
while (sc.hasNext()) {
System.out.println(sc.next());
} // prints "Oh", "My", "Goodness", "How", "Are", "You?"
As you can see, Scanner is quite powerful! You should prefer it to StringTokenizer, which is now a legacy class.
See also
Java Tutorials/Essential Classes/Regular expressions
regular-expressions.info/Tutorial
Related questions
Scanner vs. StringTokenizer vs. String.Split
you mean input from user
Scanner s = new Scanner(System.in);
System.out.print("Enter a number: ");
int number = s.nextInt();
//process the number
If you are talking about those parameters from the console input, or any other String parameters, use static Integer#parseInt() method to transform them to Integer.

Categories