Sometimes trying to do everything with lambda expressions complicates decisions. You can use:
messages.stream() .mapToLong(Message::getOffset) .sorted() .forEachOrdered(new LongConsumer() { boolean first=true; long expected; public void accept(long value) { if(first) first=false; else if(value!=expected) LOG.error("Missing offset(s) found in messages: missing from {} to {}", expected, value); expected=value+1; } });
but note that no matter how loose the thread chain can be, sorted() is an intermediate intermediate operation that creates and uses a backup array backstage. You do not lose anything if you explicitly use this array:
long[] l = messages.stream().mapToLong(Message::getOffset).toArray(); Arrays.sort(l); for(int ix=1; ix<l.length; ix++) { long value = l[ix], expected = l[ix-1]+1; if(value!=expected) LOG.error("Missing offset(s) found in messages: missing from {} to {}", expected, value); }
It is difficult to find a simpler solution. But if you want to reduce the amount of memory needed, you can use BitSet instead of an array:
OptionalLong optMin = messages.stream().mapToLong(Message::getOffset).min(); if(!optMin.isPresent()) return; long min = optMin.getAsLong(); BitSet bset = messages.stream() .mapToLong(Message::getOffset) .collect(BitSet::new, (bs,l) -> bs.set((int)(l-min)), BitSet::or); for(int set=0, clear; set>=0; ) { clear = bset.nextClearBit(set); set = bset.nextSetBit(clear); if(set >= 0) LOG.error("Missing offset(s) found in messages: missing from {} to {}", min+clear, min+set); }
This will significantly reduce the memory used when there are no gaps or reasonably small gaps compared to the range of offset values. It fails when the distance between the smallest offset and the largest offset is greater than Integer.MAX_VALUE .
You can check this in advance, which also opens up the possibility of a short circuit if there are no spaces:
LongSummaryStatistics stat = messages.stream() .mapToLong(Message::getOffset).summaryStatistics(); if(stat.getCount()==0 || // all solutions assume that there are no duplicates, in this case, // the following test allows to prove that there are no gaps: stat.getMax()-stat.getMin()==messages.size()-1) { return; } if(stat.getMax()-stat.getMin()>Integer.MAX_VALUE) { // proceed with array based test โฆ } else { long min = stat.getMin(); // proceed with BitSet based test โฆ