In general your approach is fine. However, you can do that with a single stream cascade. Compared to your original approach this saves you one iteration.
Also note that nowadays we read files using Javas new I/O API called NIO. One big advantage is that it offers Stream
methods. For example the Files#lines
method that returns a stream over all lines of the file, perfectly suited for your approach.
So all in all, here is the complete code:
String file = ...
Pattern separator = Pattern.compile("\\s");
try (Stream<String> lines = Files.lines(Paths.get(file))) {
T[] values = lines // Stream<String> lines
.flatMap(separator::splitAsStream) // Stream<String> words
.mapToInt(Integer::parseInt) // IntStream values
.mapToObj(T::new) // Stream<T> valuesAsT
.toArray(T[]::new);
} catch (IOException e) {
System.out.println("Something went wrong.");
}
Note that this code is slightly different to yours, as yours will only process one line and mine all lines. You may change that if you don't want it:
List<T[]> valuesPerLine = Files.lines(Paths.get(file)) // Stream<String> lines
.map(separator::splitAsStream) // Stream<Stream<String>> wordsPerLine
.map(lineStream -> {
return lineStream // Stream<String> words
.mapToInt(Integer::parseInt) // IntStream values
.mapToObj(T::new) // Stream<T> valuesAsT
.toArray(T[]::new);
}) // Stream<T[]> valuesPerLine
.collect(Collectors.toList());
The main difference to your original approach is that we can easily transform an IntStream
into a Stream<T>
by using mapToObj(T::new)
(or just map
if it's a regular stream and not IntStream
) which passes the elements to the constructor. After that we collect Stream<T>
into an array by using toArray(T[]::new)
.