Is this bad practice for passing an input file in Java? - java

I have a main class that expects an input file name to be provided through the command line argument; if this is not true then the program exits with an error message.
We are assuming the existence of a class called SudokuReducer. After making sure there is an input file, the main function will pass the input file (not just the name of the file) to an instance of SudokuReducer.
What I want to know, is this bad form/practice? Is it wrong to put the entirety of the scan inside a try/catch like this? Because then if I wanted to declare the SudokuReducer instance in 'main' outside of the try/catch instead of in, I can't since it doesn't recognize what 'fileInput' has been passed due to its limited scope inside the 'try'
Is there a better way of doing this? Here's what I have:
import java.io.File;
public class MainMV {
File inputFile;
public static void main(String args[]) {
// check if file is entered and handle exception
try {
if (args.length > 0) {
File inputFile = new File(args[0]);
System.out.println("Processing file");
SudokuReducer reducer = new SudokuReducer(inputFile);
} else {
System.out.println("No file entered.");
System.exit(1);
}
} catch (Exception e) {
System.out.println("File failed to open.");
System.exit(1);
}
}
}

To answer the question in the title: no, it's not bad practice, if that method needs a File to do its work.
Another option would be passing a String; and that's a poor choice, because it doesn't convey that the parameter is supposed to represent a File of some sort.
Perhaps a better option would be to pass in an InputStream to the method, since a) that clearly conveys that it's going to be used for input (as opposed to being a File that you will write to); b) it's more flexible, because it doesn't have to refer to a file on disk.
To answer the question in the question: no, it's not really good practice to wrap everything in one try/catch like this. It makes it hard to distinguish the modes of failure: many different things could go wrong in your code, and it's better to handle those things separately, e.g. to provide specific failure messages.
A better way to structure the code is something like this:
if (args.length == 0) {
System.out.println("No file entered.");
System.exit(1);
}
File inputFile = new File(args[0]);
System.out.println("Processing file");
try {
SudokuReducer reducer = new SudokuReducer(inputFile);
// Do something with reducer.
} catch (IOException e) {
e.printStackTrace();
System.out.println("File failed to open.");
System.exit(1);
}
Note that this has small blocks, handling specific errors, rather than a great big block where the error handling is separated from the thing causing the error.
Also, note that it's not catching Exception: you really don't want to do that unless you have to, because you're not correctly handling exceptions that it would catch that have to be handled in special ways (i.e. InterruptedException). Catch the most specific exception type you can.

From my understanding, Java passes parameters as a reference of the object by value which for me was terribly confusing.
Link to explanation of Pass by Reference vs Pass by Value.
Link to explanation of the Java implementation
Depending on how much information from the file is required to generate an instance of your SudokuReducer class, the overhead of this could be significant. If this is the case, you'll want to parse your input line by line doing
something like this in your main method.
try {
SudokuReducer reducer = SudokuReducer.makeSudokuReducer(args[0])
}
catch(Exception e) {
System.out.println("No file entered.");
System.exit(1);
}
Here's an example of reading a file line by line
There are many ways to do this, but the most efficient way I can think of is by using Java 8's Stream and Files classes.
The method signature will look something like this:
public static SudokuReducer makeSudokuReducer(String filename) {
//Open file
//Parse input line by line
//Use information to create a new instance of your class
//Return the instance of this class
}
You'll be able to call this static method anywhere to produce a new instance of your class from a filename.

Related

Looking for an explanation regarding file.delete() method in try catch block

