1

So normally, I know one would use a standard for loop to iterate though the array, like such:

public static void readCodesFromFile(String filename, String[] codes) throws FileNotFoundException {
    try ( Scanner fin = new Scanner(new File(filename) ); ) {
        for (int i = 0; i <= codes.length - 1; i++) {
            codes[i] = fin.nextLine();
        }
    }
}

But, I desperately want to discover how to do this with a for each loop instead. At this point I just need to know if it can be done, but also would love the efficiency and cleanliness of using this loop for this task. I have tried something like this, and moved things around many times, but cannot seem to get anything to read properly.

Below is the for each ( : ) I have been working with:

 public static void readCodesFromFile(String filename, String [] codes) throws FileNotFoundException {
     try (Scanner fin = new Scanner(new File(filename) ); ) {
         for (String code : codes) {
            codes = fin.nextLine();
         }
     }
 }
Blank Reaver
  • 225
  • 3
  • 5
  • 17
  • You can't modify the underlying array with a `for-each` (it hides the iterator). You could use a `Stream` (in Java 8+, if you wanted). `Stream.generate(() -> fin.nextLine()).limit(codes.length).collect(Collectors.toList()).toArray(codes);` – Elliott Frisch Jul 29 '17 at 15:10
  • *"**Reading** arrays **to** file"* ???? – Andreas Jul 29 '17 at 15:13
  • This is impossible using for-each loop, have a look here https://stackoverflow.com/questions/17969515/java-for-loop-by-value-or-by-reference – Ameer Jewdaki Jul 29 '17 at 15:16
  • Okay, so is it passing the value and not the reference? If it is creating a temporary string with a copy of a value from the array, it will only continue to change that copy? To change the actual values I need to just stick with the original for I suppose? – Blank Reaver Jul 29 '17 at 15:40
  • The main thing to recognize is in the enhanced version you can't reference a specific element in the array anymore because it's provided to you directly as a string instance. How do you know which one you have? In your second example, you're trying to set the entire array to a single string value. – ChiefTwoPencils Jul 29 '17 at 15:48

2 Answers2

0

At this point I just need to know if it can be done...

No, not as it's written. For one, the spec doesn't allow for it but you're also dealing with immutable Strings. Say, from your second example, code is a reference to an element in your array. Once I do code = "foo";, code now references the (presumably) new String and the array element retains its original value.

But, I desperately want to discover how to do this with a for each loop instead.

If that's the case, why not invert the problem? Instead of iterating over the array, provide a way to iterate over the file.

In this answer I'm going to assume two things:

  1. You'll provide an Iterable FileReader
  2. You'll use an ArrayList instead of a normal array (this is to get past the indexing issue with the additional benefit that you'll no longer need to know or care about the number of lines in the file)

Here's the FileReader (with a lot not implemented):

class FileReader implements Iterable<String> {

    @Override
    public Iterator<String> iterator() {
        return new FileReaderIterator();
    }

    @Override
    public void forEach(Consumer<? super String> action) { }

    @Override
    public Spliterator<String> spliterator() { return null; }

    class FileReaderIterator implements Iterator<String> {

        @Override
        public boolean hasNext() {
            return false;
        }

        @Override
        public String next() {
            return null;
        }

        @Override
        public void remove() { }

        @Override
        public void forEachRemaining(Consumer<? super String> action) { }
    }
}

Assuming you had this implemented you could have used it like so:

List<String> lines = new ArrayList<>();
FileReader reader = new FileReader(...);
for (String line : reader) {
    lines.add(line);
}

I'm not suggesting you change your design rather to consider what a different design choice could have provided.

ChiefTwoPencils
  • 13,548
  • 8
  • 49
  • 75
0

Another way you could achieve this with a basic array very easily would be to encapsulate the line in a class. For example:

class FileLine {
    private String line;

    public FileLine() {...}

    public FileLine(String line) {
        this.line = line;
    }

    public setLine(String line) {
        this.line = line;
    }
}

Make an array of those, iterate over it with the enhanced for loop, and instead of setting the value of the array string element, set the value of the string member of the FileLine instance. Like so:

// Given an array of instantiated FileLines...
for (FileLine fileLine : fileLines) {
    fileLine.setLine(...);
}

Less effort and you don't have to worry about trying to iterate over a file.

ChiefTwoPencils
  • 13,548
  • 8
  • 49
  • 75