Java – Use streams to read specific columns from a file in Java 8 and put them into a two-dimensional array

Use streams to read specific columns from a file in Java 8 and put them into a two-dimensional array… here is a solution to the problem.

Use streams to read specific columns from a file in Java 8 and put them into a two-dimensional array

I have an input file that looks like this

@id1   1.2   3.4
@id2   6.8   8.1
@id3   1.5   9.4
@id4   5.9   2.7

I just want to store the numbers in a two-dimensional array and forget the first column containing @id.
I also want to use a stream just for that operation.

So far, I’ve done two ways:

The first method reads the input file and stores each row in a list, as an array of strings:

private List<String[]> savefromfile(String filePath) throws IOException {

List<String[]> rowsOfFile = new LinkedList<String[]>();
        try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
            lines.forEach(line -> {
                String rows[] = line.trim().split("\\s+");
                rowsOfFile.add(rows);
            });
            lines.close();
        }
        return rowsOfFile;

The second method takes a list as input and returns a two-dimensional array containing only the column numbers:

private double[][] storeAllID(List<String[]> rowsOfFile) {
        int numberOfID = rowsOfFile.size();
        double[][] allID = new double[numberOfID][2];
        int i = 0;
        for (String[] line : rowsOfFile) {
            double id[] = new double[2];
            id[0] = Double.parseDouble(line[1]); 
            id[1] = Double.parseDouble(line[2]);
            allID[i++] = id;
        }
        return allID;
    }

Is there a way to make this code more efficient? I just want a short way to read the input file and return a two-dimensional array containing only numbers.
I don’t think it’s necessary to write 20 lines of code to do this.

Solution

Using a stream in a savefromfile doesn’t really get any benefit because you’re using it as if it were a normal for loop. To make the code a little more concise, you can get rid of local variables altogether and don’t need to call close() because you’re already using try-with-resources.

private List<String[]> savefromfile(String filePath) throws IOException {
    try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
        return lines
            .map(line -> line.trim().split("\\s+"))
            .collect(Collectors.toCollection(LinkedList::new));
    }
}

I don’t know why you would want to separate the parsing of double[][] into a separate method, because you can use the map in your stream to do it :

    private double[][] loadFromFile(String filePath) throws IOException {
        try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
            return lines
                .map(line -> line.trim().split("\\s+"))
                .map(line -> new double[] {
                    Double.parseDouble(line[1]),
                    Double.parseDouble(line[2])
                })
                .toArray(double[][]::new);
        }
    }

For performance, you only need to measure for yourself whether using lower-level data types and loops is worth the added complexity.

Related Problems and Solutions