Trying to make a simple 'cut' program to move files across folders.
After it makes a copy it should delete the source file but it ignores the fileLocation.delete(); method in the try block. If I put it in the 'finally' block it works and also anywhere else in the program after it goes through copying the file but that makes no sense for it to work that way, even if something goes wrong the source will be deleted. My question is why does it ignore it, I was unable to find answers online. Thank you.
File fileLocation = new File("C:\\fileLocation\\picture.png");
File fileDestination = new File("C:\\fileDestination\\picture.png");
try(FileInputStream input = new FileInputStream(fileLocation);
FileOutputStream output = new FileOutputStream(fileDestination)) {
byte[] buffer = new byte[1024];
int length;
while((length = input.read(buffer)) > 0) {
output.write(buffer,0, length);
}
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}
try(FileInputStream input = new FileInputStream(fileLocation);
... ) {
// ..
fileLocation.delete();
}
At this point, input is still open, so you can't delete the file it refers to.
According to the definition of try-with-resources in the language spec, a finally block on a try-with-resources statement will be executed after the resource is closed. As such, putting the delete in the finally block means it can succeed.
Rather than putting it in the finally (which occurs whether or not an exception is thrown), you can split up the resources into two try-with-resources blocks, and delete once you're done with input:
try (FileOutputStream output = ...) {
try (FileInputStream input = new FileInputStream(fileLocation)) {
// ..
}
// input is now closed.
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}
Now, fileLocation is only deleted when no IOException is thrown from any preceding statement in the output try-with-resources block (including the input try-with-resources block).
Or, if you want not to delete it until output is closed: move the IOException catch into a surrounding try/catch (not try-with-resources) block:
try {
try (FileOutputStream output = ...;
FileInputStream input = ...) {
// ..
}
// input and output are now both closed.
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}
Of course, a better way to move a file would be to use the utility method to move files, e.g.
Files.move(fileLocation.toPath(), fileDestination.toPath(), CopyOption.REPLACE_EXISTING);
You're using the wrong API. File.delete() is known-bad API design.
This is what's bad about it, and why it explains your confusion: Unlike just about any other API, if delete() fails to delete, it does not throw any exceptions. Instead, it returns false. This is bad in 3 important ways:
It's un-java-like. Very few APIs do that; the vast majority of them throw something instead.
It is easy to 'forget'. Just writing x.foo(); on its own, where foo() is any method that returns something (i.e. has a non-void return type), is perfectly fine java. it's java-ese for: Run this method, then take the result and toss it in the garbage. You've done that here: Call delete() and ignore the result. For delete(), that's not actually okay unless you intended to write code that effectively means: "try to delete this path. Whether it succeeds or not, continue with the code". Which, usually, isn't what you want.
If something does go wrong, it is not possible for the delete() method to tell you any details other than 'I could not accomplish it'. No way to have a message or some sort of exception type to clear things up for you.
The solution is simple. Stop using this method. Put it on the banlist: This method should no longer ever be invoked in java code. If you are maintaining some 15 year old stuff, it's fine, I guess, but a quick refactor to get rid of it wouldn't go amiss.
Great! So what's the new one I should be using?
The path/files API in the java.nio.file package.
Replace:
File f = new File("a/b/c.txt");
f.delete();
with:
Path p = Paths.get("a/b/c.txt");
Files.delete(p);
Unlike file.delete(), Files.delete(path) WILL throw an exception if the deletion cannot be performed. This exception then contains suitable information about why. For example, because the file doesn't exist, or because you do not have write access to the underlying directory, or because the file system is mounted read only, etcetera.
The new File API is also vastly more capable. It can properly handle links or alternate file systems, for example. It also has more methods. For example, it has the Files.move method which may be of particular use here.
Just for reference, why is my delete operation failing?
Probably because your own process still has the file open. On some OS/filesystem combos (in particular, on windows and e.g. NTFS), you can't delete open files. Even if your own process is the one that still has the file open.
If you use Files.delete() you'll get an exception with a message that'll get you a lot closer to that conclusion than 'the delete() call returned false', fortunately.

I want to read contains methods, in a .java file as below,

As an example, I have a .Java file like this,
public class A {
private void callData() {
//There can be custom methods like this
checkImage("A",true);
checkObject("B","C",true);
}
}
I want to read this methods name and parameters. I dont need to go inside those methods and take the values but I want to take the name and parameters. This A.java is a file located in my machine. Now I want to write a code to read this method names and parameters. I think this is clear :)
Thank you
Most questions should contain where possible a minimal example of things you have already tried as it helps us answers the question more efficiently in the problem you are having with your code. Anyway for picking out method headers and parameters you should probably be looking into using a regex if you dont want a more fully complete solution for code parsing:
Firstly read your file in, you can see examples for different version of java here from #Grimy:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public String readFile(String filename)
{
String content = null;
File file = new File(filename); //for ex foo.txt
FileReader reader = null;
try {
reader = new FileReader(file);
reader.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(reader !=null){reader.close();}
}
return content;
}
Then theres a number of solutions for a possible regex you could use here and here
(?:(?:public)|(?:private)|(?:static)|(?:protected)\s+)*
Once you have designed a regex you could use any of the normal ways to group the matches and output what you need from the matches.
Its worth mentioning for this type of program solutions such as ANTLR can be useful (but overkill, thenless you are looking to extend beyond just method headers) as they can generate an entire parser for you to use.

