0

I'm stuck on how to put the URLs into an array. I loop through fileNames and concatenate paths, but then I'm stuck on how to loop through the urls array and add what I created with the concatenation. How do I do that?

public class DataManager {

    private String[] fileNames;
    private URL[] urls;
    private ArrayList<String> gameData;
    Scanner s; 

    public DataManager(String[] fileNames, String path) throws IOException {
        this.fileNames = fileNames; 
        this.urls = new URL[fileNames.length];
        for (String file: fileNames) {
            String url = path + file;
            for (int i = 0; i < urls.length; i++) {  
                urls[i] = url;
            }
        }
    }

    public static void main(String[] args) throws IOException {
        String[] fileNames = { "50.csv", "100.csv", "500.csv" }; 
        String path = "http://people.uncw.edu/tompkinsj/331/ch07/";
        DataManager foo = new DataManager(fileNames, path);
    }

    // getters and other methods
}

2 Answers 2

1

When such a problem arises, and you have been diving deep into something, and spend too much time with one issue: always take a step back, take a break, do something else, and come back later... It pays off.

Your code is almost right

for (String file: fileNames){                   //logically OK
    String url = path + file;                 
    for (int i = 0; i < urls.length; i++) {     //things start going wrong
        urls[i] = url;                          //this line has a red underline
    }
}

You have 2 problems: a logical one, and a minor issue.

The minor problem:

This line is incorrect:

urls[i] = url;

The array urls is of type URL - which is not a supertype of String, so this line is most likely red in your IDE. To correct it, we need to create an URL instance from the String, and we are lucky: there is a constructor exactly for that: new URL(url). However, this can throw a MalformedUrlException if there is a problem which needs to be caught. For the sake of simpleness, let's just rethrow it as an IllegalStateException

try {
    urls[i] = new URL(url);
} catch (MalformedUrlException e) {
    throw new IllegalStateException("Wrong URL: " + url);
}

The logical problem:

While going through the filenames, on each iteration you also iterate over the whole urls[] array I think you don't want that: each filename will yield one URL - so it should be enough to traverse the filename array once. Also, by setting the value on each iteration - you would overwrite all previous values, and when all the loops complete, all you would be left with is an array filled with the last URL processed. I think the problem you try to solve with the inner loop is that you don't know which index to put the new element into, because you didn't keep track which filename entry you were processing. This is a scenario, where a traditional for loop is more handy than just iterating over the array:

for (int i = 0; i < fileNames.length; i++){
    String file = fileNames[i];
    String url = path + file;                 
    try {
        urls[i] = new URL(url);
    } catch (MalformedUrlException e) {
        throw new IllegalStateException("Wrong URL: " + url);
    }
}

Of course, this can be improved to be a bit shorter:

for (int i = 0; i < fileNames.length; i++){
    try {
        urls[i] = new URL(path + fileNames[i]);
    } catch (MalformedUrlException e) {
        throw new IllegalStateException("Wrong URL: " + path + fileNames[i]);
    }
}

... and of course the exception would need an appropriate handling, but that requires more in-depth knowledge about what the code is trying to do, e.g. is it considered an irrecoverable error if the URL is incorrect, etc.

Sign up to request clarification or add additional context in comments.

Comments

1

Here's a stream version, which can make the steps clearer:

urls = Arrays.stream(fileNames)
    .map(f -> path + f)   // build full path from path + filename
    .map(this::createUrl) // create URL from full path
    .toArray(URL[]::new); // create and populate an array

private URL createUrl(String url) {
    try {
       return new URL(url);
    } catch (MalformedUrlException e) {
       throw new IllegalArgumentException(url);
    }
}

Streams don't allow exploding methods. You can use massive ugly lambdas, but the helper method makes the stream code much neater.

This will throw an IllegalArgumentException if the full path is not s valid URL; if that is not going to happen you don't need to do anything more. If it could happen and you want to take special action, wrap the stream code line in a try catch.

Disclaimer: Code may not compile or work as it was thumbed in on my phone (but there's a reasonable chance it will work)

3 Comments

Nope... URL::new throws MalformedUrlException. This would not even compile. This is exactly why I didn't bother going with a Streams solution. This also exactly why I'm frustrated by Streams - this would be soooo elegant - but not possible.
@ppeterka Ah. I just thumbed that in. Nevertheless I have thumbed in a corrected version that should compile.
I feel your pain, coding on a touch screen is a disaster... The drawback is that if MalformedURLException is not considered a fatal problem, it would be quite a task to solve. But that might just be a question of structuring the surrounding code to be lambda and Streams friendly...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.