java code style question - for loops - java

Is the following code clear and easy to read?
public void createDatabase() throws SQLException, IOException {
SQLiteDatabase database = dbStore.getDatabase();
LineNumberReader scriptInputReader = new LineNumberReader(new InputStreamReader(getClass().getResourceAsStream(SCRIPT_CREATE)));
for(String line; (line = scriptInputReader.readLine()) != null;) {
database.execSQL(line);
}
}
I write a lot of "for" loops like the one above. For me it looks clear - it shows the temporary variable ("line") used in the loop, limits it's scope and points out when the loop ends (when "readLine" returns "null"). I wonder if other programmers will hate me for those...
or this one:
SQLiteDatabase database = dbStore.getDatabase();
Cursor cursor = database.query("PINS", new String [] {"ID", "X", "Y"}, null, null, null, null, "ID");
if(cursor.moveToFirst()) {
for(; !cursor.isAfterLast(); cursor.moveToNext()) {
(...)
}
}
cursor.close();
Are things like the above just "neat" or already a Java-puzzles?

I'd opt for:
String line = null;
while((line = scriptInputReader.readLine()) != null) {
... do stuff with line
}
This is clear and straightforward.

I like what you've done, but I would make one small change:
for(String line = scriptInputReader.readLine(); line != null; line = scriptInputReader.readLine()) {
database.execSQL(line);
}
This separates the iteration action from the loop termination condition. Also, unlike the "while" version, it limits the scope of the line variable to the loop - narrowing scope as much as possible is good coding practice.
Also, code style checkers usually consider assignments nested within tests as "poor style". To be clear, your code is a bit like this:
for (int i = -1; ++i < max;) { // don't do this: increment action inside condition section
// some code
}

I would use a while loop
String line = scriptInputReader.readLine();
while(line != null){
//do stuff
line = scriptInputReader.readLine();
}

I would feel more at ease with while.
The first one is not that bad as it is because it is easy to understand what the loop does, but if you add more logic in the middle of the loop and the operation is complicated it will become more difficult (because people will think:'hey, if he wanted just to read a file he would have used a while, so there must be some trick').
The second one (the for doing at the work, and no code inside the loop) is awful and probably in a not so distant future someone will say: 'Hey, there was a loop here and the contents were removed, but they forgot to remove the loop! I can optimize that by removing the for altogether').

I think there are two different schools of thought here. The one as shown by Jarek Potiuk that prefers to use for/while loops for different purposes, ie. a for loop should be used when you know the range of your loop in advance (for (;i < arr.length(); i++)) while a while is preferred for unlimited situations.
But then there's the other line of thought that uses only one kind of loop and at that the for loop because it's more versatile. The Java SDK for example uses for loops pretty extensively in unlimited situations (eg linked lists).
But then you should really write the for loop like Bohemian does - much clearer.

Some prefer to use a while-loop when you do not know when the loop will terminate. For example reading through a file.
Jarek Potiuk's solution works, however I prefer something like this:
String line = scriptInputReader.readLine();
while(line != null)
{
... do stuff with line
line = scriptInputReader.readLine();
}
It is a little bit more code, but I have to agree with Bohemian:
code style checkers usually consider
assignments nested within tests as
"poor style"

Related

Removing duplicate lines from a text file

