Cannot declare global, static Scanner object without throwing FileNotFoundException? - java

Basically, I am running a few tests for a simple CLI game I am making, and initially all of my variables/objects were declared at the beginning of the main() method. I now have to create a new method that uses some of the same objects/variables, so I decided to move all of my variables out of main() and make them static/global. In doing so, I've run into a problem: despite main() throwing FileNotFoundException, I was getting the following error message:
Tests.java:14: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
static Scanner boardReader = new Scanner(board);
Here was my code, up to the problematic line:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;
class Tests {
// GAME OBJECTS AND VARIABLES
// The following is used for reading, displaying, and writing to the game board.
static File board = new File("Board.txt");
static Scanner boardReader = new Scanner(board);
static FileWriter boardWriter = null;
static StringBuilder boardBuilder = new StringBuilder((int)board.length());
static String boardDisplay = null; // This String allows boardContents to print in a more readable way.
static String boardContents = null; // This is Board.txt represented as a String.
// There are more variables here than shown, but these are the ones relevant to my problem.
// GAMEPLAY
public static void main(String[] args) throws FileNotFoundException, IOException {
boolean gameIsOngoing = true;
while(gameIsOngoing) {
// boardContents String from boardBuilder StringBuilder
while (boardReader.hasNextLine()) {
boardContents = (boardBuilder.append(boardReader.nextLine() + System.lineSeparator()).toString());
}
// More irrelevant code here.
}
}
}
In trying to fix the problem, I tried to put the code utilizing boardReader inside a proper try-catch as shown here:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;
class Tests {
// GAME OBJECTS AND VARIABLES
// The following is used for reading, displaying, and writing to the game board.
static File board = new File("Board.txt");
static FileWriter boardWriter = null;
static StringBuilder boardBuilder = new StringBuilder((int)board.length());
static String boardDisplay = null; // This String allows boardContents to print in a more readable way.
static String boardContents = null; // This is Board.txt represented as a String.
// There are more variables here than shown, but these are the ones relevant to my problem.
// GAMEPLAY
public static void main(String[] args) throws IOException {
boolean gameIsOngoing = true;
while(gameIsOngoing) {
// boardContents String from boardBuilder StringBuilder
try (Scanner boardReader = new Scanner(board)) {
while (boardReader.hasNextLine()) {
boardContents = (boardBuilder.append(boardReader.nextLine() + System.lineSeparator()).toString());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// More irrelevant code here.
}
}
}
Which works, but it makes my code feel less readable, as the Scanner object is no longer listed with all of the other objects. I guess my question is, why didn't the first code work? Is it possible for something resembling it more to work?
I also want to mention quick that in researching for this question, I saw some things saying it is generally bad practice to have Scanner objects be global/static. I figured that because this particular Scanner isn't gathering user input (and me having no plans on maintaining this relatively simple project post-completion), it wouldn't be too problematic.
Edit: I don't know why but the editor isn't letting me put a "Hello" at the beginning of this post, so here it is... hello everyone :)

There is error because the exception is not caught. The Scanner instance is created in context of the Tests class, main method is something different, therefore catching it there won't solve the issue.
If you want a work-around, you can try something like this:
static {
try {
boardReader = new Scanner(board);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}

Related

School Java Escape Room Program

I am writing an escape room project for school which has messages such as a greeting, a win message, a loss message, etc. I stored these messages in a text file and then I read the file and store each line into one ArrayList and to access each line by their respective getter method and I use the .get function with their index value. I'm wondering if there is a way to avoid hardcoding the index numbers and on top of that is there a way I can just read the file when the program is run instead of having to make an instance of the class and then for example doing foo.readFile();
import java.io.File;
import java.util.Scanner;
import java.io.FileNotFoundException;
import java.util.ArrayList;
//package Stage;
public class EscapeRoom{
ArrayList<String> Messages;
String fileName;
private boolean win = false;
public void readFile() throws FileNotFoundException {
Messages = new ArrayList<String>();
fileName = "test.txt";
File file = new File(fileName);
Scanner scanner = new Scanner(file);
while(scanner.hasNextLine()){
Messages.add(scanner.nextLine());
}
scanner.close();
}
public void showGreeting(){
System.out.println(Messages.get(0));
}
public void showDirections(){
System.out.println(Messages.get(1));
}
public void showWin() {
System.out.println(Messages.get(2));
}
public void showLoss() {
System.out.println(Messages.get(3));
}
}
This is exactly what a properties file is for. Here is a file I named prompts.properties:
greeting = "hello, welcome to my game"
win = "you win, yay"
loss = "sorry bro, you lose"
directions = "escape with your life!"
Here is your modified program:
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
public class EscapeRoom {
Properties prompts = null;
public void readFile() throws IOException {
prompts = new Properties();
prompts.load(new FileInputStream("prompts.properties"));
}
public void showGreeting() {
System.out.println(prompts.get("greeting"));
}
public void showDirections() {
System.out.println(prompts.get("directions"));
}
public void showWin() {
System.out.println(prompts.get("win"));
}
public void showLoss() {
System.out.println(prompts.get("loss"));
}
}
Basically to get a named key-value pair you want something like a map. Properties are really a special sort of map that understands a file of records that have the format <key> = <value>.
Here is the documentation on Properties and if you decide to roll your own you would implement the same basic thing with a Map.

While loop gives me an "<identifier expected>" error

The goal is to fill an ArrayList with custom Country objects made up of information from a separate text file. The while loop gives me the "identifier expected" error, and I'm at my wit's end trying to fix it.
import java.util.Scanner;
import java.util.ArrayList;
import java.io.File;
import java.io.FileNotFoundException;
public class Driver {
public static void main(String[] args) {
//Instance variables
Scanner sc;
Country next = new Country();
String reader;
int size;
ArrayList<Country> ledger = new ArrayList<Country>();
//Suppressing this exception because I know it's there.
#SuppressWarnings("unreported exception FileNotFoundException; must be caught or declared to be thrown")
sc = new Scanner(new File("testLedger.txt"));
//"<identifier> expected" error
while (sc.hasNext()) {
next.setName(sc.nextLine());
next.setFaith(sc.nextLine());
next.setInfo(sc.nextLine());
next.setOrder(sc.nextInt());
ledger.add(next);
}
//Test accessor methods and filling of the ArrayList
for (int i = 0; i < ledger.size(); i++) {
System.out.println(ledger.get(i));
}
}
}
First, your code will not compile. You need to handle the exceptions. As in this case you are just running a test, you can use a Throw in the main method.
try {
sc = new Scanner(new File("testes.txt"));
while (sc.hasNext()) {
next.setName(sc.nextLine());
next.setFaith(sc.nextLine());
next.setInfo(sc.nextLine());
next.setOrder(sc.nextInt());
ledger.add(next);
}
} catch (FileNotFoundException e) {
System.out.println(e);
}
Second, look at the setters of your Country class and see if the method types are compatible with what you are using in the while.
For example:
sc.nextLine () // will return a String
sc.nextInt () // will return an int
your setters should be compatible with this
public void setOrder(int order){
this.order = order;
}
and Finally, as mentioned by #Dawood in comments, you need do see stackoverflow.com/q/13102045

Unreported IOException error, but has "throws Exception" and Try and Catch is within method

I created a Util class that returns an array that is based on a file. When I try to instantiate this array object in the Statistics class, I get this error:
error: unreported exception IOException; must be caught or declared to be thrown
I have both a throws IOException and try and catch. A similar stack overflow question was solved by placing the try and catch inside of the action method, but mine seems to have that already.
Any help would be much appreciated.
Util:
import java.io.*;
import java.util.*;
import java.lang.*;
public class Util {
public static Student[] readFile(String fileName) throws IOException {
Student studentArray[]=new Student[15];
try{
FileReader file = new FileReader("studentData.txt");
BufferedReader buff = new BufferedReader(file);
String line;
line = buff.readLine();
int index=0;
while(line != null){
System.out.println(line);
if(index>14){
break;
}
line = buff.readLine();
String[] result = line.split("\\s");
int sid = Integer.parseInt(result[0]);
int scores[] = new int[5];
for(int x=1;x<result.length;x++){
scores[x-1] = Integer.parseInt(result[x]);
}
Student myCSC20Student = new Student(sid, scores);
studentArray[index++] = myCSC20Student;
}
}
catch (IOException e){
System.out.println("Error: " + e.toString());
}
return studentArray;
}
}
Statistics:
import java.io.*;
import java.util.*;
public class Statistics {
final int LABS = 5;
public int[] lowscores = new int[LABS];
private int[] highscores = new int[LABS];
private float[] avgscores = new float[LABS];
public static void main(String args[]) {
Student[] studArr = Util.readFile("studentData.txt") ;
System.out.println(studArr[1]);
}
void calculateLow(Student[] a){
}
void calculateHigh(Student[] a){
}
void calculateAvg(Student[] a){
}
}
You've marked readFile as throwing IOException, so anywhere you use that method, you need to wrap it in a try-catch block.
With your current code, I would suggest removing the throws portion of the method, because you're catching it anyway. What I suggest you do is remove the try-catch in the method and leave that to the callers. I recommend this because it makes it simpler to catch errors as opposed to the returned array just being empty.
readFile() declares IOException. This means that anywhere it's called, must also declare IOException, or catch it. In this case, readFile() does not need to declare IOException because it's caught within the method.
However, a larger issue is that you're calling an IO oriented method in class initialization. This makes it very difficult to deal with actual exceptions sanely. At the very least, your readFile() should return null or an empty array in the event of an exception.
In short, don't declare IOException on readFile().
You have already added try catch block in Util class so no need to throws the IOException. Remove throws clause from readFile method in Util class.

Package that calls different classes when given input to?

I have taken all of my classes from my intro to java college in highschool class, and put them into a package called gameChoices. I then made a class that would call these classes when the user asks for them, this is called whichGame. I've imported the classes I want called using import gameChoices."whatever game it is";. How do I call these classes in whichGame? I also have them all as public static main(string [] args), which ones shouldn't have that(I think it's just whichGame that should..)? And what would I put instead? Thanks for helping a newbie out :)
The simplest way to do it is probably to set up a big if/then statement.
if(input.equals("t"))
thisOne.start();
else if(input.equals("a"))
anotherOne.start();
else if(input.equals("y"))
yetAnotherOne.start();
And so on. Might be a pain if you have a lot of classes, or if they start with the same letter.
Not sure exactly what you want to achieve, but if you need to access a class by its name you can try Class.forName() and check for exceptions thrown (particularly, ClassNotFoundException).
Using case-insensitive String equality for the name check, if would allow you to access any existing class of your ClassLoader through reflection.
Edit
Here's your main class:
package test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public class Main {
// initializes your map of letter->game class
private static final Map<String, Class<?>> GAMES = new HashMap<String, Class<?>>();
// constant name of main method for your games
private static final String MAIN_METHOD_NAME = "main";
// add your games
static {
GAMES.put("c", Chess.class);
GAMES.put("d", Doom.class);
// TODO moar gamez
}
public static void main(String[] args) {
try {
// prompts the user
System.out.println("Enter the game's name or starting letter: ");
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)
);
// gets the response
String input = br.readLine();
br.close();
// iterates over your games' first letters
for (String gameName : GAMES.keySet()) {
// the input starts with one game's first letter...
if (gameName.startsWith(input.toLowerCase())) {
// gets the class
GAMES.get(gameName)
// gets its main method (typical signature is String[] args)
.getMethod(MAIN_METHOD_NAME, String[].class)
// invokes its main method with no arguments
.invoke((Object) null, (Object) null);
}
}
// handles any disaster
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Now here are two "game" classes:
package test;
public class Chess {
public static void main(String[] args) {
System.out.println("You've chosen Chess!");
}
}
... and...
package test;
public class Doom {
public static void main(String[] args) {
System.out.println("You've chosen Doom!");
}
}
Now set your "Main" class as your... main class.
When you launch the application, it will query you for an initial letter.
If you choose "c" or "d", it will print out: "You've chosen [Chess/Doom]!"
I hope this helps you getting started.

I am having an "Illegal start of expression" error with user imput

I am trying to get user input, however I am getting
illegal start of expression at:
public static String askTheUser() throws IOException
Complete code:
Edit: I have made most of the changes you guys suggested so now I have this:
import java.io.BufferedReader;
public class Driver
{
public static void main(String[]args)
{
Dice dice;
Craps craps;
userResponse = askTheUser();
while(userResponse.equalsIgnoreCase("yes"))
{
craps = new Craps();
while(!craps.gameOver())
{
craps.roll();
//print out results of roll
}
//print out game results: if(craps.gameWon()...
userResponse.askTheUser();
}
}
public static String askTheUser() throws IOException
{
BufferedReader dataIn = new BufferedReader( new InputStreamReader(System.in) );
String data;
System.out.print("Want to play craps? Yes or No");
data = dataIn.readLine();
if(data.equals("y") || data.equals("yes"))
{
return "yes";
}
else
{
return "no";
}
}
}
However I am still getting cannot find symbol at public static String askTheUser() throws IOException. So might I be missing an import that I don't know of?
you declared askTheUser method inside main method. rip it out off the main method.
public static void main(String[]args)
{
//code that goes inside main
}
public static String askTheUser() throws IOException
{
// code that goes in askTheUser
}
and i don't think that keyboard.readline() works?
use:
InputStreamReader converter = new InputStreamReader(System.in);
BufferedReader in = new BufferedReader(converter);
in.readLine(); // Convert to string or int needed!
You can't write method inside method in Java.
But you can have many methods in the same class.
Why? Because of Java specifications.. you are simply not allowed to do so.
Note that you can have an anonymous inner class with methods under another method.

Categories