How to compare two Streams in Java 8

What would be a good way to compare two Stream instances in Java 8 and find out whether they have the same elements, specifically for purposes of unit testing?

What I've got now is:

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

or alternatively:

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

But that means I'm constructing two collections and discarding them. It's not a performance issue, given the size of my test streams, but I'm wondering whether there's a canonical way to compare two streams.

4

8 Answers

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(); } 
2

Collecting the stream under test (as you show) is a straightforward and effective way of performing the test. You may create the list of expected results in the easiest way available, which might not be collecting a stream.

Alternatively, with most libraries for creating mock collaborators, one could mock a Consumer that "expects" a series of accept() calls with particular elements. Consume the Stream with it, and then "verify" that its configured expectations were met.

Using the elementsEqual method in the Guava library:

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

You can assert the stream's content without creating a Stream<> expected.

AssertJ has fluent and readable solutions for this.

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); } } 
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); } 

If order of elements doesn't matter, then comparison can be done for any number of streams using stream groupingBy() and then checking count for each element.

Example is for IntStream but you can get the idea behind this method:

 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); 
1

Another way of doing the same thing:

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

How to Compare Two Streams in java 8 and above: with the example of Comparing 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); } } 
1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like