简体   繁体   中英

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.

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

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

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

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM