{"id":9392,"date":"2013-03-05T13:00:03","date_gmt":"2013-03-05T11:00:03","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=9392"},"modified":"2013-03-05T06:29:16","modified_gmt":"2013-03-05T04:29:16","slug":"advanced-listenablefuture-capabilities","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html","title":{"rendered":"Advanced ListenableFuture capabilities"},"content":{"rendered":"<p>Last time we <a href=\"http:\/\/nurkiewicz.blogspot.no\/2013\/02\/listenablefuture-in-guava.html\">familiarized ourselves with <code>ListenableFuture<\/code><\/a>. I promised to introduced more advanced techniques, namely transformations and chaining. Let&#8217;s start from something straightforward. Say we have our <code>ListenableFuture&lt;String&gt;<\/code> which we got from some asynchronous service. We also have a simple method:<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<\/p>\n<pre class=\"brush:java\">Document parse(String xml) {\/\/...<\/pre>\n<p>We don&#8217;t need <code>String<\/code>, we need <code>Document<\/code>. One way would be to simply resolve <code>Future<\/code> (<i>wait<\/i> for it) and do the processing on <code>String<\/code>. But much more elegant solution is to apply transformation once the results are available and treat our method as if was always returning <code>ListenableFuture&lt;Document&gt;<\/code>. This is pretty straightforward:<\/p>\n<pre class=\"brush:java\">final ListenableFuture&lt;String&gt; future = \/\/...\r\n \r\nfinal ListenableFuture&lt;Document&gt; documentFuture = Futures.transform(future, new Function&lt;String, Document&gt;() {\r\n    @Override\r\n    public Document apply(String contents) {\r\n        return parse(contents);\r\n    }\r\n});<\/pre>\n<p>or more readable:<\/p>\n<pre class=\"brush:java\">final Function&lt;String, Document&gt; parseFun = new Function&lt;String, Document&gt;() {\r\n    @Override\r\n    public Document apply(String contents) {\r\n        return parse(contents);\r\n    }\r\n};\r\n \r\nfinal ListenableFuture&lt;String&gt; future = \/\/...\r\n \r\nfinal ListenableFuture&lt;Document&gt; documentFuture = Futures.transform(future, parseFun);<\/pre>\n<p>Java syntax is a bit limiting, but please focus on what we just did. <code>Futures.transform()<\/code> doesn&#8217;t wait for underlying <code>ListenableFuture&lt;String&gt;<\/code> to apply <code>parse()<\/code> transformation. Instead, under the hood, it registers a callback, wishing to be notified whenever given future finishes. This transformation is applied dynamically and transparently for us at right moment. We still have <code>Future<\/code>, but this time wrapping <code>Document<\/code>.<\/p>\n<p>So let&#8217;s go one step further. We also have an asynchronous, possibly long-running method that calculates <i>relevance<\/i> (whatever that is in this context) of a given <code>Document<\/code>:<\/p>\n<pre class=\"brush:java\">ListenableFuture<Double> calculateRelevance(Document pageContents) {\/\/...<\/pre>\n<p>Can we somehow chain it with <code>ListenableFuture&lt;Document&gt;<\/code> we already have? First attempt:<\/p>\n<pre class=\"brush:java\">final Function&lt;Document, ListenableFuture&lt;Double&gt;&gt; relevanceFun = new Function&lt;Document, ListenableFuture&lt;Double&gt;&gt;() {\r\n    @Override\r\n    public ListenableFuture&lt;Double&gt; apply(Document input) {\r\n        return calculateRelevance(input);\r\n    }\r\n};\r\n \r\nfinal ListenableFuture&lt;String&gt; future = \/\/...\r\nfinal ListenableFuture&lt;Document&gt; documentFuture = Futures.transform(future, parseFun);\r\nfinal ListenableFuture&lt;ListenableFuture&lt;Double&gt;&gt; relevanceFuture = Futures.transform(documentFuture, relevanceFun);<\/pre>\n<p>Ouch! <i>Future of future of <code>Double<\/code><\/i>, that doesn&#8217;t look good. Once we resolve outer future we need to wait for inner one as well. Definitely not elegant. Can we do better?<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<pre class=\"brush:java\">final AsyncFunction&lt;Document, Double&gt; relevanceAsyncFun = new AsyncFunction&lt;Document, Double&gt;() {\r\n    @Override\r\n    public ListenableFuture&lt;Double&gt; apply(Document pageContents) throws Exception {\r\n        return calculateRelevance(pageContents);\r\n    }\r\n};\r\n \r\nfinal ListenableFuture&lt;String&gt; future = \/\/comes from ListeningExecutorService\r\nfinal ListenableFuture&lt;Document&gt; documentFuture = Futures.transform(future, parseFun);\r\nfinal ListenableFuture&lt;Double&gt; relevanceFuture = Futures.transform(documentFuture, relevanceAsyncFun);<\/pre>\n<p>Please look very carefully at all types and results. Notice the difference between <code>Function<\/code> and <code>AsyncFunction<\/code>. Initially we got an asynchronous method returning future of <code>String<\/code>. Later on we transformed it to seamlessly turn <code>String<\/code> into XML <code>Document<\/code>. This transformation happens asynchronously, when inner future completes. Having future of <code>Document<\/code> we would like to call a method that requires <code>Document<\/code> and returns future of <code>Double<\/code>.<\/p>\n<p>If we call <code>relevanceFuture.get()<\/code>, our <code>Future<\/code> object will first wait for inner task to complete and having its result (<code>String<\/code> -&gt; <code>Document<\/code>) will wait for outer task and return <code>Double<\/code>. We can also register callbacks on <code>relevanceFuture<\/code> which will fire when outer task (<code>calculateRelevance()<\/code>) finishes. If you are still here, the are even more crazy transformations.<\/p>\n<p>Remember that all this happens in a loop. For each web site we got <code>ListenableFuture&lt;String&gt;<\/code> which we asynchronously transformed to <code>ListenableFuture&lt;Double&gt;<\/code>. So in the end we work with a <code>List&lt;ListenableFuture&lt;Double&gt;&gt;<\/code>. This also means that in order to extract all the results we either have to register listener for each and every <code>ListenableFuture<\/code> or wait for each of them. Which doesn&#8217;t progress us at all. But what if we could easily transform from <code>List&lt;ListenableFuture&lt;Double&gt;&gt;<\/code> to <code>ListenableFuture&lt;List&lt;Double&gt;&gt;<\/code>? Read carefully &#8211; from list of futures to future of list. In other words, rather than having a bunch of small futures we have one future that will complete when all child futures complete &#8211; and the results are mapped one-to-one to target list. Guess what, Guava can do this!<\/p>\n<pre class=\"brush:java\">final List&lt;ListenableFuture&lt;Double&gt;&gt; relevanceFutures = \/\/...;\r\nfinal ListenableFuture&lt;List&lt;Double&gt;&gt; futureOfRelevance = Futures.allAsList(relevanceFutures);<\/pre>\n<p>Of course there is no waiting here as well. Wrapper <code>ListenableFuture&lt;List&lt;Double&gt;&gt;<\/code> will be notified every time one of its <i>child<\/i> futures complete. The moment the last child <code>ListenableFuture&lt;Double&gt;<\/code> completes, outer future completes as well. Everything is event-driven and completely hidden from you.<\/p>\n<p>Do you think that&#8217;s it? Say we would like to compute the biggest relevance in the whole set. As you probably know by now, we won&#8217;t wait for a <code>List&lt;Double&gt;<\/code>. Instead we will register transformation from <code>List&lt;Double&gt;<\/code> to <code>Double<\/code>!<\/p>\n<pre class=\"brush:java\">final ListenableFuture&lt;Double&gt; maxRelevanceFuture = Futures.transform(futureOfRelevance, new Function&lt;List&lt;Double&gt;, Double&gt;() {\r\n    @Override\r\n    public Double apply(List&lt;Double&gt; relevanceList) {\r\n        return Collections.max(relevanceList);\r\n    }\r\n});<\/pre>\n<p>Finally, we can listen for completion event of <code>maxRelevanceFuture<\/code> and e.g. send results (asynchronously!) using JMS. Here is a complete code if you lost track:<\/p>\n<pre class=\"brush:java\">private Document parse(String xml) {\r\n    return \/\/...\r\n}\r\n \r\nprivate final Function&lt;String, Document&gt; parseFun = new Function&lt;String, Document&gt;() {\r\n    @Override\r\n    public Document apply(String contents) {\r\n        return parse(contents);\r\n    }\r\n};\r\n \r\nprivate ListenableFuture&lt;Double&gt; calculateRelevance(Document pageContents) {\r\n    return \/\/...\r\n}\r\n \r\nfinal AsyncFunction&lt;Document, Double&gt; relevanceAsyncFun = new AsyncFunction&lt;Document, Double&gt;() {\r\n    @Override\r\n    public ListenableFuture&lt;Double&gt; apply(Document pageContents) throws Exception {\r\n        return calculateRelevance(pageContents);\r\n    }\r\n};\r\n \r\n\/\/...\r\n \r\nfinal ListeningExecutorService pool = MoreExecutors.listeningDecorator(\r\n    Executors.newFixedThreadPool(10)\r\n);\r\n \r\nfinal List&lt;ListenableFuture&lt;Double&gt;&gt; relevanceFutures = new ArrayList&lt;&gt;(topSites.size());\r\nfor (final URL siteUrl : topSites) {\r\n    final ListenableFuture&lt;String&gt; future = pool.submit(new Callable&lt;String&gt;() {\r\n        @Override\r\n        public String call() throws Exception {\r\n            return IOUtils.toString(siteUrl, StandardCharsets.UTF_8);\r\n        }\r\n    });\r\n    final ListenableFuture&lt;Document&gt; documentFuture = Futures.transform(future, parseFun);\r\n    final ListenableFuture&lt;Double&gt; relevanceFuture = Futures.transform(documentFuture, relevanceAsyncFun);\r\n    relevanceFutures.add(relevanceFuture);\r\n}\r\n \r\nfinal ListenableFuture&lt;List&lt;Double&gt;&gt; futureOfRelevance = Futures.allAsList(relevanceFutures);\r\nfinal ListenableFuture&lt;Double&gt; maxRelevanceFuture = Futures.transform(futureOfRelevance, new Function&lt;List&lt;Double&gt;, Double&gt;() {\r\n    @Override\r\n    public Double apply(List&lt;Double&gt; relevanceList) {\r\n        return Collections.max(relevanceList);\r\n    }\r\n});\r\n \r\nFutures.addCallback(maxRelevanceFuture, new FutureCallback&lt;Double&gt;() {\r\n    @Override\r\n    public void onSuccess(Double result) {\r\n        log.debug(\"Result: {}\", result);\r\n    }\r\n \r\n    @Override\r\n    public void onFailure(Throwable t) {\r\n        log.error(\"Error :-(\", t);\r\n    }\r\n});<\/pre>\n<p>Was it worth it? <i>Yes<\/i> and <i>no<\/i>. <i>Yes<\/i>, because we learned some really important constructs and primitives used together with futures\/promises: chaining, mapping (transforming) and reducing. The solution is beautiful in terms of CPU utilization &#8211; no waiting, blocking, etc. Remember that the biggest strength of <a href=\"http:\/\/nodejs.org\/\">Node.js<\/a> is its &#8220;no-blocking&#8221; policy. Also in <a href=\"http:\/\/netty.io\/\">Netty<\/a> futures are ubiquitous. Last but not least, it feels very <i>functional<\/i>.<\/p>\n<p>On the other hand, mainly due to Java syntax verbosity and lack of type inference (yes, we will jump into Scala soon) code seems very unreadable, hard to follow and maintain. Well, to some degree this holds true for all message driven systems. But as long as we don&#8217;t invent better APIs and primitives, we must learn to live and take advantage of asynchronous, highly parallel computations.<\/p>\n<p>If you want to experiment with <code>ListenableFuture<\/code> even more, don&#8217;t forget to read <a href=\"http:\/\/code.google.com\/p\/guava-libraries\/wiki\/ListenableFutureExplained\">official documentation<\/a>.<br \/>\n&nbsp;<\/p>\n<p><b><i>Reference: <\/i><\/b><a href=\"http:\/\/nurkiewicz.blogspot.com\/2013\/02\/advanced-listenablefuture-capabilities.html\">Advanced ListenableFuture capabilities<\/a> from our <a href=\"http:\/\/www.javacodegeeks.com\/p\/jcg.html\">JCG partner<\/a> Tomasz Nurkiewicz at the <a href=\"http:\/\/nurkiewicz.blogspot.com\/\">NoBlogDefFound<\/a> blog.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time we familiarized ourselves with ListenableFuture. I promised to introduced more advanced techniques, namely transformations and chaining. Let&#8217;s start from something straightforward. Say we have our ListenableFuture&lt;String&gt; which we got from some asynchronous service. We also have a simple method: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Document parse(String xml) {\/\/&#8230; We don&#8217;t need &hellip;<\/p>\n","protected":false},"author":13,"featured_media":112,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[88,280],"class_list":["post-9392","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-concurrency","tag-google-guava"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Advanced ListenableFuture capabilities<\/title>\n<meta name=\"description\" content=\"Last time we familiarized ourselves with ListenableFuture. I promised to introduced more advanced techniques, namely transformations and chaining. Let&#039;s\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Advanced ListenableFuture capabilities\" \/>\n<meta property=\"og:description\" content=\"Last time we familiarized ourselves with ListenableFuture. I promised to introduced more advanced techniques, namely transformations and chaining. Let&#039;s\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2013-03-05T11:00:03+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Tomasz Nurkiewicz\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/tnurkiewicz\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Tomasz Nurkiewicz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html\"},\"author\":{\"name\":\"Tomasz Nurkiewicz\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/fb1be85725c10e8361e641fa851e79e1\"},\"headline\":\"Advanced ListenableFuture capabilities\",\"datePublished\":\"2013-03-05T11:00:03+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html\"},\"wordCount\":722,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"keywords\":[\"Concurrency\",\"Google Guava\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html\",\"name\":\"Advanced ListenableFuture capabilities\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"datePublished\":\"2013-03-05T11:00:03+00:00\",\"description\":\"Last time we familiarized ourselves with ListenableFuture. I promised to introduced more advanced techniques, namely transformations and chaining. Let's\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/enterprise-java-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"java-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2013\\\/03\\\/advanced-listenablefuture-capabilities.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Advanced ListenableFuture capabilities\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/fb1be85725c10e8361e641fa851e79e1\",\"name\":\"Tomasz Nurkiewicz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g\",\"caption\":\"Tomasz Nurkiewicz\"},\"description\":\"Java EE developer, Scala enthusiast. Enjoying data analysis and visualization. Strongly believes in the power of testing and automation.\",\"sameAs\":[\"http:\\\/\\\/nurkiewicz.blogspot.com\\\/\",\"https:\\\/\\\/x.com\\\/https:\\\/\\\/twitter.com\\\/tnurkiewicz\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/tomasz-nurkiewicz\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Advanced ListenableFuture capabilities","description":"Last time we familiarized ourselves with ListenableFuture. I promised to introduced more advanced techniques, namely transformations and chaining. Let's","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html","og_locale":"en_US","og_type":"article","og_title":"Advanced ListenableFuture capabilities","og_description":"Last time we familiarized ourselves with ListenableFuture. I promised to introduced more advanced techniques, namely transformations and chaining. Let's","og_url":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2013-03-05T11:00:03+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","type":"image\/jpeg"}],"author":"Tomasz Nurkiewicz","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/tnurkiewicz","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Tomasz Nurkiewicz","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html"},"author":{"name":"Tomasz Nurkiewicz","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/fb1be85725c10e8361e641fa851e79e1"},"headline":"Advanced ListenableFuture capabilities","datePublished":"2013-03-05T11:00:03+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html"},"wordCount":722,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","keywords":["Concurrency","Google Guava"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html","url":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html","name":"Advanced ListenableFuture capabilities","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","datePublished":"2013-03-05T11:00:03+00:00","description":"Last time we familiarized ourselves with ListenableFuture. I promised to introduced more advanced techniques, namely transformations and chaining. Let's","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/enterprise-java-logo.jpg","width":150,"height":150,"caption":"java-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2013\/03\/advanced-listenablefuture-capabilities.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Advanced ListenableFuture capabilities"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/fb1be85725c10e8361e641fa851e79e1","name":"Tomasz Nurkiewicz","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f2a8f9f1060fc7c1161c42f8ba901e0e79fb767dec39ec34b2d3b95cab9dc728?s=96&d=mm&r=g","caption":"Tomasz Nurkiewicz"},"description":"Java EE developer, Scala enthusiast. Enjoying data analysis and visualization. Strongly believes in the power of testing and automation.","sameAs":["http:\/\/nurkiewicz.blogspot.com\/","https:\/\/x.com\/https:\/\/twitter.com\/tnurkiewicz"],"url":"https:\/\/www.javacodegeeks.com\/author\/tomasz-nurkiewicz"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/9392","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=9392"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/9392\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/112"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=9392"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=9392"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=9392"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}