首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java 8 lambda:遍历流对象并在流中使用以前的/下一个对象

Java 8 lambda:遍历流对象并在流中使用以前的/下一个对象
EN

Stack Overflow用户
提问于 2017-03-15 13:20:48
回答 6查看 7.3K关注 0票数 6

我正在练习一些入门级的java 8 lambda功能。

给出一个消息列表,每个消息都包含一个消息偏移量,其中所有偏移必须形成一个连续的整数列表,我试图找出需要警告的空白。我觉得这一切都应该与一个漂亮的羔羊做得很好。但我不能把头绕着它。

所以,这里有一个工作片段:

代码语言:javascript
复制
private void warnAboutMessageGaps(final List<Message> messages) {

    final List<Long> offsets = messages.stream()
            .sorted(comparingLong(Message::getOffset))
            .map(Message::getOffset)
            .collect(toList())
            ;

    for (int i = 0; i < offsets.size() - 1; i++) {
        final long currentOffset = offsets.get(i);
        final long expectedNextOffset = offsets.get(i) + 1;
        final long actualNextOffset = offsets.get(i + 1);
        if (currentOffset != expectedNextOffset) {
            LOG.error("Missing offset(s) found in messages: missing from {} to {}", currentOffset + 1, actualNextOffset - 1);
        }
    }
}

我无法理解的是如何使它能够在lambda中完成“与前一个/下一个对象的比较”。如有任何指示,将不胜感激。

/edit:关于StreamEx和其他第三方解决方案的建议,虽然受到赞赏,但不是我想要的。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2019-10-26 07:20:41

对于目前的问题,这种方法似乎更合适。

代码语言:javascript
复制
messages.stream().sorted( Comparator.comparingLong( Message::getOffset ) )
  .reduce( (m1, m2) -> {
    if( m1.getOffset() + 1 != m2.getOffset() )
      LOG.error( "Missing offset(s) found in messages: missing from {} to {}", m1.getOffset(), m2.getOffset() );
    return( m2 );
  } );

这个解决方案使用的是reduce,而不是它的预期用途。它仅使用reduce的能力来遍历流中的所有对。

reduce的结果是使用而不是。(不可能进一步使用结果,因为这将需要可变的减少。)

票数 1
EN

Stack Overflow用户

发布于 2017-03-15 13:47:44

您可以使用StreamEx使用pairMap方法来完成这一任务:

代码语言:javascript
复制
StreamEx.of(messages)
        .sorted(Comparator.comparingLong(Message::getOffset))
        .pairMap((prev, next) -> new Message[] {prev, next})
        .forEach(prevNext -> {
            long currentOffset = prevNext[0].getOffset();
            long expectedNextOffset = prevNext[0].getOffset() + 1;
            long actualNextOffset = prevNext[1].getOffset();
            if (currentOffset != expectedNextOffset) {
                LOG.error(
                    "Missing offset(s) found in messages: missing from {} to {}",
                    currentOffset + 1, actualNextOffset - 1);
            }
        });
票数 3
EN

Stack Overflow用户

发布于 2017-03-16 13:01:47

有时候,尝试使用lambda表达式做任何事情都会使解决方案更加复杂。您可以使用:

代码语言:javascript
复制
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;
        }
    });

但是请注意,无论流链看起来多么流畅,sorted()是一个有状态的中间操作,它在幕后创建和使用支持数组。如果显式地使用该数组,则不会丢失任何内容:

代码语言:javascript
复制
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);
}

很难找到更简单的解决办法。但是,如果要减少所需的内存量,可以使用BitSet而不是数组:

代码语言:javascript
复制
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);
}

与偏移值范围相比,如果没有空白或相当小的空白,这将大大减少使用的内存。当最小偏移距和最大偏移量之间的距离大于Integer.MAX_VALUE时,就会失败。

你可能会事先检查一下,如果根本没有漏洞的话,这也会为你提供捷径的机会:

代码语言:javascript
复制
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
    …
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42811045

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档