Use the results of two different types of Guava ListenableFutures

I have two ListenableFutures that are terminated on other threads. Each future has a different type, and I want to use both of their results when they are both full.

Is there an elegant way to handle this with Guava?

+8
java guava future
source share
4 answers
Runnable listener = new Runnable() { private boolean jobDone = false; @Override public synchronized void run() { if (jobDone || !(future1.isDone() && future2.isDone())) { return; } jobDone = true; // TODO do your job } }; future1.addListener(listener); future2.addListener(listener); 

Not very elegant, but should do the job.

Or, more elegantly, but you will need castes:

 ListenableFuture<List<Object>> composedFuture = Futures.allAsList(future1, future2); 
+1
source share

If you want some type of security, you can do the following:

 class Composite { public A a; public B b; } public ListenableFuture<Composite> combine(ListenableFuture<A> futureA, final ListenableFuture<B> futureB) { return Futures.transform(futureA, new AsyncFunction<A, Composite>() { public ListenableFuture<Composite> apply(final A a) throws Exception { return Futures.transform(futureB, new Function<B, Compisite>() { public Composite apply(B b) { return new Composite(a, b); } } } } } ListenableFuture<A> futureA = ... ListenableFuture<B> futureB = ... ListenableFuture<Composite> result = combine(futureA, futureB); 

In this case, the Composite can be Pair<A, B> from Apache Commons, if you want.

In addition, a failure in any future will result in a failure in the resulting consolidated future.

Another solution would be to take a look at Trickle from the Spotify team. GitHub README has an example that shows a solution to a similar problem.

There are undoubtedly other solutions, but this is the one that appeared in my head.

+8
source share

If you want some type safety, you can combine the result of two different independent tasks using the EventBus from the Guava sister com.google.common.eventbus package

As an example, let's assume that one of you Futures returns Integer , and the other Double .

First, create a drive class (another name builder, collector, etc.) that you register as an event receiver with EventBus. As you can see, this is really a POJO, which will be an Integer and Double event

 class Accumulator { Integer intResult; Double doubleResult; @Subscribe // This annotation makes it an event handler public void setIntResult ( final Integer val ) { intResult = val; } @Subscribe public void setDoubleResult ( final Double val ) { doubleResult = val; } } 

Here is an implementation of a method that takes 2 futures and combines them into a battery.

 final ListenableFuture< Integer > future1 = ...; final ListenableFuture< Double > future2 = ...; final ImmutableList< ListenableFuture< ? extends Object> > futures = ImmutableList.< ListenableFuture<? extends Object> >of( future1, future2 ); final ListenableFuture< Accumulator > resultFuture = Futures.transform( // If you don't care about failures, use allAsList Futures.successfulAsList( futures ), new Function< List<Object>, Accumulator > ( ) { @Override public Accumulator apply ( final List< Object > input ) { final Accumulator accumulator = new Accumulator( ); final EventBus eventBus = new EventBus( ); eventBus.register( accumulator ); for ( final Object cur: input ) { // Failed results will be set to null if ( cur != null ) { eventBus.post( cur ); } } return accumulator; } } ); final Accumulator accumulator = resultFuture.get( ); 
0
source share

Here is a simple example that will add 2 listening futures:

 //Asynchronous call to get first value final ListenableFuture<Integer> futureValue1 = ...; //Take the result of futureValue1 and transform it into a function to get the second value final AsyncFunction<Integer, Integer> getSecondValueAndSumFunction = new AsyncFunction<Integer, Integer>() { @Override public ListenableFuture<Integer> apply(final Integer value1) { //Asynchronous call to get second value final ListenableFuture<Integer> futureValue2 = ...; //Return the sum of the values final Function<Integer, Integer> addValuesFuture = new Function<Integer, Integer>() { @Override public Integer apply(Integer value2) { Integer sum = value1 + value2; return sum; } }; //Transform the second value so its value can be added to the first final ListenableFuture<Integer> sumFuture = Futures.transform(futureValue2, addValuesFuture); return sumFuture; } }; final ListenableFuture<Integer> valueOnePlusValueTwo = Futures.transform(futureValue1, getSecondValueAndSumFunction); 
0
source share

All Articles