Vlad
Vlad

Reputation: 18633

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.

Upvotes: 51

Views: 44466

Answers (8)

ETO
ETO

Reputation: 7279

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

Upvotes: 1

Mihail
Mihail

Reputation: 390

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

Upvotes: 2

Marc Dzaebel
Marc Dzaebel

Reputation: 435

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

Upvotes: 2

ZhongYu
ZhongYu

Reputation: 19682

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

Upvotes: 43

Frank Neblung
Frank Neblung

Reputation: 3175

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

Upvotes: 2

Arpan Saini
Arpan Saini

Reputation: 5191

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

Upvotes: -1

Lii
Lii

Reputation: 12112

Using the elementsEqual method in the Guava library:

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

Upvotes: 4

erickson
erickson

Reputation: 269667

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.

Upvotes: 4

Related Questions