From c6792532e27f719e8c1674a18f9ff8143dfb1ca3 Mon Sep 17 00:00:00 2001 From: Noa Resare Date: Sun, 22 Feb 2015 10:12:55 +0100 Subject: [PATCH 1/3] break lines in README.md --- README.md | 54 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 176015d..f31aea7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ### Futures-extra -Futures-extra is a set of small utility functions to simplify working with Guava's ListenableFuture class +Futures-extra is a set of small utility functions to simplify working with +Guava's ListenableFuture class ### Build status @@ -29,7 +30,8 @@ To import it with maven, use this: ### Examples #### Cleaner transforms for Java 8. -Java 8 introduced lambdas which can greatly reduce verbosity in code, which is great when using futures and transforms. +Java 8 introduced lambdas which can greatly reduce verbosity in code, which is +great when using futures and transforms. Ideally you would want to do something like this: ```java @@ -38,8 +40,10 @@ public static ListenableFuture example(ListenableFuture future) { } ``` -This doesn't actually work though, because Futures.transform has two variants: one that takes a Function and one that takes an AsyncFunction. -Hence the compiler can't determine which variant to use without additional type information. +This doesn't actually work though, because Futures.transform has two variants: +one that takes a Function and one that takes an AsyncFunction. +Hence the compiler can't determine which variant to use without additional +type information. To work around that you have to cast it like this: ```java @@ -55,15 +59,18 @@ public static ListenableFuture example(ListenableFuture future) { } ``` -This is just a simple delegating method that explicitly calls Futures.transform(future, Function). -There is also a corresponding FuturesExtra.asyncTransform that calls Futures.transform(future, AsyncFunction). +This is just a simple delegating method that explicitly calls +Futures.transform(future, Function). There is also a corresponding +FuturesExtra.asyncTransform that calls Futures.transform(future, AsyncFunction). #### Joining multiple futures A common use case is waiting for two or more futures and then transforming the -result to something else. You can do this in a couple of different ways, here are two of them: +result to something else. You can do this in a couple of different ways, here +are two of them: -The examples are for Java 8, but they also work for Java 6 and 7 (though it becomes more verbose). +The examples are for Java 8, but they also work for Java 6 and 7 (though it +becomes more verbose). ```java final ListenableFuture futureA = getFutureA(); @@ -72,7 +79,8 @@ final ListenableFuture futureB = getFutureB(); return Futures.transform(Futures.allAsList(futureA, futureB), list -> combine((A) list.get(0), (B) list.get(1)); ``` -This one has the problem that you have to manually make sure that the casts and ordering are correct, otherwise you will get ClassCastException. +This one has the problem that you have to manually make sure that the casts and +ordering are correct, otherwise you will get ClassCastException. You could also do this one instead to avoid casts: ```java @@ -82,8 +90,11 @@ final ListenableFuture futureB = getFutureB(); return Futures.transform(Futures.allAsList(futureA, futureB), list -> combine(getUnchecked(futureA), getUnchecked(futureB)); ``` -Now you instead need to make sure that the futures in the transform input are the same as the ones you getUnchecked. -If you fail to do this, things may work anyway (which is a good way of hiding bugs), but block the thread, actually removing the asynchronous advantage. Even worse - the future may never finish, blocking the thread forever. +Now you instead need to make sure that the futures in the transform input are +the same as the ones you getUnchecked. If you fail to do this, things may work +anyway (which is a good way of hiding bugs), but block the thread, actually +removing the asynchronous advantage. Even worse - the future may never finish, +blocking the thread forever. To simplify these use cases we have a couple of helper functions: ```java @@ -94,9 +105,12 @@ return FuturesExtra.syncTransform2(futureA, futureB, (a, b) -> combine(a, b)); ``` -This is much clearer! We don't need any type information because the lambda can infer it, and we avoid the potential bugs that can occur as a result of the first to examples. +This is much clearer! We don't need any type information because the lambda can +infer it, and we avoid the potential bugs that can occur as a result of the +first to examples. -The tuple transform can be used up to 6 arguments. If you need more than that, some refactoring is likely in place, but you can also use the JoinedResult: +The tuple transform can be used up to 6 arguments. If you need more than that, +some refactoring is likely in place, but you can also use the JoinedResult: ```java final ListenableFuture futureA = getFutureA(); @@ -107,13 +121,16 @@ return Futures.transform(futureJoined, joined -> combine(joined.get(futureA), joined.get(futureB))); ``` -This supports an arbitrary number of futures, but is slightly more complex. However, it is much safer than the first two examples, -because joined.get(...) will fail if you try to get the value of a future that was not part of the input. +This supports an arbitrary number of futures, but is slightly more complex. +However, it is much safer than the first two examples, because joined.get(...) +will fail if you try to get the value of a future that was not part of the +input. #### Timeouts -Sometimes you want to stop waiting for a future after a specific timeout and to do this you generally need to have some sort of scheduling involved. -To simplify that, you can use this: +Sometimes you want to stop waiting for a future after a specific timeout and to +do this you generally need to have some sort of scheduling involved. To simplify +that, you can use this: ```java final ListenableFuture future = getFuture(); final ListenableFuture futureWithTimeout = FuturesExtra.makeTimeoutFuture(scheduledExecutor, future, 100, TimeUnit.MILLISECONDS); @@ -121,7 +138,8 @@ final ListenableFuture futureWithTimeout = FuturesExtra.makeTimeoutFuture(sch #### Select -If you have some futures and want to succeed as soon as the first one succeeds, you can use select: +If you have some futures and want to succeed as soon as the first one succeeds, +you can use select: ```java final List> futures = getFutures(); final ListenableFuture firstSuccessful = FuturesExtra.select(futures); From 8f17a065ad9ab1e15ece9e77f9248ae31896f038 Mon Sep 17 00:00:00 2001 From: Noa Resare Date: Sun, 22 Feb 2015 12:56:06 +0100 Subject: [PATCH 2/3] README.md updates * FuturesExtra.join returns JoinedResults not JoinedResult * Language updates and a bit of clarification * Added type information to the lambdas that makes the example code for joining futures compile. --- README.md | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index f31aea7..25fc2e2 100644 --- a/README.md +++ b/README.md @@ -31,21 +31,25 @@ To import it with maven, use this: #### Cleaner transforms for Java 8. Java 8 introduced lambdas which can greatly reduce verbosity in code, which is -great when using futures and transforms. +great when using futures and transforms. One drawback with lambdas though is +that when a lambda is supplied as an argument to a method with overloaded +parameters, the compiler may fail to figure out which variant of a method call +that is intended to be used. -Ideally you would want to do something like this: +Ideally, applying java 8 lambdas to Guava's Futures.transform() would look +something like this: ```java public static ListenableFuture example(ListenableFuture future) { return Futures.transform(future, a -> toB(a)); } ``` -This doesn't actually work though, because Futures.transform has two variants: -one that takes a Function and one that takes an AsyncFunction. -Hence the compiler can't determine which variant to use without additional -type information. +Unfortunately this doesn't actually work because Futures.transform has +two variants: one that takes a Function as it's second parameter and one that +takes an AsyncFunction. The compiler can't determine which variant to use +without additional type information. -To work around that you have to cast it like this: +You could work around that you have to cast it like this: ```java public static ListenableFuture example(ListenableFuture future) { return Futures.transform(future, (Function) a -> toB(a)); @@ -76,19 +80,21 @@ becomes more verbose). final ListenableFuture futureA = getFutureA(); final ListenableFuture futureB = getFutureB(); -return Futures.transform(Futures.allAsList(futureA, futureB), - list -> combine((A) list.get(0), (B) list.get(1)); +ListenableFuture ret = Futures.transform(Futures.allAsList(futureA, futureB), + (Function, C>)list -> combine((A) list.get(0), (B) list.get(1)); ``` +where combine is a method with parameters of type A and B returning C. + This one has the problem that you have to manually make sure that the casts and ordering are correct, otherwise you will get ClassCastException. -You could also do this one instead to avoid casts: +You could also access the futures directly to avoid casts: ```java final ListenableFuture futureA = getFutureA(); final ListenableFuture futureB = getFutureB(); -return Futures.transform(Futures.allAsList(futureA, futureB), - list -> combine(getUnchecked(futureA), getUnchecked(futureB)); +ListenableFuture ret = Futures.transform(Futures.allAsList(futureA, futureB), + (Function, C>)list -> combine(Futures.getUnchecked(futureA), Futures.getUnchecked(futureB)); ``` Now you instead need to make sure that the futures in the transform input are the same as the ones you getUnchecked. If you fail to do this, things may work @@ -101,7 +107,7 @@ To simplify these use cases we have a couple of helper functions: final ListenableFuture futureA = getFutureA(); final ListenableFuture futureB = getFutureB(); -return FuturesExtra.syncTransform2(futureA, futureB, +ListenableFuture FuturesExtra.syncTransform2(futureA, futureB, (a, b) -> combine(a, b)); ``` @@ -109,14 +115,15 @@ This is much clearer! We don't need any type information because the lambda can infer it, and we avoid the potential bugs that can occur as a result of the first to examples. -The tuple transform can be used up to 6 arguments. If you need more than that, -some refactoring is likely in place, but you can also use the JoinedResult: +The tuple transform can be used up to 6 arguments named syncTransform2() through +syncTransform6(). If you need more than that you could probably benefit from +some refactoring, but you can also use FuturesExtra.join(): ```java final ListenableFuture futureA = getFutureA(); final ListenableFuture futureB = getFutureB(); -final ListenableFuture futureJoined = FuturesExtra.join(futureA, futureB); +final ListenableFuture futureJoined = FuturesExtra.join(futureA, futureB); return Futures.transform(futureJoined, joined -> combine(joined.get(futureA), joined.get(futureB))); ``` From 22219a9d069364b7333d62de38435163a99b0f83 Mon Sep 17 00:00:00 2001 From: Noa Resare Date: Sun, 22 Feb 2015 19:09:20 +0100 Subject: [PATCH 3/3] Minor README.md updates --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 25fc2e2..acdb8b5 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,11 @@ public static ListenableFuture example(ListenableFuture future) { ``` Unfortunately this doesn't actually work because Futures.transform has -two variants: one that takes a Function as it's second parameter and one that +two variants: one that takes a Function as its second parameter and one that takes an AsyncFunction. The compiler can't determine which variant to use without additional type information. -You could work around that you have to cast it like this: +You could work around that by casting it like this: ```java public static ListenableFuture example(ListenableFuture future) { return Futures.transform(future, (Function) a -> toB(a)); @@ -107,7 +107,7 @@ To simplify these use cases we have a couple of helper functions: final ListenableFuture futureA = getFutureA(); final ListenableFuture futureB = getFutureB(); -ListenableFuture FuturesExtra.syncTransform2(futureA, futureB, +ListenableFuture ret = FuturesExtra.syncTransform2(futureA, futureB, (a, b) -> combine(a, b)); ```