This Question now has a follow-up question
After learning a lot about applying OO principles, interfaces and a bit about argument-handling I post a revised version of my previous code. This is still an exercise for me to improve my general coding for a simple program. As such I would like to ask to pay special attention towards the application of OO programming principles and Exception handling, because those are the areas I feel weakest at.
The code is tested and - just like before - works properly.
Here a quote of the still relevant sections of the previous question:
The task itself is to go through a large .txt file that contains lines with ">" as their first character and to remove all spaces in these lines. I am using this program to modify files in FASTA format, a format often used in biology.
Algorithm:
- Read next line from input file and store in "line"
- If "line" contains ">" as first character, remove all spaces in "line"
- Print "line" to output file
- If next line is not null, go back to Step 1
Step 2 was changed from "If line contains ">" " to "If Line contains ">" as first character", since that reduces the number of comparisons the if-statement has to make - I think.
Code structure
The code structure changed a lot compared to last time and is now a lot more complex, which is why it has its own section.
Argument parsing is no longer handled by ArgumentHandler, which was split into a class ArgumentCollection
- which does the argument parsing now - and a class ArgumentHandler
- which triggers the argument parsing and contains the code that slowy previously suggested putting into a createArgumentHandler()
method. ArgumentCollection
implements an interface ArgumentManager
that provides a bunch of method to manipulate, set and test arguments of the various flags. ArgumentHandler
now also implements an Interface Configuration
that provides the methods getSourceFile()
and getSinkFile()
that returns the files to read from/write to. For the sake of some semblance of brevity 'ArgumentCollection' is not shown (It has over 250 lines of code).
Besides Configuration
, the Client also works with the classes 'FileLineReader' , and 'FileLineWriter' (both implementing AutoCloseable
) , which have the methods readLine()
/writeLine()
.
The Client
public interface Configuration {
/**
* Returns the name and path of a file to read from in form of a String.
*/
String getSourceFile();
/**
* Returns the name and path of a file to write to in form of a String.
*/
String getSinkFile();
/** Prints all arguments */
void printArguments();
}
public class RemoveSpaces_Client {
private static void printProgramProgress(int i) {
if (i % 1000000 == 0) {
System.out.println(i / 1000000 + " * 10^6 lines written.");
}
}
public static void main(String[] args) {
Configuration arguments = new ArgumentHandler(args);
System.out.println("Starting Program with the following arguments: ");
arguments.printArguments();
try (FileLineReader inputReader = new FileLineReader(arguments.getSourceFile());
FileLineWriter outputWriter = new FileLineWriter(arguments.getSinkFile());) {
/*
* Write every line from input file to output file. If the line is a
* name (contains ">"), remove all spaces in it before writing.
*/
int i = 0;
for (String line = inputReader.readLine(); line != null; line = inputReader.readLine()) {
if (line.charAt(0) == '>') {
line = line.replace(" ", "");
}
outputWriter.writeLine(line);
printProgramProgress(++i);
}
} catch (IOException e) {
System.out.println("Reader or Writer caused an IOException!");
e.printStackTrace();
throw new UncheckedIOException(e);
}
System.out.println("Finished!");
}
}
FileLineReader
public class FileLineReader implements AutoCloseable {
private BufferedReader reader;
public FileLineReader(String filename) throws FileNotFoundException {
this.reader = new BufferedReader(new FileReader(filename));
}
public String readLine() throws IOException {
return reader.readLine();
}
public void close() throws IOException {
reader.close();
}
}
FileLineWriter
public class FileLineWriter implements AutoCloseable {
private Writer writer;
public FileLineWriter(String filename) throws IOException {
try {
this.writer = new BufferedWriter(new FileWriter(filename));
} catch (IOException e) {
System.out.println(
"Output file name " + filename + " was not accessible or could not be created. Printing to "
+ (filename + ".nospace.txt instead"));
this.writer = new BufferedWriter(new FileWriter(filename + ".nospace.txt"));
}
}
public void writeLine(String line) throws IOException {
this.writer.write(line);
this.writer.write(System.lineSeparator());
}
public void close() throws IOException {
this.writer.close();
}
}
ArgumentHandler
public class ArgumentHandler implements Configuration {
private ArgumentManager arguments;
ArgumentHandler(String[] args) {
/*
* Define all allowed Flags and their associated arguments in an
* ArgumentCollection. If possible, assign arguments their default
* values. "null" are arguments that must be specified through parsing
* of args or the program can't run. "" are arguments that are optional
* or whose default value depends on an argument whose value needs to be
* parsed.
*/
String[] argumentList = { "-i", null, "-o", "", "-h", "Text to display if -h is called" };
arguments = new ArgumentCollectionImplementation1(argumentList);
arguments.parseArguments(args);
/*
* If flag "-o" does not have an argument associated with it after
* argument parsing, set its argument to its default value.
*/
if (!arguments.flagHasArguments("-o")) {
arguments.setFlagArgument("-o", 0, arguments.getFlagStringArgument("-i") + ".nospace.txt");
}
}
public String getSourceFile() {
return arguments.getFlagStringArgument("-i");
}
public String getSinkFile() {
return arguments.getFlagStringArgument("-o");
}
public void printArguments() {
arguments.printArguments();
}
}
Final Comment
One major thing this definitely taught me - If you can avoid it, don't code easy tasks in java. This program totals over 300 lines of code (not counting comments and package/import statements) to do something, as Vogel612 pointed out, that you can do in 1 line in sed in a linux-terminal.