Closing a Java Scanner object made during constructor chaining - java

I'm using constructor chaining, and I'm worried that it's causing a resource leak. Here are my two constructors:
/**
* Constructor to build the map based off of a file. Redirects to the Scanner-based constructor
* #param fileName the name of the file to open
*/
public GeoMap(String fileName) throws FileNotFoundException {
this(new Scanner(new File(fileName)));
}
/**
* Constructor to build the map based off of a Scanner. (Probably from an open file.)
* #param scanner the Scanner to read
*/
public GeoMap(Scanner scanner) {
// goes on to read the string data and make an object...
It's important that the object be created from any type of Scanner (keyboard, file, etc.), though it'll usually be from a file. The problem is that I think there's a resource leak going on here. Whenever I'm reading a file, I like to close it when I'm done. Problem is, the constructor chaining means that the this() call must be the first line. I'd be inclined to do something like this:
this(Scanner scannerToClose = new Scanner(new File(fileName)));
In my mind that would give me the name of a Scanner I could then close out. But that seems to really confuse the compiler--I get about 5 compile-time errors out of it, including a lot of "cannot find symbol" problems that imply that the compiler's just not wired for this sort of thing. Does Java support this? Or do I need to make a totally different initFromScanner() function that both constructors call? (Not elegant.)
Thanks.

Call scanner.close() at the end of your GeoMap(Scanner scanner) constructor.
This will close the Scanner created in GeoMap(String filename) since a reference to it is passed into the GeoMap(Scanner scanner) as scanner.
In essence, the scanner variable points to the new scanner that was created, so calling scanner.close() anywhere, in any method, closes it for any and all other methods it may be in the scope of.
Here is a program which demonstrates the object oriented nature of Scanners:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Main
{
static class Test
{
String name;
public Test(String filename) throws FileNotFoundException
{
this(new Scanner(new File(filename)));
}
public Test(Scanner scanner)
{
name = scanner.nextLine();//body of constructor
scanner.close();
System.out.println("Your name is "+ name);
scanner.close();
/*These next lines of code show that the Scanner is closed */
String throwsException = scanner.nextLine();
System.out.println(throwsException + "here");//unreachable
}
}
public static void main(String[] args)
{
try
{
Test temp = new Test("input.txt");
}
catch(Exception e)
{
System.out.println(e);
}
}
}
input.txt:
Smitty
output:
Your name is Smitty
java.lang.IllegalStateException: Scanner closed
In essence it doesn't matter where the Scanner is created, if it is closed at any point, it is closed everywhere that it is in scope.

I assume that your issue is that you only want to close the involved scanner if you have created it in your constructor that takes fileName. I don't think there's anything wrong with your idea of having an init method that both of your constructors call. I don't think that's inelegant.
I think what I would do is create a third private constructor instead of an init method. It's really the same thing either way, although maybe at some point you'd want to be able to pass in a pre-built Scanner that you want closed at the end of the constructor call, in which case you could make this new constructor public so you could call it from the outside.
In either case, what I'd do is pass a boolean "closeScanner" parameter to the new constructor/method that indicates if the scanner should be closed or not. Here's my idea in code:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
class GeoMap {
/**
* Constructor to build the map based off of a file. Redirects to the Scanner-based constructor
*
* #param fileName the name of the file to open
*/
public GeoMap(String fileName) throws FileNotFoundException {
this(new Scanner(new File(fileName)), true);
}
/**
* Constructor to build the map based off of a Scanner. (Probably from an open file.)
*
* #param scanner the Scanner to read
*/
public GeoMap(Scanner scanner) {
this(scanner, false);
}
private GeoMap(Scanner scanner, boolean closeScanner) {
// goes on to read the string data and make an object...
if (closeScanner)
scanner.close();
}
}

Lets start with this:
public GeoMap(Scanner scanner) {
...
}
Is there a resource leak here? Well, it depends on where the responsibility for closing the Scanner lies.
If responsibility lies in the constructor, then we can plug the leak like this:
public GeoMap(Scanner scanner) {
try (Scanner s = scanner) {
// original body
}
}
This is the ideal solution, but it assumes that the effect lifetime of the Scanner is the constructor.
If it is the caller responsibility, then the caller needs to deal with leak prevention. That is doable ... but outside of the scope of this question.
If it is neither the constructor or the caller's responsibility, then you need to treat the GeoMap itself as a resource, with all that that entails.
Now we consider this:
public GeoMap(String fileName) throws FileNotFoundException {
this(new Scanner(new File(fileName)));
}
Firstly, does new Scanner(new File(fileName)) present a potential resource leak?
In theory, yes. The Scanner constructor could open a stream for the file, and then fail, leaving the stream open.
In practice, it is highly unlikely. If we ignore bugs in the class library, and application bugs like using unrecognized character set names, the only cause of a spontaneous failure of new Scanner that could leak a file descriptor, etc is if you got an OOME. But that is likely to trigger a full GC anyway.
So what happens after that?
The answer depends on the earlier answer of where the responsibility lies in the GeoMap(Scanner) constructor.
If the responsibility lies in that constructor, we know how to avoid the leak; see above.
Otherwise ... we have problem:
There are possible solutions, but they may involve changing the way that the Scanner is used.
There may also be leaks involving the use of the that constructor directly.
In summary, depending on how you specify and implement GeoMap(Scanner), the GeoMap(String) constructor can be implemented to be leak proof in practice.

First, your class GeoMap should define how it handles a scanner that is given to it in the constructor; usually, when it is allowed to create its own Scanner instances as in your sample, the policy is that the GeoMap instance can do whatever it wants with that scanner, including closing it – this means it owns it, and ownership is transferred in the respective constructor.
If this is not the case (it does not own the scanner), you either have to drop the GeoMap(String) constructor (because, when not the GeoMap instance owns it, who else do and takes care of it later?), or you have to come to a design similar to that below:
class GeoMap
{
private final Scanner m_Scanner;
private final boolean m_MayCloseScanner;
/**
* Creates a GeoMap from a file.
*
* #param fileName The name of the file to open.
*/
public GeoMap( String fileName ) throws FileNotFoundException
{
this( new Scanner( new File( fileName ) ), true );
} // GeoMap()
/**
* Creates a GeoMap from a Scanner instance.
*
* #param scanner The Scanner to read
*/
public GeoMap( Scanner scanner )
{
this( scanner, false );
} // GeoMap()
/**
* Internal constructor.
*
* #param scanner The scanner to read.
* #param mayClose true, if this instance of GeoMap may close the
* given Scanner instance, false otherwise.
*/
private GeoMap( Scanner scanner, boolean mayClose )
{
m_Scanner = scanner;
m_MayCloseScanner = mayClose;
} // GeoMap()
…
}
// class GeoMap
Here the ownership is tracked by the flag m_MayCloseScanner.
Unfortunately, this does not yet solve your issue with the resource leak: the scanner will still not be closed, when the GeoMap instance is no longer used.
When your GeoMap instance will not own the scanner at all, you don't care, the resources taken by the scanner are a POOP (a problem of other people).
Ok, when you will need the scanner only for the initialisation of the GeoMap instance, you can have an init() method that closes the scanner when done:
…
public void init()
{
// Do something with the scanner ...
…
// Close the scanner when done.
m_Scanner.close()
} // init()
…
Of course, when GeoMap may or may not own the scanner, the closing line needs to look like this: if( m_MayCloseScanner ) m_Scanner.close;.
But if that init option does not work, you need a destructor for GeoMap instances. The concept of a destructor does not exist in Java, the closest to it was to implement finalize(), but this was deprecated some time ago (finally with Java 9), with good reason.
Have a look to this post on how to use Cleaner, PhantomReference and Closeable for your GeoMap class. It looks a bit confusing in the beginning, but reveals to be relatively straight forward in the end.

Related

Beginner assistance with transferring information between classes

I am working on a homework assignment that takes input from a .csv file and will prompt the user for different questions pertaining to the information contained within (crime statistics).
My code is as follows and it's still really early so I just have some placeholder variables in there as I have been wracking my head trying to figure out the best approach to this problem.
import java.io.*;
public class USCrimeArray {
String crimeArray[][] = new String[21][20];
public void createCrimeArray() throws Exception{
String crimeArrayInputString;
int crimeArrayRowValue = -1;
try (BufferedReader crimeArrayInput = new BufferedReader(new FileReader("C:/Users/Joey/Documents/Crime.csv"))) {
while ((crimeArrayInputString = crimeArrayInput.readLine()) != null) {
crimeArrayRowValue++;
crimeArray[crimeArrayRowValue] = crimeArrayInputString.split(",");
}
} catch (IOException io) {
io.getMessage();
}
}
public USCrimeArray(){
String[][] thisArray = crimeArray.clone();
}
public String[][] getCrimeArray(){
return crimeArray.clone();
}
}
This is the code for my first class and if I do a deepToString inside of createCrimeArray I get the information back that I want. The constructor for USCrimeArray hasn't really been thought out yet my main question is how to write the information to the crimeArray[][] so that I can carry it back over to other classes.
Once again this test main hasn't been thought out too far because I am still struggling with why my method is not writing over the crimeArray[][] with the while loop and it is as follows:
import java.util.Arrays;
public class USCrimeClass {
public static void main(String[] args) {
USCrimeArray crimeArray = new USCrimeArray();
String[][] test = crimeArray.getCrimeArray();
System.out.println(Arrays.deepToString(test));
}
}
I know there's a lot I'm doing wrong here, but this is the end result so far after having altered everything over and over again and not making any progress. The result of the system out in this is obviously just a 21x20 array of null elements. Any help would be greatly appreciated.
You need to call createCrimeArray() in USCrimeClass
public class USCrimeClass {
public static void main(String[] args) {
USCrimeArray crimeArray = new USCrimeArray();
crimeArray.createCrimeArray();
String[][] test = crimeArray.getCrimeArray();
System.out.println(Arrays.deepToString(test));
}
}
Also,
in the constructor of USCrimeArray you are clonning the array into a local variable thisArray but never use it. this is redundant and can be safely removed.
in getCrimeArray() you are returning a clone of the array. this is not needed (unless you want to keep USCrimeArray immutable). you can just return the array itself
Instance variables
instance variables are non static class level variables (much like crimeArray).
One can consider instance variables as serving two purposes:
"details" of the problem domain of the class. For example Person class will have instance variables such as firstName and lastName that are details of one person.
"configuration" variables holding information related to the technological environment and not pertaining to the problem domain of the class. For example, one sometimes might find a class with a boolean deleted instance variable that signifies a "soft deleted" instance that is not to be presented to the user or included in calculations. the purpose behind this is to support undo of deletion.
so crimeArray is of category details of USCrimeArray. common best practice is to initialise instance variables in the class constructor, so by the time you finish creating a new instance, you have one that has full and valid details. So I would move all of the code of createCrimeArray() into the constructor.
If you need to modify an instance variable after it was initialised, then a "setter" method can be used. these have a standardized signature: public void setCrimeArray(crimeArray[][]). having a standardized signature allows your class to be used by frameworks and libraries that add functionality. For example, storing the data in a relational database, sending/recieving the data over the internet, etc.
Now, I see that the external input that is used to populate the array comes from a file. The way it is coded now, USCrimeArray can only read one specific file from predetermined file syatem location. a more flexible way would be for the class to receive the specification for external input as an argument:
public USCrimeArray(String filename) {
...
try (BufferedReader crimeArrayInput = new BufferedReader(new FileReader(filename))) {
...
}
now the same class can be used to process an array from different files.
now you can even make the file name an argument of the java program:
public class USCrimeClass {
public static void main(String[] args) {
USCrimeArray crimeArray = new USCrimeArray(arg[0]);
System.out.println(Arrays.deepToString(test));
}
}
now the same java program can process different files without need for recompile.

Cannot add new object to a set, values come from a file

I am trying to create a public instance method that takes no arguments and returns no values. It is required to get an input from a user to select a file, this part I have no issues with. The method needs to make use of the BufferReader and Scanner Objects. So that it can read the file selected. For each line that is read, a new object should be created and its instance variables set using the values found in the file.
That object that is created should then be added to a list. This is where I am having issues, it won't let me add the new object to the list. Below is my code:
public void readInEntrants()
{
String pathname = OUFileChooser.getFilename();
File aFile = new File(pathname);
Scanner bufferedScanner = null;
Set<Entrant> entrantSet = new HashSet<>();
try
{
String currentEntrantLine;
Scanner lineScanner;
bufferedScanner = new Scanner(new BufferedReader(new FileReader(aFile)));
while (bufferedScanner.hasNextLine())
{
currentEntrantLine = bufferedScanner.nextLine();
lineScanner = new Scanner(currentEntrantLine);
lineScanner.useDelimiter(" ");
currentEntrantLine = lineScanner.next();
entrantSet.add(new Entrant(currentEntrantLine)); // <----- Here is where I am having trouble. It won't let me add the new object to the class Entrant
}
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
finally
{
try
{
bufferedScanner.close();
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
}
return entrantSet;
}
I'm not sure what to do. Could anyone see what I am doing wrong?
Sorry for got to add that it is a compilation issue, it will not compile properly.
Use an IDE ,I bet you dont (otherwise it would mark compilation error immediatly with red -> you use return in void method ) and in this case you would see other errors.
(off: this would go to comment section however under 50reputation I am not allowed to do that. Stackoverflow should change this imo. )
First of all:
You marked function readInEntrants as public void so you can't use return inside.
You could either remove return entrantSet; instruction or change function definition to public Set<Entrant> readInEntrants.
Concerning problem you have:
Basing on comment you left on beatrice answer I think you have only parameterless constructor for 'Entrant' class, while you try to create it passing string as parameter.
new Entrant(currentEntrantLine)
What you need to do is define Entrant class constructor that accept String as it's argument. For example:
public Entrant(String dataToParse)
{
// here you parse data from string to entrant fields
}
On the side:
You use bufferedReader to read entire file line at once and that's ok, but then you define Scanner lineScanner to iterate through line elements and then use it only once.
This way for file... let's say:
One Two Three
Four Five Six
Your while loop would work like this:
Store "One Two Three" inside currentEntrantLine.
Create scanner that'll work on "One Two Three", and set it to use space as delimiter.
Use .next to "Finds and returns the next complete token" (see documentation) and then store value inside currentEntrantLine. This way contents of currentEntrantLine is "One". Not entire line.
In next iteration you would have scanner working on "Four Five Six" and "Four" as currentEntranceLine content.
It seems the constructor of entrant class does not have any argument. Pass String as an argument type in the constructor to set the String field inside the Entrant class .

designing classes for other developers to use in java

class CSVReader {
private List<String> output;
private InputStream input;
public CSVReader(InputStream input) {
this.input = input;
}
public void read() throws Exception{
//do something with the inputstream
// create output list.
}
public List<String> getOutput() {
return Collections.unmodifiableList(output);
}
I am trying to create a simple class which will be part of a library. I would like to create code that satisfies the following conditions:
handles all potential errors or wraps them into library errors and
throws them.
creates meaningful and complete object states (no incomplete object structures).
easy to utilize by developers using the library
Now, when I evaluated the code above, against the goals, I realized that I failed badly. A developer using this code would have to write something like this -
CSVReader reader = new CVSReader(new FileInputStream("test.csv");
reader.read();
read.getOutput();
I see the following issues straight away -
- developer has to call read first before getOutput. There is no way for him to know this intuitively and this is probably bad design.
So, I decided to fix the code and write something like this
public List<String> getOutput() throws IOException{
if(output==null)
read();
return Collections.unmodifiableList(output);
}
OR this
public List<String> getOutput() {
if(output==null)
throw new IncompleteStateException("invoke read before getoutput()");
return Collections.unmodifiableList(output);
}
OR this
public CSVReader(InputStream input) {
read(); //throw runtime exception
}
OR this
public List<String> read() throws IOException {
//read and create output list.
// return list
}
What is a good way to achieve my goals? Should the object state be always well defined? - there is never a state where "output" is not defined, so I should create the output as part of constructor? Or should the class ensure that a created instance is always valid, by calling "read" whenever it finds that "output" is not defined and just throw a runtime exception? What is a good approach/ best practice here?
I would make read() private and have getOutput() call it as an implementation detail. If the point of exposing read() is to lazy-load the file, you can do that with exposing getOutput only
public List<String> getOutput() {
if (output == null) {
try {
output = read();
} catch (IOException) {
//here you either wrap into your own exception and then declare it in the signature of getOutput, or just not catch it and make getOutput `throws IOException`
}
}
return Collections.unmodifiableList(output);
}
The advantage of this is that the interface of your class is very trivial: you give me an input (via constructor) I give you an output (via getOutput), no magic order of calls while preserving lazy-loading which is nice if the file is big.
Another advantage of removing read from the public API is that you can go from lazy-loading to eager-loading and viceversa without affecting your clients. If you expose read you have to account for it being called in all possible states of your object (before it's loaded, while it's already running, after it already loaded). In short, always expose the least possible
So to address your specific questions:
Yes, the object state should always be well-defined. Your point of not knowing that an external call on read by the client class is needed is indeed a design smell
Yes, you could call read in the constructor and eagerly load everything upfront. Deciding to lazy-load or not is an implementation detail dependent on your context, it should not matter to a client of your class
Throwing an exception if read has not been called puts again the burden to calling things in the right, implicit order on the client, which is unnecessary due to your comment that output is never really undefined so the implementation itself can make the risk-free decision of when to call read
I would suggest you make your class as small as possible, dropping the getOutput() method all together.
The idea is to have a class that reads a CSV file and returns a list, representing the result. To achieve this, you can expose a single read() method, that will return a List<String>.
Something like:
public class CSVReader {
private final InputStream input;
public CSVReader(String filename) {
this.input = new FileInputStream(filename);
}
public List<String> read() {
// perform the actual reading here
}
}
You have a well defined class, a small interface to maintain and the instances of CSVReader are immutable.
Have getOutput check if it is null (or out of date) and load it in automatically if it is. This allows for a user of your class to not have to care about internal state of the class's file management.
However, you may also want to expose a read function so that the user can chose to load in the file when it is convenient. If you make the class for a concurrent environment, I would recommend doing so.
The first approach takes away some flexibility from the API: before the change the user could call read() in a context where an exception is expected, and then call getOutput() exception-free as many times as he pleases. Your change forces the user to catch a checked exception in contexts where it wasn't necessary before.
The second approach is how it should have been done in the first place: since calling read() is a prerequisite of calling getOutput(), it is a responsibility of your class to "catch" your users when they "forget" to make a call to read().
The third approach hides IOException, which may be a legitimate exception to catch. There is no way to let the user know if the exception is going to be thrown or not, which is a bad practice when designing runtime exceptions.
The root cause of your problem is that the class has two orthogonal responsibilities:
Reading a CSV, and
Storing the result of a read for later use.
If you separate these two responsibilities from each other, you would end up with a cleaner design, in which the users would have no confusion over what they must call, and in what order:
interface CSVData {
List<String> getOutput();
}
class CSVReader {
public static CSVData read(InputStream input) throws IOException {
...
}
}
You could combine the two into a single class with a factory method:
class CSVData {
private CSVData() { // No user instantiation
}
// Getting data is exception-free
public List<String> getOutput() {
...
}
// Creating instances requires a factory call
public static CSVData read(InputStream input) throws IOException {
...
}
}

Compare files string by string

I have two files:
Grader.getFileInfo("data\\studentSubmissionA.txt");
Grader.teacherFiles("data\\TeacherListA.txt");
Both contain a list of math problems, but the TeacherList is unsolved in order to check that the StudentSubmission was not altered from the original version.
studentSubmission is sent to the Grader class and the method currently looks like this:
public static void getFileInfo(String fileName)
throws FileNotFoundException {
Scanner in = new Scanner(new File(fileName))
while (in.hasNext()) {
String fileContent = in.nextLine();
}
and the TeacherFiles method looks like
public static void teacherFiles(String teacherFiles)
throws FileNotFoundException{
Scanner in = new Scanner(new File(teacherFiles));
while (in.hasNext()){
String teacherContent = in.nextLine();
String line = teacherContent.substring(0, teacherContent.indexOf('='));
}
I don't know how to get these methods to another method in order to compare them since they're coming from a file and I have to put something in the method signature to pass them and it doesn't work.
I tried putting them in one method, but that was a bust as well.
I don't know where to go from here.
And unfortunately, I can't use try/catches or arrays.
Is it possible to send the .substring(0 , .indexof('=')) through the methods?
Like line = teacherFiles(teacherContent.substring(0 , .indexof('='))); Is it possible to do this?
Think in more general terms. Observe that your methods called getFileInfo and teacherFiles, respectively are the very same except a few nuances. So why do not we think about finding the optimal way of merging the two functionalities and handling the nuances outside of them?
It is logical that you cannot use arrays as you need to know the number of elements of your array before you initialize it and your array would have already been initialized when you read the file. So using an array for this task is either an overkill (for example you allocate 1000 elements in your memory and you use only 10 elements) or insufficient (if you create an array of 10 elements, but you would need 1000). So, due to the fact that you do not know the number of rows in advance you need to use another data structure for your task.
So create the following method:
public static AbstractList<String> readFile(String filePath) throws FileNotFoundException, IOException {
Scanner s = new Scanner(new File(filePath));
AbstractList<String> list = new ArrayList<String>();
while (s.hasNext()){
list.add(s.next());
}
s.close();
return list;
}
Then use the method to read the student file and to read the teacher file. Store the results into two separate AbstractList<String> variables, then iterate through them and compare them as you like. Again, think in more general terms.

Picking up from where I left off when reading a file in Java

I am trying to read info from a file and create objects out of that information. Every 6 or so lines of the file is a different unit, meaning that the first set of lines are relevant to object A, the next set to object B, and so on.
I can read from the file and create my object just fine--for the first set. My problem is that I don't know how to get the reader to pick up from the spot it left off at when creating the next object...
(Note: the read() method which creates the file is part of the new object being created, not in a main() or anything like that). Here are the relevant bits of code:
The driver:
public class CSD{
public static void main (String[] argv){
Vector V=new Vector(10);
CoS jon=new CoS();
jon.display();
}//end main
}
which calls CoS, whose constructor is:
public CoS(){
try{
String fileName=getFileName();
FileReader freader=new FileReader(fileName);
BufferedReader inputFile=new BufferedReader(freader);
this.read(inputFile);
setDegree(major);
setStatus(credits);
} catch(FileNotFoundException ex){
}//end catch
}
Which calls both read() and getFileName():
public void read(BufferedReader inputFile){
try{
int n;
super.read(inputFile);
String str=inputFile.readLine();
if (str!=null){
n=Integer.parseInt(str);
setCredits(n);
str=inputFile.readLine();
setMajor(str);
}//end if
}catch(IOException ex){}
}//end method
public String getFileName() {
Scanner scan = new Scanner(System.in);
String filename;
System.out.print("Enter the file name and path ==> ");
filename = scan.nextLine();
System.out.println("");
return filename;
}
Thanks in advance, guys!
Why not use ObjectInputStream and ObjectOutputStream? Or any kind of real serialization?
javadoc: http://docs.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html
example code: http://www.javadb.com/writing-objects-to-file-with-objectoutputstream
Basically, since you write your objects to a file and want to take care of the lines where they are located, I'll suggest a few other serialization alternatives.
One is the Object * Stream - you create a ObjectStream on a File and just write objects thru it. Later when you read, you read the objects in the reverse order you wrote them and they will come back just as you wrote them.
Another is to implement Serializable. Remember that transient keyword? Use it on fields you do not want to save to the file.
And then there's the raw "by hand" approach where you save only the things you want to save and reconstruct the objects later by passing these initialization values to their constructor. Kinda like people suggested that you make the file line a argument to the ctor :)
EDIT:
guess writing with Object*Streams requires you to implement Serializable or Externalizable.
but if the example code isn't clear enough, ask :)

Categories