<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 14 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:"Trebuchet MS";
        panose-1:2 11 6 3 2 2 2 2 2 4;}
@font-face
        {font-family:Tahoma;
        panose-1:2 11 6 4 3 5 4 4 2 4;}
@font-face
        {font-family:Consolas;
        panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:12.0pt;
        font-family:"Times New Roman","serif";
        color:black;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
pre
        {mso-style-priority:99;
        mso-style-link:"HTML Vorformatiert Zchn";
        margin:0cm;
        margin-bottom:.0001pt;
        font-size:10.0pt;
        font-family:"Courier New";
        color:black;}
span.HTMLVorformatiertZchn
        {mso-style-name:"HTML Vorformatiert Zchn";
        mso-style-priority:99;
        mso-style-link:"HTML Vorformatiert";
        font-family:Consolas;
        color:black;}
span.E-MailFormatvorlage19
        {mso-style-type:personal-reply;
        font-family:"Trebuchet MS","sans-serif";
        color:blue;
        font-weight:normal;
        font-style:normal;
        text-decoration:none none;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body bgcolor="white" lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue">Hello Peter,<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue">thank you for this excellent post! I now understand how layered exception handling works with CompletableFutures. The key point I wasn’t aware of is that
 exceptionally() can just pass on CompletionExceptions.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue">I do not need the SupplierX interface, I just use Callable, and I call the utility toSupplier(), which is a bit more specific. Given that CompletableFuture
 already does all this exception magic, I really don’t understand why there is no supplyAsync(Callable) method in the standard interface.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue">I like
</span>unwrapWrap (again <span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue">
except for its name, perhaps call it unwrapX, or unwrapCE ?). I particularly like the try-catch-idiom using unwrap inside exceptionally(), and the neat way it avoids peppering instanceof all over the place. Also nice is that the interface FunctionX can remain
 private in a utility class exposing these static helper methods.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue">Sebastian<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:10.0pt;font-family:"Trebuchet MS","sans-serif";color:blue"><o:p> </o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal"><b><span lang="DE" style="font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext">From:</span></b><span lang="DE" style="font-size:10.0pt;font-family:"Tahoma","sans-serif";color:windowtext"> Peter Levart [mailto:peter.levart@gmail.com]
<br>
<b>Sent:</b> Wednesday, August 27, 2014 3:56 PM<br>
<b>To:</b> Millies, Sebastian; concurrency-interest@cs.oswego.edu<br>
<b>Subject:</b> Re: [concurrency-interest] Layered exception handling with CompletableFuture<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<p class="MsoNormal">On 08/27/2014 10:39 AM, Millies, Sebastian wrote:<o:p></o:p></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<pre>So I find myself wrapping all the Callables, and tunneling the exceptions with RuntimeException, as Doug Lea recommends.<o:p></o:p></pre>
</blockquote>
<p class="MsoNormal" style="margin-bottom:12.0pt"><br>
The interesting part of javadoc for CompletionStage is the following:<br>
<br>
- Two method forms support processing whether the triggering stage completed normally or exceptionally: Method
<i>whenComplete</i> allows injection of an action regardless of outcome, otherwise preserving the outcome in its completion. Method
<i>handle</i> additionally allows the stage to compute a replacement result that may enable further processing by other dependent stages. In all other cases, if a stage's computation terminates abruptly with an (unchecked) exception or error, then all dependent
 stages requiring its completion complete exceptionally as well, with a <b><i>CompletionException</i></b> holding the exception as its cause.<br>
<br>
So If you do the following:<br>
<br>
        CompletableFuture.supplyAsync(() -> {<br>
            throw new IllegalStateException();<br>
        }).whenComplete((x, t) -> {<br>
            System.out.println("Result: " + x + "\nException: " + t);<br>
        });<br>
<br>
...you will get:<br>
<br>
Result: null<br>
Exception: java.util.concurrent.CompletionException: java.lang.IllegalStateException<br>
<br>
So if stage funcition/supplier throws an (unchecked) exception, it is always wrapped with CompletionException as stage outcome. The signature of exception handling functions passed to CompletionStage methods declares plain Throwable, but at least CompletableFuture
 seems to always arange so that CompletionException is passed to those functions unless you call methods like completeExceptionally on it. You can use this to your advantage (will get to that shortly)...<br>
<br>
Another "implementation detail" of CompletableFuture is evident if you try this:<br>
<br>
        CompletableFuture.supplyAsync(() -> {<br>
            throw new CompletionException(new Exception("I'm checked exception"));<br>
        }).whenComplete((x, t) -> {<br>
            System.out.println("Result: " + x + "\nException: " + t);<br>
        });<br>
<br>
...you will get:<br>
<br>
Result: null<br>
Exception: java.util.concurrent.CompletionException: java.lang.Exception: I'm checked exception<br>
<br>
So if stage funcition/supplier throws CompletionException, it is not wrapped with another CompletionException as the stage outcome but it becomes the stage outcome directly.<br>
<br>
Finally the following "implementation detail" of CompletableFuture is also useful for our purpose. If you try:<br>
<br>
        try {<br>
            CompletableFuture.supplyAsync(() -> {<br>
                throw new CompletionException(new Exception("I'm checked exception"));<br>
            }).get();<br>
        } catch (ExecutionException | InterruptedException e) {<br>
            System.out.println("Got: " + e);<br>
        }<br>
<br>
...you will get:<br>
<br>
Got: java.util.concurrent.ExecutionException: java.lang.Exception: I'm checked exception<br>
<br>
So if CompletableFuture outcome is CompletionException wrapping some Throwable, then calling get() on the future will throw ExecutionException wrapping this same Throwable. The cause of CompletionException is effectively unwrapped before being wrapped with
 ExecutionException in get().<br>
<br>
This behaviour lends itself to the use of <b>CompletionException</b> as a general wrapper for any exception (checked or unchecked) thrown by the stage function/supplier.<br>
<br>
You can create helper functional interfaces:<br>
<br>
    interface SupplierX<T> {<br>
        T get() throws Throwable;<br>
    }<br>
<br>
    interface FunctionX<T, R> {<br>
        R apply(T t) throws Throwable;<br>
    }<br>
<br>
    // ... etc ... and utility static methods:<br>
<br>
    static <T> Supplier<T> wrap(SupplierX<T> supplier) {<br>
        return () -> {<br>
            try {<br>
                return supplier.get();<br>
            } catch (Throwable e) {<br>
                throw new CompletionException(e);<br>
            }<br>
        };<br>
    }<br>
<br>
    static <R> Function<Throwable, R> unwrapWrap(FunctionX<Throwable, R> fn) {<br>
        return (throwable) -> {<br>
            try {<br>
                return fn.apply(throwable instanceof CompletionException<br>
                                ? throwable.getCause()<br>
                                : throwable);<br>
            } catch (Throwable e) {<br>
                throw new CompletionException(e);<br>
            }<br>
        };<br>
    }<br>
<br>
    // ... etc.<br>
<br>
<br>
And then use them as following:<br>
<br>
<br>
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(wrap(<br>
            () -> {<br>
                double r = Math.random();<br>
                if (r < 1d / 3d) return "OK";<br>
                else if (r < 2d / 3d) throw new FileNotFoundException();<br>
                else throw new EOFException();<br>
            }<br>
        ));<br>
<br>
        cf = cf.exceptionally(unwrapWrap(<br>
            (t) -> {<br>
                try {<br>
                    throw t;<br>
                } catch (IOException e) {<br>
                    throw new IllegalStateException("Converted from: " + e);<br>
                }<br>
            }<br>
        ));<br>
<br>
        cf = cf.exceptionally(unwrapWrap(<br>
            (t) -> {<br>
                try {<br>
                    throw t;<br>
                } catch (RuntimeException e) {<br>
                    return "Handled: " + e;<br>
                }<br>
            }<br>
        ));<br>
<br>
        System.out.println(cf.get());<br>
<br>
<br>
<br>
Regards, Peter<o:p></o:p></p>
</div>
<br>
<div align="center">
<table class="MsoNormalTable" border="1" cellspacing="0" cellpadding="0" width="100%" style="width:100.0%; border:outset #666666 1.0pt">
<tbody>
<tr>
<td style="border:inset #666666 1.0pt; padding:3.75pt 3.75pt 3.75pt 3.75pt">
<p class="MsoNormal"><span style="font-size:8pt; font-family:"Trebuchet MS","sans-serif"; color:gray">Software AG – Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany – Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management
 Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Dr. Wolfram Jost, Arnd Zinnhardt; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky -
</span><a href="http://www.softwareag.com"><b><span style="font-size:8pt; font-family:"Trebuchet MS","sans-serif"; color:navy">http://www.softwareag.com</span></b><span style="font-size:8pt; font-family:"Trebuchet MS","sans-serif"; color:gray">
</span></a><span style="font-size:12.0pt"></span></p>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>