{"id":81,"date":"2020-12-27T13:16:55","date_gmt":"2020-12-27T11:16:55","guid":{"rendered":"http:\/\/victorrentea.ro\/blog\/?p=81"},"modified":"2020-12-31T07:47:42","modified_gmt":"2020-12-31T05:47:42","slug":"exceptions-and-streams","status":"publish","type":"post","link":"https:\/\/victorrentea.ro\/blog\/exceptions-and-streams\/","title":{"rendered":"Exceptions and Streams"},"content":{"rendered":"<div id=\"bsf_rt_marker\"><\/div><p>Java 8 gave us <code>Optional<\/code>, a mighty weapon against the most frequent Exception in Java: <code>NullPointerException<\/code>, that I talked about in <a href=\"avoiding-null-pointer\">this blog post<\/a>. However, Java 8 also brought new headaches regarding exceptions, as the default functional interfaces in Java 8 don\u2019t declare throwing any checked exceptions. So usually when you get a checked exception within a lambda, you have to fix that somehow.<\/p>\n<h2>Converting Checked into Runtime Exceptions<\/h2>\n<p>The default suggestion offered by most IDEs to auto-fix this issue will produce code like this:<\/p>\n<pre><code>SimpleDateFormat format = new SimpleDateFormat(\"yyyy-MM-dd\");<\/code>\n<code>List&lt;String&gt; dateList = asList(\"2020-10-11\", \"2020-nov-12\", \"2020-12-01\");<\/code>\n<code>List&lt;Date&gt; dates = dateList.stream().map(s -&gt; {<\/code>\n<code>   try {<\/code>\n<code>      return format.parse(s);<\/code>\n<code>   } catch (ParseException e) {<\/code>\n<code>      throw new RuntimeException(e);<\/code>\n<code>   }<\/code>\n<code>}).collect(toList());<\/code><\/pre>\n<p>Horrible code.<\/p>\n<p>We could create a dedicated function doing just <code>.parse<\/code> and then cast a spell on it with <code>@SneakyThrows<\/code>, as we&#8217;ve discussed in <a href=\"hide-checked-exceptions-with-sneakythrows\">a previous article<\/a>:<\/p>\n<pre><code>   List&lt;Date&gt; dates = dateList.stream()<\/code>\n<code>        .map(s -&gt; uglyParse(format, s))<\/code>\n<code>        .collect(toList());<\/code>\n<code>   ...<\/code>\n<code>}<\/code><\/pre>\n<p><code>@SneakyThrows<\/code><br \/>\n<code>private static Date uglyParse(SimpleDateFormat format, String s) {<\/code><br \/>\n<code>   return format.parse(s);<\/code><br \/>\n<code>}<\/code><\/p>\n<p>But creating this new method just to hack it with Lombok feels wrong. Indeed, we created it for a purely technical reason: to hide the annoying checked exception which doesn&#8217;t fit with the <code>java.util.Function<\/code> interface that doesn&#8217;t declare throwing anything.<\/p>\n<p>Let&#8217;s play a bit and create a <code>ThrowingFunction<\/code> interface declaring to throw any checked exception:<\/p>\n<pre><code>interface ThrowingFunction&lt;T,R&gt; {<\/code>\n<code>    R apply(T t) throws Exception;<\/code>\n<code>}<\/code><\/pre>\n<p>Then, our <code>s-&gt;format.parse(s)<\/code> expression could be <a href=\"https:\/\/docs.oracle.com\/javase\/tutorial\/java\/javaOO\/lambdaexpressions.html#target-typing\">target-typed<\/a> to this new interface, so the following line compiles:<\/p>\n<pre><code>ThrowingFunction&lt;String, Date&gt; p = s -&gt; format.parse(s);<\/code>\n<code>\/\/ or<\/code>\n<code>ThrowingFunction&lt;String, Date&gt; p = format::parse;<\/code><\/pre>\n<p>Unfortunately, the <code>Stream.map()<\/code> operation takes a <code>java.util.function.Function<\/code>. You can&#8217;t change that, but let&#8217;s imagine we had a function that would take a <code>ThrowingFunction<\/code> and return back a &#8216;classic&#8217; <code>java.util.function.Function<\/code> that doesn&#8217;t throw any checked exception anymore.<\/p>\n<pre><code>Function&lt;String, Date&gt; f = wrapAsRuntime(p);<\/code>\n<code>List&lt;Date&gt; dates = dateList.stream().map(f).collect(toList());<\/code><\/pre>\n<p>And here&#8217;s the strange <code>wrapAsRuntime<\/code> function:<\/p>\n<pre><code>private static &lt;T,R&gt; Function&lt;T, R&gt; wrapAsRuntime(ThrowingFunction&lt;T, R&gt; p) {<\/code>\n<code>    return t -&gt; {<\/code>\n<code>        try {<\/code>\n<code>            return p.apply(t);<\/code>\n<code>        } catch (Exception e) {<\/code>\n<code>            throw new RuntimeException(e);<\/code>\n<code>        }<\/code>\n<code>    };<\/code>\n<code>}<\/code><\/pre>\n<p>If that&#8217;s complete nonsense for your, then I would advice that you try to type it yourself. It helps a lot!<\/p>\n<p>Notice that we\u2019ve used generics to make it highly reusable. That&#8217;s quite a good idea, isnt&#8217;it? It&#8217;s so good that of course others had it it many years ago&#8230; \ud83d\ude42<\/p>\n<p>Introducing the <code>Unchecked.function()<\/code> from the <a href=\"https:\/\/github.com\/jOOQ\/jOOL\">jool library<\/a> that does EXACTLY what we did above. Using it, the final code looks like:<\/p>\n<pre><code>List&lt;Date&gt; dates = dateList.stream().map(Unchecked.function(format::parse)).collect(toList());<\/code><\/pre>\n<p>If you&#8217;ve been using Java 8 for many years, then this library is a must-have.<\/p>\n<blockquote><p><strong>Best-practice<\/strong>: Whenever checked exceptions are annoying you in lambdas <code>-&gt;<\/code> or method references <code>::<\/code>, use <code>Unchecked.*<\/code> to rethrow it as a <code>RuntimeException<\/code><\/p><\/blockquote>\n<p>This doesn&#8217;t involve any hack in the bytecode (<a href=\"hide-checked-exceptions-with-sneakythrows\">as @SneakyThrows does<\/a>), but only plain java code. Passing a function as a parameter to another function is a very useful practice that I will be blogging about soon, but functions that both take and return functions &#8211; I found that the vast majority of developers have a hard time reasoning about them. It&#8217;s one of the most complex, hard to read, and especially hard to debug in Java, so avoid mixing it with complex business logic. But since it&#8217;s a library doing it, and the purpose is straightforward, I never hesitated to use it many of my projects. On the other hand, if you want to avoid depending on this library, you just saw the necessary code to write.<\/p>\n<p>Now let&#8217;s shift a bit the perspective. No matter how you twist it, the processing of the entire stream stops when the first exception is thrown. But what if we don&#8217;t want to crash but instead collect all the errors.<\/p>\n<h2>The Try Monad<\/h2>\n<p>Let\u2019s change the requirements a bit: we now want to parse all the <strong>valid<\/strong> dates and return them IF at least half of them are parseable, otherwise we should throw an exception. This time we can\u2019t let an exception terminate the execution of our stream. Instead, we want to go through all of the items and collect both parsed dates and exceptions. For example, if we are given 3 correctly-formatted dates and 2 invalid ones, we should return the 3 ones that we were able to parse correctly.<\/p>\n<blockquote><p>Whenever you want to <strong>collect the exceptions<\/strong> happening in items, consider using the vavr <code>Try<\/code> monad.<\/p><\/blockquote>\n<p>The <code>Try&lt;&gt;<\/code> class from the <a href=\"https:\/\/www.vavr.io\/\">vavr library<\/a> is a specialization of the <code>Either&lt;&gt;<\/code> concept present in many functional programming languages. An instance can store either the result or the occurred exception (if any).<\/p>\n<pre><code>List&lt;Try&lt;Date&gt;&gt; tries = dateList.stream()<\/code>\n<code>    .map(s -&gt; Try.of(<\/code>\n<code>        () -&gt; format.parse(s) \/\/ throwing code<\/code>\n<code>    ))<\/code>\n<code>    .collect(toList());<\/code><\/pre>\n<p>If the <em>throwing code<\/em> crashes with an exception, the surrounding <code>Try.of<\/code> function will catch that exception and return a <strong>failed Try<\/strong>. Therefore, in the <code>tries<\/code> list above, there can be items with <code>isSuccess()<\/code> either <code>true<\/code> or <code>false<\/code>. To count the success ratio, the shortest (geekest) form is:<\/p>\n<pre><code>double successRatio = tries.stream()<\/code>\n<code>    .mapToInt(t -&gt; t.isSuccess() ? 1 : 0)<\/code>\n<code>    .average()<\/code>\n<code>    .orElse(0);<\/code><\/pre>\n<p>Then,<\/p>\n<pre><code>if (successRatio &gt; .5) {<\/code>\n<code>    return tries.stream()<\/code>\n<code>        .filter(Try::isSuccess)<\/code>\n<code>        .map(Try::get)<\/code>\n<code>        .collect(toList());<\/code>\n<code>} else {<\/code>\n<code>    throw new IllegalArgumentException(\"Too many invalid dates\");<\/code>\n<code>}<\/code><\/pre>\n<p>Problem solved.<\/p>\n<p>To better understand the code, we can extract a function from it, that returns a <code>Try&lt;&gt;<\/code>:<\/p>\n<pre><code>private static Try&lt;Date&gt; tryParse(SimpleDateFormat format, String s) {<\/code>\n<code>    return Try.of(() -&gt; format.parse(s));<\/code>\n<code>}<\/code><\/pre>\n<p>This resembles the style of handling exceptions in other languages like Go and Haskell, which return the exception to their callers.<\/p>\n<p>By the way, if you think a bit, you could solve the problem without the <code>Try<\/code>, by sweeping the data twice: first to count the parseable dates, and then to actually parse them. Or even a single pass using a combination of a <code>.map<\/code> returning a <code>null<\/code>\/<code>Optional.empty<\/code> for errors, followed by a <code>.filter<\/code>. That could work too, but the <code>Try<\/code> approach might be more readable.<\/p>\n<blockquote><p><strong>Tip<\/strong>: Consider <code>*vavr.Try&lt;&gt;<\/code> when you want to collect both results and exceptions in a single pass through data.<\/p><\/blockquote>\n<p>By the way, if you keep thinking at the &#8220;Monad&#8221; word, here\u2019s a nice article to get you past that: <a href=\"https:\/\/dzone.com\/articles\/functor-and-monad-examples-in-plain-java\">Monads for Java developers<\/a><\/p>\n<p><strong>Disclaimer<\/strong>: avoid streaming a large number of items in batch processing. Instead, stick with the industry default: process the data in chunks, and consider introducing Spring Batch for state-of-the-art batches.<\/p>\n<h2>Conclusions<\/h2>\n<ul>\n<li>Checked exceptions don&#8217;t play nice with the Java Stream API.<\/li>\n<li>Use <code>@SneakyThrows<\/code> (<a href=\"https:\/\/projectlombok.org\/features\/SneakyThrows\">Lombok<\/a>) or <code>Unchecked<\/code> (<a href=\"http:\/\/www.jooq.org\/products\/jOO%CE%BB\/javadoc\/0.9.5\/org\/jooq\/lambda\/Unchecked.html\">jOOL<\/a>) to get rid of checked exceptions with Streams<\/li>\n<li>Consider <code>Try<\/code> (<a href=\"https:\/\/www.javadoc.io\/doc\/io.vavr\/vavr\/0.10.0\/io\/vavr\/control\/Try.html\">vavr<\/a>) whenever you want to collect the errors occurring for an element instead of terminating the Stream.<\/li>\n<\/ul>\n<p><strong>Update<\/strong><\/p>\n<p>The Vavr library also has an equivalent for wrapping checked exceptions into runtime ones (thanks Babis Routis):<\/p>\n<p>.map(CheckedFunction1.of(s -&gt; uglyParse(format, s).unchecked()))<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Java 8 gave us Optional, a mighty weapon against the most frequent Exception in Java: NullPointerException, that I talked about in this blog post. However, Java 8 also brought new headaches regarding exceptions, as the &hellip; <\/p>\n","protected":false},"author":1,"featured_media":100,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[6,10,9,3],"class_list":["post-81","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-practical-tips","tag-exceptions","tag-functional-programming","tag-java8","tag-lombok"],"_links":{"self":[{"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/posts\/81","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/comments?post=81"}],"version-history":[{"count":16,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/posts\/81\/revisions"}],"predecessor-version":[{"id":171,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/posts\/81\/revisions\/171"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/media\/100"}],"wp:attachment":[{"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/media?parent=81"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/categories?post=81"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/tags?post=81"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}