Splitting a text file

I have this text file of the format:
Token:A1
sometext
Token:A2
sometext
Token:A3
I want to split this file into multiple files, such that
File 1 contains
A1
sometext
File 2 contains
A2
sometext
I do not have much idea about any programming or scripting language as such, what would be the best way to go about the process? I was thinking of using Java to solve the problem.
if you want to use java, I would look into using Scanner in conjunction with File and PrintWriter with a for loop and some exception handling you will be good to go.
import the proper libraries!
import java.io.*;
import java.util.*;
declare the class of course
public class someClass{
public static void main(String [] args){
now here's where stuff starts to get interesting. We use the class File to create a new file that has the name of the file to be read passed as a parameter. You can put whatever you want there whether its a path to the file or just the file name if its in the same directory as your code.
File currentFile = new File("new.txt");
if (currentFile.exists() && currentFile.canRead()){
try{
next we create a scanner to scan through that newly created File object. the for loop continues on as long as the file has new tokens to scan through. .hasNext() returns true only if the input in the scanner has another token. PrintWriter writes and creates the files. I have it set that it will create the files based on the iteration of the loop (0,1,2,3 etc) but that can be easily changed. (see new PrintWriter(i + ".txt". UTF-8); )
Scanner textContents = new Scanner(currentFile);
for(int i = 0; textContents.hasNext(); i++){
PrintWriter writer = new PrintWriter(i + ".txt", "UTF-8");
writer.println(textContents.next());
writer.close();
}
these catch statements are super important! Your code wont even compile without them. If there is an error they will make sure your code doesn't crash. I left the inside of them empty so you can do what you see fit.
} catch (FileNotFoundException e) {
// do something
}
catch (UnsupportedEncodingException i){
//do something
}
}
}
}
and thats pretty much it! if you have any questions be sure to comment!
There is no best way and it depends on your environment and need actually. But for any language figure out your basic algorithm and try using the best available data structure(s). If you are using Java, consider using guava splitter and do look into its implementation.

Java PrintWriter: Why do we handle FileNotFoundException if the file is automatically created if not found?

