“This is the 21st day of my participation in the Gwen Challenge in November. See details of the event: The Last Gwen Challenge 2021”.

preface

Hello everyone, I’m Llamy. Streaming computing has always been a problem that appears frequently in Java interview. Today’s “Interview God” series will talk about the implementation of Java stream merge.

Plain Java methods

The JDK 8 Stream class has some useful static methods. Such as concat () :

Merge two streams

@Test 
public void merge(a) { 
    Stream<Integer> stream1 = Stream.of(1.3.5); 
    Stream<Integer> stream2 = Stream.of(2.4.6); 
    
    Stream<Integer> resultingStream = Stream.concat(stream1, stream2); 
    
    assertEquals( 
        Arrays.asList(1.3.5.2.4.6), 
        resultingStream.collect(Collectors.toList())); 
}
Copy the code

Merging multiple streams

When we merge multiple streams, things get a little more complicated. One possible approach is to merge the first two flows and then use the merge result to merge the other flows.

Such as:

@Test 
public void merge(a) { 
    Stream<Integer> stream1 = Stream.of(1.3.5); 
    Stream<Integer> stream2 = Stream.of(2.4.6); 
    Stream<Integer> stream3 = Stream.of(18.15.36);
    
    Stream<Integer> resultingStream = Stream.concat( 
       Stream.concat(stream1, stream2), stream3);
    
    assertEquals( 
        Arrays.asList(1.3.5.2.4.6.18.15.36),
        resultingStream.collect(Collectors.toList())); 
}
Copy the code

This method is not feasible for more rheologies. Of course, we could create intermediate variables or helper methods to make it more readable, but there is a better way:

@Test 
public void merge(a) { 
    Stream<Integer> stream1 = Stream.of(1.3.5); 
    Stream<Integer> stream2 = Stream.of(2.4.6); 
    Stream<Integer> stream3 = Stream.of(18.15.36); 
    Stream<Integer> stream4 = Stream.of(99); 
    
    Stream<Integer> resultingStream = Stream.of( 
        stream1, stream2, stream3, stream4) 
        .flatMap(i -> i); 

    assertEquals( 
        Arrays.asList(1.3.5.2.4.6.18.15.36.99), 
        resultingStream.collect(Collectors.toList())); 
}
Copy the code

It goes through two steps:

  • Start by creating a new Stream with four Streams and generate a nested Stream
  • And then we use the identity functionflatMap()Into the Stream

Using StreamEx

StreamEx is an open source Java library that extends the possibilities of Java 8 Streams. It uses the StreamEx class as an enhancement to the Stream interface of the JDK.

Combined flow

The StreamEx library allows us to merge streams using the append() instance method:

@Test 
public void merge(a) { 
    Stream<Integer> stream1 = Stream.of(1.3.5); 
    Stream<Integer> stream2 = Stream.of(2.4.6); 
    Stream<Integer> stream3 = Stream.of(18.15.36); 
    Stream<Integer> stream4 = Stream.of(99); 
    
    Stream<Integer> resultingStream = StreamEx.of(stream1) 
        .append(stream2) 
        .append(stream3) 
        .append(stream4); 
    
    assertEquals( 
        Arrays.asList(1.3.5.2.4.6.18.15.36.99), 
        resultingStream.collect(Collectors.toList())); 
}
Copy the code

Because it is an instance method, we can easily link it together and attach multiple Streams.

Use prepend() to merge streams

StreamEx also contains a method that adds an element before another, called prepend() :

@Test 
public void merge(a) { 
    Stream<String> stream1 = Stream.of("foo"."bar");
    Stream<String> openingBracketStream = Stream.of("[");
    Stream<String> closingBracketStream = Stream.of("]");
    
    Stream<String> resultingStream = StreamEx.of(stream1) 
        .append(closingBracketStream) 
        .prepend(openingBracketStream); 
    
    assertEquals( 
        Arrays.asList("["."foo"."bar"."]"), 
        resultingStream.collect(Collectors.toList())); 
}
Copy the code

Using Joo lambda.

Joo λ is a JDK 8 compatible library that provides useful extensions to the JDK. The most important flow abstraction here is called SEQ. Note that this is a sequential and ordered stream, so calling parallel() will have no effect.

Combined flow

Like the StreamEx library, jooλ has an append() method:

@Test 
public void merge(a) { 
    Stream<Integer> seq1 = Stream.of(1.3.5); 
    Stream<Integer> seq2 = Stream.of(2.4.6); 

    Stream<Integer> resultingSeq = Seq.ofType(seq1, Integer.class) 
        .append(seq2); 

    assertEquals( 
        Arrays.asList(1.3.5.2.4.6), 
        resultingSeq.collect(Collectors.toList())); 
}
Copy the code

Use prepend() to merge streams

@Test 
public void merge(a) { 
    Stream<String> seq = Stream.of("foo"."bar");
    Stream<String> openingBracketStream = Stream.of("[");
    Stream<String> closingBracketStream = Stream.of("]");
    
    Stream<String> resultingStream = Seq.ofType(seq, String.class)
        .append(closingBracketStream) 
        .prepend(openingBracketStream); 
    
    assertEquals( 
        Arrays.asList("["."foo"."bar"."]"), 
        resultingStream.collect(Collectors.toList())); 
}
Copy the code

conclusion

It’s easy to merge two streams using JDK 8, but when we need to merge multiple streams using SteamEx or the JOOλ library we can append streams by append(), which is much more readable.