1

How can I output to a given writer all the rows in the list that consist only of Latin letters or numbers and return the number of successfully written bytes before the first exception using a lambda expression?

My code:

public int writeAllCountingBytesTransferred(Writer writer, List<String> list) {     
    return list.stream().filter(x -> x.matches("^[a-zA-Z0-9]+$") ).forEach(x-> {
        try {
            writer.write(x);
            how do I count bytes?
        } catch (IOException e) {
            how do I return bytes?

        }
    });        
}
Youcef LAIDANI
  • 55,661
  • 15
  • 90
  • 140
Alexander
  • 59
  • 5
  • Does this answer your question? [How to count String bytes properly?](https://stackoverflow.com/questions/43195075/how-to-count-string-bytes-properly) – papaya Feb 17 '20 at 13:50

2 Answers2

2

I would map to an IntStream of the string lengths and sum() it:

return list.stream()
    .filter(x -> x.matches("^[a-zA-Z0-9]+$"))
    .mapToInt(x-> {
      try {
        writer.write(x);
        return x.length();
      } catch (IOException e) {
        return 0;
      }
    })
    .sum();

Note that when the strings are all letters and digits the char length and byte length are the same.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • Intelligent solution :) – Youcef LAIDANI Feb 17 '20 at 14:07
  • 1
    You can not say whether char length and byte length are the same, without knowing the `Writer`’s actual character encoding. For `UTF-16`, for example, even latin letters and digits produce two bytes per char. Besides that, for an arbitrary `Writer`, we can not even assume a plain text output format. The writer could produce a Base64 output, for example. Who knows… Further, when encountering an `IOException`, you can not assume that nothing has been written already. – Holger Feb 17 '20 at 15:36
  • @Holger all true and thanks for raising these finer points, but given `matches("^[a-zA-Z0-9]+$")` and the typical case, my code would pass all tests that would likely be written for it. I always strive for simplicity, brevity and readability and vigorously apply [YAGNI](https://martinfowler.com/bliki/Yagni.html). – Bohemian Feb 17 '20 at 21:01
  • 1
    YAGNI is fine when you know all your requirements, but here, all we have is a `Writer` without further information. The minimum we should do, is to document the assumptions and limitations of a solution. – Holger Feb 18 '20 at 07:31
0
public class CountingWriter extends FilterWriter {
    private long count;

    public CountingWriter(Writer out) {
        super(out);
    }

    /**
     * The number of chars written. For ASCII this is the number of bytes.
     * @return the char count.
     */
    public long getCount() {
        return count;
    }

    @Override
    public void write(int c) throws IOException {
        super.write(c);
        ++count;
    }

    @Override
    public void write(char[] cbuf, int off, int len) throws IOException {
        super.write(cbuf, off, len);
        count += len;
    }

    @Override
    public void write(String str, int off, int len) throws IOException {
        super.write(str, off, len);
        count += len;
    }
}

CountingWriter cWriter = new CountingWriter(writer);
...
long count = cWriter.getCount();

A FilterWriter is a nice wrapper class that delegates to the original writer, and can be used for this kind of filtering purposes.

As ASCII implies that every char is written as a single byte. (If the encoding for the file is not UTF-16LE or such.)

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138