In the following SSCCE, I do not get a FileNotFoundException even if I delete this file from the given location/path i.e. "D:\\Eclipse Workspaces\\SAMPLES AND OTHER SNIPPETS\\SoapCallResults.txt"
Rather the PrintWriter seems to create the file if it is not found.
If the Printwriter creates the file if it is not found, why do we try to handle the FileNotFoundException (compiler complains if we don't surround it with try/catch or add a throws clause) when it is never going to be thrown?
package com.general_tests;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class PrintWriterFileNotFoundExceptionTest {
public static void main(String[] args) {
String myName = "What ever my name is!";
PrintWriter printWriter = null;
try {
printWriter = new PrintWriter("D:\\Eclipse Workspaces\\SAMPLES AND OTHER SNIPPETS\\SoapCallResults.txt");
printWriter.println(myName);
} catch (FileNotFoundException e) {
System.out.println("FILE NOT FOUND EXCEPTION!");
e.printStackTrace();
} finally {
if (printWriter != null) { printWriter.close(); }
}
}
}
FileNotFoundException is a checked exception, which simply translates that you will have to either catch it or add it in the throws clause.
I hope this answers your question about why we actually need it even though a file is created if not present-
From javadoc -
FileNotFoundException - If the given file object does not denote an existing, writable regular file and a new regular file of that name cannot be created, or if some other error occurs while opening or creating the file
Replace Eclipse Workspaces in your path with foo and see if you get the exception. The file itself may be created, but not the whole path above it.
You can also leave the path exactly as it is, but set read-only, hidden, and system attributes on the file. The OS will not be able to either write or create it.
Another variation: modify the file's ACL so your user doesn't have the write permission.
There are many more.
FIleNotFoundException is a checked exception. You need to handle these type of exceptions if your codeblock is throwing them. For unchecked type of exceptions, you don't have to handle (not mandatory). Can you really guarantee that the file is created, but not corrupted or the disk record isn't corrupted? Also, look into this - Java: checked vs unchecked exception explanation.
Main thing is that your constructor is throwing FileNotFoundException (look here - https://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#print%28char%29), which you have to catch (because it is checked).
Tips - For Eclipse, try and see what ctrl+SPACe reveals about an object's method. If your JavaDoc is in the right location, you will see all the explanation of what a method is doing including "Throws: SomeException" bit. This is what you need to look for when calling a method (i.e. whether you need try catch block for this).

java exception handling in constructor

honestly I'm not very experienced with exception handling, because often for my laziness I tend to not handle exceptions. So here's a very basic question.
I would like to know what's the cleanest way to accomplish this situation, with an exception handling approach:
I have a class (ConfigManager) that reads a file within its constructor, and need that file to exists to be constructed correctly, given as the constructor parameter.
If the file doesn't exist, I would like to catch the FileNotFoundException, create the file with some defaults values, and continue the creation of the ConfigManager object with the default config file now available.
Here's some code:
class ConfigManager{
ConfigManager(String file){
try{
builder = builderFactory.newDocumentBuilder();
document = builder.parse (new FileInputStream(file));
....
}catch (FileNotFoundException e) {
File configFile = new File (file);
try {
configFile.createNewFile();
BufferedWriter writer = new BufferedWriter(new FileWriter(configFile));
writer.write(this.defaultConfig);
writer.close();
return new ConfigManager(string); //Here's the problem. I can't do that but I need to try build ConfigManager again. How do that?
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
How to construct a new ConfigManager object, after the default config file has been created?
Is that the rigth way to handle such type of exception?
thanks in advance
What you can do is ensure the file exists before attempting to parse it.
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
} catch (FileNotFoundException e) {
BufferedWriter writer = new BufferedWriter(new FileWriter(configFile));
writer.write(defaultConfig);
writer.close();
fis = new FileInputStream(file);
}
try{
builder = builderFactory.newDocumentBuilder();
document = builder.parse (fis);
don't do the reading file in the constructor, create a method (possibly private) that does the reading of the file and setting of the values on the ConfigManager.
Then in the constructor, where you try to call the constructor again, just call the method.
i.e. dont call the constructor again.
update -- I would organize the code like this:
ConfigManager(String fileName) {
File file = new File(fileName);
if (!file.exists()){
// create this method -- Im assuming its ok to put the default
// config on the path where the file did not exist.
createDefaultConfigFile(fileName);
}
parseConfigFile(fileName, ...); // create this method too
}
this is obviously not working code, and I dont know specifically what you are doing so its as far as I can go. But its more readable than what you have now, and a bit more organized. Also, do you really want to create a new default config file if the specified one does not exist? Why not pop up a warning saying the config did not exist so you are using defaults, but not write the default file? You might have a reason to write the default, and if thats true then ok, but if you don't have to, don't add more work...
The solution is to partition your constructor into two parts. The first part tries to create the FileInputStream from the existing file. If it throws the FileNotFoundException, then you create and populate the file as above, and then open the FileInputStream again. The second part takes the file FileInputStream opened by the first part (regardless of how it was opened) and proceeds with initialization.
Another option is to defer this loading to an init() method, so that consumers of your class must both create and initialize their objects.
You need to be able to call the constructor again, but without creating a new object - just calling it on the same object. Since Java doesn't allow you to do that, you have to create an auxillary method, move the code from the constructor into that, and then call the new method from the constructor.
This is a basic technique for any situation where you need to implement recursion, but you can't directly recurse.
The cleanest way of accomplishing this is not to perform any operations that can result in exceptions in the constructor. If you absolutely need to perform them before your object can be used, do them in a separate method init().
Try delegating the parsing of the configuration file to another method. That way, you can check if the file exists first and then either create a default one, or pass the existing one to this new method.
Well, actually you have a new instance of ConfigManager after the constructor was executed without an error. So all you have to to is to just remove the line in question.
Or consider using a static initializer. This will check for the file only once, when your application is deployed/started.
often for my laziness I tend to not
handle exceptions
I suggest you fix the laziness first. In reality you are just creating more work for yourself further down the line.

Categories

Resources