The Java 8 Stream.concat() method merges two streams into one stream. The combined stream consists of all the elements of both streams.
If either of the streams is a parallel stream, the resulting stream will also be a parallel stream. Be careful when combining parallel and sequential streams because this may affect performance and behavior.
The concat() method is useful in the following usecases:
- Combining results from different data sources.
- Merging multiple streams into one for unified processing.
- Concatenating static data with dynamically generated data.
1. Stream concat() Method
The concat() method is a static method in Stream class. Its method signature is:
static <T> Stream<T> concat(Stream<? extends T> firstStream, Stream<? extends T> secondStream)
- It creates a lazily concatenated stream whose elements are all the elements of the firstStream followed by all the elements of the secondStream.
- The resulting stream is ordered if both of the input streams are ordered.
- The resulting stream is parallel if either of the input streams is parallel.
- When the resulting stream is closed, the close handlers for both input streams are invoked.
2. Merge Two Streams using Stream.concat()
Java example to merge two streams of numbers – to obtain a stream that contains numbers from both streams.
Stream<Integer> firstStream = Stream.of(1, 2, 3);
Stream<Integer> secondStream = Stream.of(4, 5, 6);
Stream<Integer> resultingStream = Stream.concat(firstStream, secondStream);
System.out.println( resultingStream.toList() );
Program Output.
[1, 2, 3, 4, 5, 6]
3. Combining Multiple Streams using Stream.concat()
Java example to merge four streams of numbers – to obtain a stream that contains numbers from all streams. Notice we have made a static import to Stream.concat() function which makes the code readable.
Stream<Integer> first = Stream.of(1, 2);
Stream<Integer> second = Stream.of(3,4);
Stream<Integer> third = Stream.of(5, 6);
Stream<Integer> fourth = Stream.of(7,8);
Stream<Integer> resultingStream = Stream.concat(first, concat(second, concat(third, fourth)));
System.out.println( resultingStream.toList() );
Program Output.
[1, 2, 3, 4, 5, 6, 7, 8]
4. Combining Streams without Duplicate Elements
4.1. Using distinct() with Primitives and Strings
While merging two streams, we can use distinct() API and the resulting stream will contain only the unique elements.
Stream<Integer> firstStream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> secondStream = Stream.of(4, 5, 6, 7, 8, 9);
Stream<Integer> resultingStream = Stream.concat(firstStream, secondStream).distinct();
System.out.println( resultingStream.toList() );
Program Output.
[1, 2, 3, 4, 5, 6, 7, 8, 9]
4.2. Custom Equality Check for User-defined Objects
In case of merging streams of custom objects, we can drop the duplicate elements during stream iteration. We can use the distinctByKey() function created for java stream distinct by object property example.
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main
{
public static void main(String[] args)
{
Stream<Employee> stream1 = getEmployeeListOne().stream();
Stream<Employee> stream2 = getEmployeeListTwo().stream();
Stream<Employee> resultingStream = Stream.concat(stream1, stream2)
.filter(distinctByKey(Employee::getFirstName));
System.out.println( resultingStream.collect(Collectors.toList()) );
}
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor)
{
Map<Object, Boolean> map = new ConcurrentHashMap<>();
return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
private static ArrayList<Employee> getEmployeeListOne()
{
ArrayList<Employee> list = new ArrayList<>();
list.add( new Employee(1l, "Lokesh", "Gupta") );
list.add( new Employee(5l, "Brian", "Piper") );
list.add( new Employee(7l, "Charles", "Piper") );
list.add( new Employee(6l, "David", "Beckham") );
return list;
}
private static ArrayList<Employee> getEmployeeListTwo()
{
ArrayList<Employee> list = new ArrayList<>();
list.add( new Employee(2l, "Lokesh", "Gupta") );
list.add( new Employee(4l, "Brian", "Piper") );
list.add( new Employee(3l, "David", "Beckham") );
return list;
}
}
Program Output.
[Employee [id=1, firstName=Lokesh, lastName=Gupta],
Employee [id=5, firstName=Brian, lastName=Piper],
Employee [id=7, firstName=Charles, lastName=Piper],
Employee [id=6, firstName=David, lastName=Beckham]]
Drop me your questions in the comments section related to merging two or more streams of objects in Java 8.
Happy Learning !!
Reference: Stream concat() API Docs
Comments