Reputation: 1659
I'm trying to get away from while ((line = br.readLine()) != null)
, but the limitations of streams are proving to be hard to overcome in an elegant way in this case.
I want the first line which matches a certain criterion and the last two lines before this which matches two different criteria. This seems to be the best I can do, but it only works if lines are encountered in the right order so it doesn't terminate early. So are they? It's hard to tell from the documentation.
String[] savedLines = { "", "", "" };
try (Stream<String> lines = Files.lines(file)) {
lines.allMatch(line -> {
if (line.startsWith(s1)) {
savedLines[0] = line;
} else if (line.startsWith(s2) && line.contains(s3)) {
savedLines[1] = line;
} else if (line.startsWith(s4)) {
savedLines[2] = line;
return false;
}
return true;
});
}
Upvotes: 0
Views: 213
Reputation: 21189
The JEP 461: Stream Gatherers Java 22 preview language feature adds built-in support for sliding windows, which could be used to check each trio of adjacent lines, in order.
List<String> result;
try (Stream<String> lines = Files.lines(file)) {
result = lines.gather(Gatherers.windowSliding(3))
.filter(w -> w.get(0).startsWith(s1)
&& w.get(1).startsWith(s2)
&& w.get(1).contains(s3)
&& w.get(2).startsWith(s4))
.findFirst()
.orElse(List.of());
}
This uses the new Stream.gather
method with the new built-in Gatherers.windowSliding
gatherer to convert the initial Stream<String>
to a Stream<List<String>>
of three-element lists of consecutive lines.
As this is still a preview language feature, it should not be used in production code until it graduates to being a permanent feature.
An intermediate operation that transforms a stream of input elements into a stream of output elements, optionally applying a final action when the end of the upstream is reached. […]
[…]
There are many examples of gathering operations, including but not limited to: grouping elements into batches (windowing functions); de-duplicating consecutively similar elements; incremental accumulation functions (prefix scan); incremental reordering functions, etc. The class
Gatherers
provides implementations of common gathering operations.
Returns a stream consisting of the results of applying the given gatherer to the elements of this stream.
Returns a Gatherer that gathers elements into windows -- encounter-ordered groups of elements -- of a given size, where each subsequent window includes all elements of the previous window except for the least recent, and adds the next element in the stream. […]
Example:
// will contain: [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8]] List<List<Integer>> windows2 = Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowSliding(2)).toList(); // will contain: [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8]] List<List<Integer>> windows6 = Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowSliding(6)).toList();
Upvotes: 1
Reputation: 140454
Given that the lines are being read from a file, I can't see why they wouldn't be in file order - it would take more storage to do anything other than read the current line, then read the next line etc.
Irrespective, don't do it like this: you are going against what it says in the documentation about the predicate of Stream.allMatch
:
predicate
- a non-interfering, stateless predicate to apply to elements of this stream
Your predicate is not stateless. You shouldn't do this in allMatch
.
Stick with BufferedReader
.
Upvotes: 2