【问题标题】:How to compare two Streams in Java 8如何比较 Java 8 中的两个流
【发布时间】:2016-01-15 19:36:24
【问题描述】:

比较 Java 8 中的两个 Stream 实例并确定它们是否具有相同的元素(特别是用于单元测试)的好方法是什么?

我现在得到的是:

@Test
void testSomething() {
  Stream<Integer> expected;
  Stream<Integer> thingUnderTest;
  // (...)
  Assert.assertArrayEquals(expected.toArray(), thingUnderTest.toArray());
}

或者:

Assert.assertEquals(
    expected.collect(Collectors.toList()),
    thingUnderTest.collect(Collectors.toList()));

但这意味着我正在构建两个集合并丢弃它们。考虑到我的测试流的大小,这不是性能问题,但我想知道是否存在比较两个流的规范方法。

【问题讨论】:

  • 我很确定没有办法不将流强制转换为集合或数组,就像您在上面所做的那样。
  • 向每个人请求一个iterator(),然后同步遍历它们。
  • 顺便说一句,这出现在 Streams 本身的测试框架中。我们指定了 18 种遍历模式(还有更多,这些是我们测试过的)并一直遍历“相同”的流,并比较结果是否相同(流库语义允许的模重排序。)参见,例如, hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/test/java/….
  • @BrianGoetz 枚举常量作为测试用例!?

标签: java junit java-8 java-stream


【解决方案1】:
static void assertStreamEquals(Stream<?> s1, Stream<?> s2) {
    Iterator<?> iter1 = s1.iterator(), iter2 = s2.iterator();
    while(iter1.hasNext() && iter2.hasNext())
        assertEquals(iter1.next(), iter2.next());
    assert !iter1.hasNext() && !iter2.hasNext();
}

【讨论】:

  • 我想你也可以使用BaseStream&lt;?,?&gt; s1, BaseStream&lt;?,?&gt; s2来支持IntStreamLongStreamDoubleStream
  • @TagirValeev -- 好主意。而对于性能痴迷者,他们应该重载assertStreamEquals(IntStream, IntStream) 等。
【解决方案2】:

收集被测流(如您所示)是执行测试的一种直接有效的方法。您可以以最简单的可用方式创建预期结果列表,这可能不会收集流。

或者,对于大多数用于创建模拟协作者的库,可以模拟一个 Consumer,它“预期”一系列带有特定元素的 accept() 调用。 ConsumeStream,然后“验证”其配置的期望是否得到满足。

【讨论】:

    【解决方案3】:

    使用 Guava 库中的elementsEqual 方法:

    Iterators.elementsEqual(s1.iterator(), s2.iterator())
    

    【讨论】:

      【解决方案4】:

      您可以断言流的内容创建Stream&lt;&gt; expected

      AssertJ 对此有流畅易读的解决方案。

      import static org.assertj.core.api.Assertions.assertThat;
      import java.util.stream.Stream;
      import org.junit.jupiter.api.Test;
      
      class MyTests {
          @Test
          void test() {
              Stream<Integer> actual = Stream.of(0, 8, 15); // your thingUnderTest
      
              assertThat(actual).containsExactly(0, 8, 15);
          }
      }
      

      【讨论】:

        【解决方案5】:
        public static boolean equalStreams(Stream<?> ... streams) {
            List<Iterator<?>> is = Arrays.stream(streams)
                    .map(Stream::iterator)
                    .collect(Collectors.toList());
        
            while (is.stream().allMatch(Iterator::hasNext))
                if (is.stream().map(Iterator::next).distinct().limit(2).count() > 1)
                    return false;
        
            return is.stream().noneMatch(Iterator::hasNext);
        }
        

        【讨论】:

          【解决方案6】:

          如果元素的顺序无关紧要,则可以使用流 groupingBy() 对任意数量的流进行比较,然后检查每个元素的计数。

          示例用于 IntStream,但您可以了解此方法背后的想法:

              IntStream stream1 = IntStream.range(1, 9);
              IntStream stream2 = IntStream.range(1, 10);
          
              boolean equal = IntStream.concat(stream1, stream2)
                      .boxed()
                      .collect(Collectors.groupingBy(Function.identity()))
                      .entrySet().stream().noneMatch(e -> e.getValue().size() != 2);
          

          【讨论】:

          • 或者更好地使用 collect(groupingBy(identity(),counting())).values().stream().noneMatch(count -> count != 2)
          【解决方案7】:

          做同样事情的另一种方式:

          static void assertStreamEquals(Stream<?> s1, Stream<?> s2) {
              Iterator<?> it2 = s2.iterator();
              assert s1.allMatch(o -> it2.hasNext() && Objects.equals(o, it2.next())) && !it2.hasNext();
          }
          

          【讨论】:

          • 如果 s1 是并行流怎么办? ;-)
          【解决方案8】:

          如何比较java 8及以上版本的两个流:以比较IntStream为例

          package com.techsqually.java.language.generics.basics;
          
          import java.util.Iterator;
          import java.util.stream.IntStream;
          import java.util.stream.Stream;
          
          public class TwoStreamComparision {
          
              public static void main(String[] args) {
          
                  String a = "Arpan";
                  String b = "Arpen";
          
                  IntStream s1 =  a.chars();
                  IntStream s2  = b.chars();
          
                  Iterator<Integer> s1It = s1.iterator();
                  Iterator<Integer> s2It = s2.iterator();
          
                  //Code to check how many characters are not equal in both the string at their Respective Position
                  int count = 0;
                  while (s2It.hasNext()){
                      if (!s1It.next().equals(s2It.next())){
                          count++;
                      }
                  }
                  System.out.println(count);
              }
          }
          

          【讨论】:

          • 我想你忘记检查流的长度是否不同。如果s1 更短,您的代码将崩溃,如果s2 更短,则给出错误结果。
          猜你喜欢
          • 2017-05-10
          • 1970-01-01
          • 1970-01-01
          • 2011-07-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-12
          相关资源
          最近更新 更多