Reputation: 101
This is my poor attempt at trying to create an array inside a static method. What this program does is list documents that have a certain extension. I want to be able to store them in an array and access that array from main. Is it possible? This is my code so far:
package recogniseKeywords;
import java.io.File;
import java.io.FileInputStream;
import java.util.Arrays;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
public class KeywordsRecognition {
public static void listFilesForFolder(final File folder) {
String[] files = {};
int fileSize = 0;
String[] extensions = {".doc", ".docm", ".xls"};
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
for(int i=0; i<extensions.length; i++) {
//Check if contains one of the extensions and isn't a temporary file(~$)
if (fileEntry.getName().contains(extensions[i]) && !fileEntry.getName().startsWith("~$")) {
System.out.println(fileEntry.getName());
files[fileSize] = fileEntry.getName();
fileSize++;
}
}
}
}
}
public static void main(String[] args) throws Exception {
String[] keywords = {"Performance Enhancement", "Functional Specification", "Technical Specification", "Faults", "Arval", "Vehicle", "Fines", "Insurance"};
final File folder = new File("C:/work");
listFilesForFolder(folder);
System.out.println(Arrays.toString(files));
}
}
}
I am aware that this is a static method and that int, as well as the array, is not treated as in a non-static method, however, I don't know how to proceed further.
Upvotes: 0
Views: 2184
Reputation: 16209
The best pointer I can give you is to leave the clutches of the static realm and go into instance-land, the land of object-oriented opportunities!
In your main method do this:
public static void main(String[] args) throws Exception {
KeywordsRecognition app = new KeywordsRecognition();
app.start();
}
Then implement the start method and start your work there. Doing this will give you more options in your code design, allowing you to write more readable and testable code, and thus code with less bugs and maintenance issues.
To access the result of listFilesForFolder you can either return it, assign it to a field, or add it to a collection. Since you are recursing I would say: add it to a collection.
Rationale: each recursion adds to the same collection. You don't want intermediate results visible to other code than the recursion so avoid a field and use a method parameter. Also, it's quite common to pass data through a recursion in this manner, so other developers will understand it.
private static final String ROOT_FOLDER_DEFAULT = "C:/work";
private static final String[] EXTENSIONS = {".doc", ".docm", ".xls"};
// TODO: the keywords are not used anywhere yet
private static final String[] KEYWORDS = {"Performance Enhancement", "Functional Specification", "Technical Specification", "Faults", "Arval", "Vehicle", "Fines", "Insurance"};
public void start(String rootFolder) {
List<String> files = new ArrayList<>();
readFilesRecursively(new File(rootFolder), files);
// trick to print list contents by converting to array
System.out.println(Arrays.toString(files.toArray()));
}
// recursion is not that common so when you use it,
// it's a good idea to clearly indicate this in the method name
public void readFilesRecursively(File folder, List<String> files) {
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
readFilesRecursively(file, files);
} else {
for(String extension : EXTENSIONS) {
String fileName = file.getName();
if (fileName.contains(extension ) && !isTemporaryFile(fileName)) {
files.add(fileName);
}
}
}
}
}
// if you find yourself adding a comment in the middle of your code
// that usually means you need to extract a method for that bit
private boolean isTemporaryFile(String fileName) {
return fileName.startsWith("~$");
}
public static void main(String[] args) throws Exception {
KeywordsRecognition app = new KeywordsRecognition();
app.start(getRootFolder(args));
}
private static String getRootFolder(String[] args) {
if(args != null && args.length > 0) {
return args[0];
}
else {
return ROOT_FOLDER_DEFAULT:
}
}
Sidenote: you cannot increase the size of an array; once you create it, its size is fixed. So either initialize the array to the correct length, or use a java.util.List instead (optionally converting the List to an array after it has been fully populated):
List<String> values = new ArrayList<>();
values.add("1");
values.add("foo");
values.add("elderberries");
String[] valuesAsArray = values.toArray();
Either that, or:
String[] valuesAsArray = new String[3];
values[0] = "1";
values[1] = "foo";
values[2] = "elderberries";
Upvotes: 1
Reputation: 719239
The reason that main
can't see the files
variable in listFilesForFolder
is that files
is a local variable. Its scope is the listFilesForFolder
method itself. (This would still be true if you declared main
and listFilesForFolder
as instance methods.)
There are a number of possible solutions. The most straightforward are:
Return the value files
as the result of listFilesForFolder
, and use the returned value in main
.
Declare files
as a static
variable rather than a local variable.
Declare files
as an instance variable, and then change the code to be more object oriented; see Adrian's answer for an example.
Of these approaches, 1 and 3 are better. Approach 2 will work in a simple example like this, but is problematic (for various reasons) in a large application.
Upvotes: 0