Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to search between two Streams in Java 8

If I have 2 Streams like coming in a method as shown below

public Stream<Transaction> getPendingTransaction(Stream<PendingTransaction> pendingTransactionStream,Stream<ProcessedTransaction> processedTransactionStream){ }

and I want to find all objects which are present in pendingTransactionStream which are also present in processedTransactionStream based upon some criteria like

if transaction.getId() is same for an Transaction object present in pendingTransactionStream and processedTransactionStreamthen that object is same and we can collect them in a list.

I tried doing like this but its giving error

processedTransactionStream
        .filter( (processedTransaction)->
        {
            pendingTransactionStream.anyMatch(s->s.getTransactionId().equals(processedTransaction.getTransactionId()) );
        } 
        ).collect(Collectors.toList());
like image 923
saum22 Avatar asked Jan 15 '19 07:01

saum22


People also ask

What are two types of streams in Java 8?

With Java 8, Collection interface has two methods to generate a Stream. stream() − Returns a sequential stream considering collection as its source. parallelStream() − Returns a parallel Stream considering collection as its source.

What does .stream do in Java?

Introduced in Java 8, the Stream API is used to process collections of objects. A stream is a sequence of objects that supports various methods which can be pipelined to produce the desired result. A stream is not a data structure instead it takes input from the Collections, Arrays or I/O channels.

Does Java 8 have streams?

Java 8 offers the possibility to create streams out of three primitive types: int, long and double. As Stream<T> is a generic interface, and there is no way to use primitives as a type parameter with generics, three new special interfaces were created: IntStream, LongStream, DoubleStream.

How do I combine two streams in Java?

concat() in Java. Stream. concat() method creates a concatenated stream in which the elements are all the elements of the first stream followed by all the elements of the second stream. The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel.


2 Answers

Well, you can't consume the pendingTransactionStream Stream multiple times. You can transform it to a List (or even better, a Set) of transaction IDs to use in the filter method.

Set<String> pending = pendingTransactionStream.map(PendingTransaction::getTransactionId)
                                              .collect(Collectors.toSet());
List<ProcessedTransaction> processed = 
    processedTransactionStream.filter(pt -> pending.contains(pt.getTransactionId()))
                              .collect(Collectors.toList());
like image 170
Eran Avatar answered Sep 25 '22 15:09

Eran


You can't iterate Streams more than once. So your current code doesn't work (you get an exception like IllegalStateException: Stream already closed. From the java doc:

A stream should be operated on (invoking an intermediate or terminal stream operation) only once.

A possible solution would be to convert the pendingTransactionStream into a map where the key is the type of the id (I use string, because I don't know the keyType):

Actually a Set would be better as you don't need the PendingTransaction for anything else, for an example have a look at @Eran's answer

Map<String, PendingTransaction> pendingTransactionMap = pendingTransactionStream
    .collect(PendingTransaction::getId, Function.identity());

And then filter your processedTransactionStream, by checking if the id is in the map:

List<ProcessedTransaction> processedTransactionList = processedTransactionStream
    .filter(p -> pendingTransactionMap.containsKey(p.getId()))
    .collect(Collectors.toList());
like image 45
Lino Avatar answered Sep 26 '22 15:09

Lino