I have a text file that is sorted alphabetically, with around 94,000 lines of names (one name per line, text only, no punctuation.
Example:
Alice
Bob
Simon
Simon
Tom
Each line takes the same form, first letter is capitalized, no accented letters.
My code:
try{
BufferedReader br = new BufferedReader(new FileReader("orderedNames.txt"));
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("sortedNoDuplicateNames.txt", true)));
ArrayList<String> textToTransfer = new ArrayList();
String previousLine = "";
String current = "";
//Load first line into previous line
previousLine = br.readLine();
//Add first line to the transfer list
textToTransfer.add(previousLine);
while((current = br.readLine()) != previousLine && current != null){
textToTransfer.add(current);
previousLine = current;
}
int index = 0;
for(int i=0; i<textToTransfer.size(); i++){
out.println(textToTransfer.get(i));
System.out.println(textToTransfer.get(i));
index ++;
}
System.out.println(index);
}catch(Exception e){
e.printStackTrace();
}
From what I understand is that, the first line of the file is being read and loaded into the previousLine variable like I intended, current is being set to the second line of the file we're reading from, current is then compared against the previous line and null, if it's not the same as the last line and it's not null, we add it to the array-list.
previousLine is then set to currents value so the next readLine for current can replace the current 'current' value to continue comparing in the while loop.
I cannot see what is wrong with this.
If a duplicate is found, surely the loop should break?
Sorry in advance when it turns out to be something stupid.
Use a TreeSet instead of an ArrayList.
Set<String> textToTransfer = new TreeSet<>();
The TreeSet is sorted and does not allow duplicates.
Don't reinvent the wheel!
If you don't want duplicates, you should consider using a Collection that doesn't allows duplicates. The easiest way to remove repeated elements is to add the contents to a Set which will not allow duplicates:
import java.util.*;
import java.util.stream.*;
public class RemoveDups {
public static void main(String[] args) {
Set<String> dist = Arrays.asList(args).stream().collect(Collectors.toSet());
}
}
Another way is to remove duplicates from text file before reading the file by the Java code, in Linux for example (far quicker than do it in Java code):
sort myFileWithDuplicates.txt | uniq -u > myFileWithoutDuplicates.txt
While, like the others, I recommend using a collection object that does not allow repeated entries into the collection, I think I can identify for you what is wrong with your function. The method in which you are trying to compare strings (which is what you are trying to do, of course) in your While loop is incorrect in Java. The == (and its counterpart) are used to determine if two objects are the same, which is not the same as determining if their values are the same. Luckily, Java's String class has a static string comparison method in equals(). You may want something like this:
while(!(current = br.readLine()).equals(previousLine) && current != null){
Keep in mind that breaking your While loop here will force your file reading to stop, which may or may not be what you intended.

Stanford Tokenizer NullPointerException

I was just struck with an odd exception from the entrails of StanfordNLP, when trying to tokenize:
java.lang.NullPointerException at
edu.stanford.nlp.process.PTBLexer.zzRefill(PTBLexer.java:24511) at
edu.stanford.nlp.process.PTBLexer.next(PTBLexer.java:24718) at
edu.stanford.nlp.process.PTBTokenizer.getNext(PTBTokenizer.java:276)
at
edu.stanford.nlp.process.PTBTokenizer.getNext(PTBTokenizer.java:163)
at
edu.stanford.nlp.process.AbstractTokenizer.hasNext(AbstractTokenizer.java:55)
at
edu.stanford.nlp.process.DocumentPreprocessor$PlainTextIterator.primeNext(DocumentPreprocessor.java:270)
at
edu.stanford.nlp.process.DocumentPreprocessor$PlainTextIterator.hasNext(DocumentPreprocessor.java:334)
The code that cause it looks like this:
DocumentPreprocessor dp = new DocumentPreprocessor(new StringReader(
tweet));
// unigrams
for (List<HasWord> sentence : dp) {
for (HasWord word : sentence) {
// do stuff
}
}
// bigrams
for (List<HasWord> sentence : dp) { //<< exception is thrown here
Iterator<HasWord> it = sentence.iterator();
String st1 = it.next().word();
while (it.hasNext()) {
String st2 = it.next().word();
String bigram = st1 + " " + st2;
// do stuff
st1 = st2;
}
}
What is going on? Has this to do with me looping over the tokens twice?
This is certainly an ugly stacktrace, which can and should be improved. (I'm about to check in a fix for that.) But the reason that this doesn't work is that a DocumentProcessor acts like a Reader: It only lets you make a single pass through the sentences of a document. So after the first for-loop, the document is exhausted, and the underlying Reader has been closed. Hence the second for-loop fails, and here crashes out deep in the lexer. I'm going to change it so that it just will give you nothing. But to get what you want you either want to (most efficient) get both the unigrams and bigrams in one for-loop pass through the document or to create a second DocumentPreprocessor for the second pass.
I think it.next().word() is causing it.
Change your code so you can first check if it.hasNext() and then do it.next().word() .

Workaround for declaring array in an if condition

I have a problem with this part of the code where I want to be able to declare an array and the size of which should be the corresponding no of splits in the string.
Or do I need to count the no of commas in the string and allocate size accordingly or is there a better solution.
String MapPath2[];
if(type.equals("comparative"))
MapPath2[]=args[1].split(",");
I haven't had a chance to code in java in the recent past. Please spare me if it is a silly question and guide me as a noob. Appreciate your help.
You don't need to declare the size, what you have is fine if you remove the extra []:
String MapPath2[];
if(type.equals("comparative"))
MapPath2=args[1].split(",");
The array split gives back to you has the appropriate size. If you need to know the resulting size, use MapPath2.length (after assigning it).
You'd probably want to do something in the else as well, so that MapPath2 has a definite value either way:
String MapPath2[];
if(type.equals("comparative"))
MapPath2=args[1].split(",");
else
MapPath2=null;
or more concisely:
String MapPath2[];
MapPath2 = type.equals("comparative") ? args[1].split(",") : null;
(Instead of the nulls there, if having an empty array is preferred for subsequent logic as is sometimes handy, replace null with new String[0] above and below. Other times, it's more handy to have the null as a "no data" flag.)
Side note: There are some overwhelmingly common code style conventions in the Java world that you would be best advised to use in your code:
Variable names should start with a lower case letter, so as not to be confused with class names.
The [] should go with the type name rather than the variable name.
Always use {} even when the body of an if or else is only one line.
Put spaces around operators and keywords for ease of reading.
Applying those:
String[] mapPath2;
if (type.equals("comparative")) {
mapPath2 = args[1].split(",");
}
else {
mapPath2 = null;
}
Many people also put the else on the same line as the }, so:
String[] mapPath2;
if (type.equals("comparative")) {
mapPath2 = args[1].split(",");
} else {
mapPath2 = null;
}
Or again, more concisely:
String[] mapPath2;
mapPath2 = type.equals("comparative") ? args[1].split(",") : null;
You can use List instead of Array if you don't know what size it needs be.
Then you can use
List<String> list = new ArrayList<>();
if(type.equals("comparative")){
Collections.addAll(list, args[1].split(","));
}

Finding a word and copying the line it's in in Java

I'm trying to create a small program that allows you to search for a word in a text file, and then the program should print out the whole line the text is in.
Example:
test.txt
don't mind this text
don't mind this either
and then when you let the program search for the word "text", it should print out "Don't mind this text".
What's the best way to do this?
This is what I have;
public boolean findFileInCache(){
try (BufferedReader br = new BufferedReader(new FileReader("direct.txt")))
{
while ((name = br.readLine()) != null)
{
Process p = Runtime.getRuntime().exec(name);
}
}
catch (IOException e1) { }
return true;
}
Use BufferedReader to read the file line by line using the BufferedReader.readLine() method.
For each line, check if the word is in it using a regular expression, or by splitting the line into a String[] (using String.split()), and iterating the entries in the resulting array to check if any of them is the desired word. If the desired word is there - print the entire line.
If you chose the 2nd suggestion, don't forget to check equality of two strings by using equals() and NOT by using ==
There are a couple of things you need to do:
Learn the basics by going through an introductory Java book, or course notes, from the beginning, making sure you understand each step as it comes.
Read the Javadocs of likely classes, to find methods that could be useful for the task.
You have already found two core pieces of the solution:
You are getting a line at a time using BufferedReader.readLine()
You are doing it in a while loop, so you handle one line at a time
Now, you need to work out how to deal with each line. Although you didn't include the type, name is a String. It would be better as:
while ((String name = br.readLine()) != null) {
... do something with `line`
}
If your code compiled without String there, it means you declared name as a global. Don't do that, until you know what you're doing.
Breaking things into methods is good; so let's make "do something with line" use a method now:
while ((String name = br.readLine()) != null) {
if(matches(line,"text")) {
System.out.println(line);
}
}
Now you need to write matches():
private boolean matches(String line, String word) {
boolean result = // work out whether it's a match
return result;
}
So, how do you write the guts of matches()?
Well, start by looking at the methods available in String. It has methods like contains() and split(). Some of those methods return other types, like arrays. Your teaching material and reference materials tell you how to look in arrays. The answers are there.

While loop executes a statement that I need to store in Java

I couldn't find a better way to word the question but here is what I would like to do. I am using the RandomAccessFile class to do various things with an input file.
I would like to check to make sure the next line file is not null before attempting to store the line.
So I use the code:
while (raf.readLine() ! = null)
{
//Do things with that line
}
But once I call raf.readLine() in the while loop I iterate to the next line without actually storing the line. Is there I way I can store the line that way read in the while loop?
One common way to do this is something like:
while ((myLine = raf.readLine()) != null)
{
//Do things with that line, held in myLine
}
An assignment evaluates to the value that was assigned.
You can declare the variable to store the line outside the loop and initialize it with the first line, and read the next line at the end of the loop, then check if that variable is null in the loop condition.
String currentLine = raf.readLine();
while(currentLine != null)
{
//do stuff
currentLine = raf.readLine();
}

Categories

Resources