patternjavaModerate
Text Analyzer - Properly implementing Java coding style
Viewed 0 times
properlytextjavastyleimplementingcodinganalyzer
Problem
As a new Java learner I would like to improve my coding style.
I wrote a program which gets as an input a file name, and asks for two file names for the output.
The first output file includes all the words from the input file with their number of occurrences.
The second output file includes the words in lexicographic order.
There is some code that is written twice, I think I can fix that by declaring a new method for this part of code, but I'm not sure how to do this properly.
```
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.io.*;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
public class TextAnalyzer {
private static HashMap wordCount = new HashMap();
public static StringBuffer stringBuffer;
public static void main(String[] args) throws IOException {
if (args.length == 0) {
System.out.println("Please specify input file as program argument");
return;
}
getWordsCount(args[0]);
String outputFileName;
Scanner scanner = new Scanner(System.in);
System.out.println("Please enter output file name:");
outputFileName = scanner.nextLine();
while (outputFileName.isEmpty()) {
System.out
.println("Invalid file name ! Please re-enter output file name:\n");
outputFileName = scanner.nextLine();
}
stringBuffer = new StringBuffer();
for (Entry word : wordCount.entrySet()) {
stringBuffer.append(String.format("%s\t%d%n", word.getKey(),
word.getValue()));
}
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(outputFileName));
bufferedWriter.write(stringBuffer.toString());
bufferedWriter.close();
Set s = wordCount.keySet();
List l = new ArrayList(s);
I wrote a program which gets as an input a file name, and asks for two file names for the output.
The first output file includes all the words from the input file with their number of occurrences.
The second output file includes the words in lexicographic order.
There is some code that is written twice, I think I can fix that by declaring a new method for this part of code, but I'm not sure how to do this properly.
```
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.io.*;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
public class TextAnalyzer {
private static HashMap wordCount = new HashMap();
public static StringBuffer stringBuffer;
public static void main(String[] args) throws IOException {
if (args.length == 0) {
System.out.println("Please specify input file as program argument");
return;
}
getWordsCount(args[0]);
String outputFileName;
Scanner scanner = new Scanner(System.in);
System.out.println("Please enter output file name:");
outputFileName = scanner.nextLine();
while (outputFileName.isEmpty()) {
System.out
.println("Invalid file name ! Please re-enter output file name:\n");
outputFileName = scanner.nextLine();
}
stringBuffer = new StringBuffer();
for (Entry word : wordCount.entrySet()) {
stringBuffer.append(String.format("%s\t%d%n", word.getKey(),
word.getValue()));
}
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(outputFileName));
bufferedWriter.write(stringBuffer.toString());
bufferedWriter.close();
Set s = wordCount.keySet();
List l = new ArrayList(s);
Solution
Single responsibility principle
The
It would be better to split that up to smaller methods,
in a way that each method has a single responsibility.
You will end up with something more modular, reusable, testable.
Make variables local when possible
so doesn't need to be a member variable.
Declare it right before you need it,
in fact, it's best at the time of initialization:
Avoid static variables when possible
None of the static variables were needed.
In general, avoid static variables as much as possible,
especially if they are mutable.
but still easy enough:
make
Use the enhanced for-each loop
Instead of this:
Since you don't need the index values and it's just clutter,
the recommended writing style is this:
This has another advantage that in this form the loop can work efficiently not only with an
because elements are no longer accessed by index.
Use boolean expressions directly
Instead of this:
You can and should write this:
Refer to types by interfaces
Instead of this:
This would be better:
Use Java 7
I'm guessing you're using an older version because of things like this:
Starting from Java 7 you don't need to specify the type parameters at the right hand side of expressions, the compiler can figure them out most of the time, and you can use the diamond operator
Unused imports
You have some unused imports:
I'm surprised your IDE doesn't warn about them.
In fact it probably does.
Strive to keep warnings to minimum, ideally down to zero.
Extremely poor names
In this code,
the variable names
Sure you can come up with better names for these,
which will make the code so much more readable.
Prefer
This is rarely needed in practice,
and in this example it's completely unnecessary.
Use
Btw, is there a benefit to accumulating the output in memory before producing the output? Probably not.
You could just write the output directly,
without building up a long string.
Put braces consistently
In this code, you put braces for the
At the minimum, be consistent.
The recommendation is to put braces always.
The
main method does most of the job.It would be better to split that up to smaller methods,
in a way that each method has a single responsibility.
You will end up with something more modular, reusable, testable.
Make variables local when possible
stringBuffer is only used within the main method,so doesn't need to be a member variable.
Declare it right before you need it,
in fact, it's best at the time of initialization:
StringBuffer stringBuffer = new StringBuffer();Avoid static variables when possible
None of the static variables were needed.
In general, avoid static variables as much as possible,
especially if they are mutable.
wordCount is not as simple to eliminate as stringBuffer,but still easy enough:
make
getWordsCount return a Map.Use the enhanced for-each loop
Instead of this:
for (int i = 0; i < l.size(); i++) {
s2 = s2 + l.get(i) + "\n";
}Since you don't need the index values and it's just clutter,
the recommended writing style is this:
for (String word : l) {
s2 = s2 + word + "\n";
}This has another advantage that in this form the loop can work efficiently not only with an
ArrayList, but with a LinkedList too,because elements are no longer accessed by index.
Use boolean expressions directly
Instead of this:
while (scanner.hasNext() == true) {You can and should write this:
while (scanner.hasNext()) {Refer to types by interfaces
Instead of this:
private static HashMap wordCount = new HashMap();This would be better:
private static Map wordCount = new HashMap();Use Java 7
I'm guessing you're using an older version because of things like this:
List l = new ArrayList(s);Starting from Java 7 you don't need to specify the type parameters at the right hand side of expressions, the compiler can figure them out most of the time, and you can use the diamond operator
<> like this:List l = new ArrayList<>(s);Unused imports
You have some unused imports:
import java.io.FileNotFoundException;
import java.util.Map;I'm surprised your IDE doesn't warn about them.
In fact it probably does.
Strive to keep warnings to minimum, ideally down to zero.
Extremely poor names
In this code,
the variable names
s, l, s2 are bordering obfuscation.Set s = wordCount.keySet();
List l = new ArrayList<>(s);
Collections.sort(l);
String s2 = "";
for (int i = 0; i < l.size(); i++) {
s2 = s2 + l.get(i) + "\n";
}Sure you can come up with better names for these,
which will make the code so much more readable.
Prefer
StringBuilder over StringBufferStringBuffer synchronizes internally to make it thread safe.This is rarely needed in practice,
and in this example it's completely unnecessary.
Use
StringBuilder instead.Btw, is there a benefit to accumulating the output in memory before producing the output? Probably not.
You could just write the output directly,
without building up a long string.
Put braces consistently
In this code, you put braces for the
if, but not for the elseif (tokenCount == null) {
wordCount.put(token, 1);
} else
wordCount.put(token, tokenCount + 1);At the minimum, be consistent.
The recommendation is to put braces always.
Code Snippets
StringBuffer stringBuffer = new StringBuffer();for (int i = 0; i < l.size(); i++) {
s2 = s2 + l.get(i) + "\n";
}for (String word : l) {
s2 = s2 + word + "\n";
}while (scanner.hasNext() == true) {while (scanner.hasNext()) {Context
StackExchange Code Review Q#92818, answer score: 11
Revisions (0)
No revisions yet.