{"id":470,"date":"2021-04-09T12:35:10","date_gmt":"2021-04-09T16:35:10","guid":{"rendered":"http:\/\/freedville.com\/blog\/?p=470"},"modified":"2021-04-09T12:35:10","modified_gmt":"2021-04-09T16:35:10","slug":"book-review-java-8-in-action","status":"publish","type":"post","link":"https:\/\/freedville.com\/blog\/2021\/04\/09\/book-review-java-8-in-action\/","title":{"rendered":"Book Review: Java 8 In Action"},"content":{"rendered":"\n<p>Java 8 has been out for long enough \u2013 I needed to go learn\nthe new features!&nbsp; I read <a href=\"https:\/\/www.manning.com\/books\/java-8-in-action\">Java 8 In Action<\/a> by\nManning Publications.&nbsp; (There\u2019s a newer\nversion, <a href=\"https:\/\/www.manning.com\/books\/modern-java-in-action\">Modern\nJava in Action<\/a>, covering up to Java 10, but I was strictly working on Java\n8 projects)<\/p>\n\n\n\n<p>This book has been a godsend!&nbsp; After reading through the book and working\nthrough its many examples, I now have a strong grasp on the new features of Java\n8.<\/p>\n\n\n\n<p>Java 8 is a major language update, borrowing great ideas\nfrom other languages that help to keep Java &#8220;fresh&#8221;.&nbsp; The biggest benefits of these updates are:<\/p>\n\n\n\n<ul><li><strong>Parallelism<\/strong> \u2013 Java 8 makes it easy to take\nadvantage of multi-core processors.<\/li><li><strong>Conciseness<\/strong> \u2013 Java\u2019s verbose boilerplate code\ncan often be replaced with Java 8 syntactic sugar.<\/li><li><strong>Ready for Big data<\/strong> \u2013 With streams you can\nwork on larger datasets without loading all of them into memory at once (analogous\nto Map\/Reduce)<\/li><li><strong>Imperative, not Declarative<\/strong> \u2013 You can\nmore often write \u201cwhat\u201d you want to do, rather than \u201chow\u201d you want it done.<\/li><\/ul>\n\n\n\n<p>These updates are accomplished through three major features:<\/p>\n\n\n\n<ul><li><strong>Method reference<\/strong> \u2013 You can now pass\nmethods (functions) to other functions.<\/li><li><strong>Lambda<\/strong> \u2013 A lambda is a one-use function\nwith a name.&nbsp; Previous Java versions let\nyou approximate Lambdas with anonymous classes, in a verbose way.<\/li><li><strong>Streams<\/strong> \u2013 A stream processes collections using\na database-like syntax.&nbsp; You describe\nwhat you want and let the language figure out how to accomplish it.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 1 &#8211; Introduction<\/h2>\n\n\n\n<p>Chapter 1 introduces a few of these features with a simple\nand illuminating example: filtering files. &nbsp;Many Java developers are familiar with the verbose\nboilerplate code in the first code block.<\/p>\n\n\n\n<p><em>Pre-Java 8:<\/em><\/p>\n\n\n\n<p><code>File [] hiddenFiles = new File(\".\").listFiles(new FileFilter() {<br>\u00a0\u00a0 public boolean accept(File file) {<br>\u00a0\u00a0\u00a0\u00a0\u00a0 return file.isHidden()<br>\u00a0\u00a0 }<br>});<br><\/code><\/p>\n\n\n\n<p><em>Java 8 using method references<\/em><\/p>\n\n\n\n<p><code>File[] hiddenFiles = new File(\".\").listFiles(File::isHidden);<\/code><\/p>\n\n\n\n<p>This is an exciting example to see where this book is going!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chapter 2 \u2013 Behavior Parameterization<\/h2>\n\n\n\n<p>Chapters 1 and 2 further show the value of method references\nby doing more advanced filtering.&nbsp; The\nold method took five lines for a filter, whereas the Java 8 method took only\none line.&nbsp; When multiple levels of\nfiltering are needed, Java 8 really shines!&nbsp;\nPre-Java 8, if you wanted to filter apples on two conditions, you either\nwrote 5-line methods and chained them, or made one complex 5-line filtering\nmethod.&nbsp; With method references and\nstreams, you can do complex filtering simply.&nbsp;\nLook at this Java 8 code for filtering a list of apples to collect only\nheavy, green apples: <\/p>\n\n\n\n<p><code>List&lt;Apple> inventory = getApples();<br>List&lt;Apple> filteredApples = inventory.stream()<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .filter(Apple::isGreenApple)<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .filter(Apple::isHeavyApple)<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .collect(toList());<\/code><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Chapter 3 &#8211; Lambdas<\/h1>\n\n\n\n<p>Chapter 3 introduces Lambdas.&nbsp; Lambdas have these characteristics:<\/p>\n\n\n\n<ul><li><strong>Anonymous<\/strong> (no name)<\/li><li><strong>Function<\/strong> (not associated with a class, but has\nparameters\/body\/return type\/exceptions)<\/li><li><strong>Passable<\/strong> (can be passed as argument)<\/li><li><strong>Concise<\/strong> (lots of boilerplate is removed)<\/li><\/ul>\n\n\n\n<p>Lambdas can be used anywhere a @FunctionalInterface is\naccepted.&nbsp; Think about all of the\none-method interfaces you\u2019re familiar with \u2013 FileFilter::accept as an\nexample.&nbsp; Each of those can now be\nreplaced with a Lambda expression.<\/p>\n\n\n\n<p>File::isHidden could be written as a lambda:<\/p>\n\n\n\n<p><code>(File f) -> f.isHidden()<\/code><\/p>\n\n\n\n<p>And then could be consumed as:<\/p>\n\n\n\n<p><code>File[] hiddenFiles = new File(\".\").listFiles((File f) -> f.isHidden());<\/code><\/p>\n\n\n\n<p>The authors are careful to mention that when a lambda gets\nlong, you should replace it with a named function.<\/p>\n\n\n\n<p>Out of all the Java 8 features, I\u2019m most concerned about\nLambdas.&nbsp; They have the most potential for\nabuse.&nbsp; I strongly prefer named methods\nfor the following reasons:<\/p>\n\n\n\n<ul><li>The name gives a descriptive label<\/li><li>Named methods are more easily reused<\/li><li>Lambdas cannot be unit tested directly<\/li><\/ul>\n\n\n\n<p>A one-line lambda may be fine, but as a code reviewer I would be looking hard at code with many lambdas and try to find ways to reduce them.<\/p>\n\n\n\n<p>The book had a wonderful table describing all of the @FunctionalInterface\ntypes in Java.&nbsp; The most common ones are:<\/p>\n\n\n\n<ul><li><strong>Predicate&lt;T&gt;<\/strong> &#8211; returning a Boolean for\nsome object, for instance Apple::isHeavy is a predicate.<\/li><li><strong>Consumer&lt;T&gt;<\/strong> &#8211; takes an object and\nreturns void<\/li><li><strong>Supplier&lt;T&gt;<\/strong> &#8211; takes no arguments\nand produces an object<\/li><li><strong>Function&lt;T, R&gt;<\/strong> &#8211; takes an object of\ntype T and returns and object of type R<\/li><li>There are also versions that take two parameters<\/li><\/ul>\n\n\n\n<p>This table helped me understand streams better.&nbsp; A lot of stream operations are accomplished\nwith Predicates and Functions.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Chapters 4-7 \u2013 All about streams<\/h1>\n\n\n\n<p>Chapter 1 got me excited about streams \u2013 this section sealed\nthe deal.<\/p>\n\n\n\n<p>Streams let you move from external iteration to internal\niteration:<\/p>\n\n\n\n<ul><li><strong>External iteration (imperative)<\/strong>: you\nwrite the loop<\/li><li><strong>Internal iteration (declarative)<\/strong>: the\nloop is implied, you don&#8217;t write it<\/li><\/ul>\n\n\n\n<p>The first time I read that, it was not very exciting.&nbsp; After all, I\u2019m really good at writing for\nloops!&nbsp; What made this amazing for me was\nhow I could build a multi-level table from some raw data (essentially a pivot\ntable).&nbsp; I had a CSV file with SurveyResponses\n(data, questionId, count)<\/p>\n\n\n\n<p><code>20210306,q1,53<br>20210306,q2,23<br>20210307,q1,15<br>20210307,q2,8<\/code><\/p>\n\n\n\n<p>After reading these values into List&lt;SurveyResponse&gt;\nresponses, it took only a few lines to build the pivot table.&nbsp; How many lines would this team without\nstreams?<\/p>\n\n\n\n<p><code>Map&lt;String, Map&lt;String, Integer>> responsesByDateAndNode =<br>\u00a0\u00a0responses.stream().collect(<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em>groupingBy<\/em>(SurveyResponse::getDate,<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em>groupingBy<\/em>(SurveyResponse::getQuestionId,<br>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<em>reducing<\/em>(0, SurveyResponse::getCount, Integer::<em>sum<\/em>)<br>\u00a0\u00a0))<br>);\u00a0 <\/code><\/p>\n\n\n\n<p>The key insights from the book on streams are:<\/p>\n\n\n\n<ul><li>Think of Streams as a fancy Iterator.&nbsp; <\/li><li>Or think of a stream as a lazily-constructed\ncollection.<\/li><li>Most operations on a stream are finding or\ngrouping.<\/li><li>Elements in a stream are produced only as and\nwhen required. (Lazy evaluation!)<\/li><li>A stream can be consumed only once.<\/li><\/ul>\n\n\n\n<p>This section of the book has many great recipes on how to\nuse streams.&nbsp; Almost every recipe\nincludes a non-streams code version for comparison.&nbsp; It\u2019s amazing how much code melts away when\nyou use streams.&nbsp; The declarative nature\nof streams programming means you spend more time thinking about what you want,\nand less time figuring out how to implement it in a bunch of for-loops and\ntemporary variables.<\/p>\n\n\n\n<p>I don\u2019t want to reproduce the many examples from this book \u2013\nbuy the book for this section alone!<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Chapter 8 &#8211; Refactoring, testing, and debugging<\/h1>\n\n\n\n<p>I loved this chapter &#8211; I would have liked even more\ndiscussion on these concepts.<\/p>\n\n\n\n<p>The first key point was general guiding principles for\nrefactoring code to the \u201cJava 8 way\u201d:<\/p>\n\n\n\n<ul><li>Anonymous classes -&gt; Lambda Expressions<\/li><li>Lambda Expressions -&gt; Method References<\/li><li>Imperative data processing (loops) -&gt;\nDeclarative data processing (streams)<\/li><\/ul>\n\n\n\n<p>It\u2019s funny to me that Lambdas are on both the left and right\nside of these equations \ud83d\ude00<\/p>\n\n\n\n<p>But, there are several design patterns are suitable for\nlambdas \u2013 each of which can be done more concisely with lambdas: strategy,\ntemplate method, observer, chain of responsibility, factory.&nbsp; Lambdas that become long should instead\nbecome named methods, passed as method reference.<\/p>\n\n\n\n<p>Another key principle from the book is:<\/p>\n\n\n\n<ul><li>Removing verbosity improves readability<\/li><\/ul>\n\n\n\n<p>I would supplement that message<\/p>\n\n\n\n<ul><li>Removing verbosity <strong>usually<\/strong> improves\nreadability<\/li><\/ul>\n\n\n\n<p>Java 8 code with lambdas can be so concise it almost becomes\ncryptic, at least for this Java 5 developer.&nbsp;\nThe book does not explore this point very hard, only urging readers to\nconsider readability.&nbsp; I urge caution in\nusing some Java 8 features \u2013 make sure your code is still readable, don\u2019t just\nforce-fit as many Java 8 features as you can.<\/p>\n\n\n\n<p>The key testing message around lambdas is that lambdas\ncannot be tested directly.&nbsp; You can only\ntest a function that uses\/consumes a lambda, not the lambda itself.&nbsp; This tells me it is critical not to make your\nlambdas \u201ctoo big\u201d.&nbsp; From this alone, I\u2019m\nsuspicious of the value of any lambda that\u2019s more than one or two lines long.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Chapter 10 &#8211; Using Optional as a better alternative to null<\/h1>\n\n\n\n<p>Optionals is an interesting Java 8 feature.&nbsp; Optionals wrap nullable values.&nbsp; Java code that uses null has many problems:<\/p>\n\n\n\n<ul><li><strong>Source of error<\/strong> &#8211; NullPointerException is\nthe most common exception seen in Java<\/li><li><strong>Code bloat<\/strong> \u2013 every null check makes code\nmore verbose<\/li><li><strong>Breaks encapsulation<\/strong> \u2013 as an API\nconsumer, you are always worried about pointers being null.<\/li><li><strong>Type system is broken<\/strong> &#8211; null gives no\nhints what Object was supposed to be used<\/li><li><strong>Exit complexity<\/strong> &#8211; Many null-checks in\nyour code can introduce many possible exit points<\/li><\/ul>\n\n\n\n<p>It\u2019s helpful to think of Optional as a Stream that has at\nmost one value.&nbsp; (It is not actually a\nStream, Optional extends Object, but has many of the same methods.)<\/p>\n\n\n\n<p>Even though Optional has Optional.empty(), or\nOptional.isPresent(), you start to reintroduce the same problems from null.&nbsp; When possible, use methods that have default\nbehavior.<\/p>\n\n\n\n<p>If a Person object has an Optional&lt;String&gt; name field,\nyou can do the following to return a person\u2019s name if it exists, or \u201cUnknown\nname\u201d if it doesn\u2019t.&nbsp; <\/p>\n\n\n\n<p><code>String name = person.getName().orElse(\u201cUnknown name\u201d);<\/code><\/p>\n\n\n\n<p>You can also supply a function argument that consumes an\nOptional value only if it exists:<\/p>\n\n\n\n<p><code>person.getName().ifPresent(System.out::println)<\/code><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Other chapters<\/h1>\n\n\n\n<p>The remaining chapters had useful content but were not life-changing.<\/p>\n\n\n\n<ul><li>Chapter 9 &#8211; Default methods<\/li><li>Chapter 11 &#8211; CompletableFuture: composable\nasynchronous programming<\/li><li>Chapter 12 &#8211; New Date and Time API<\/li><li>Chapter 13 &#8211; Thinking Functionally<\/li><li>Chapter 14 &#8211; Functional programming techniques<\/li><li>Chapter 15 &#8211; Blending OOP and FP: comparing Java\n8 and Scala<\/li><li>Chapter 16 &#8211; Conclusions and where next for Java<\/li><li>Appendix A &#8211; Miscellaneous Language Updates<\/li><li>Appendix B &#8211; Miscellaneous Library Updates<\/li><li>Appendix C &#8211; Performing multiple operations in\nparallel on a stream<\/li><li>Appendix D &#8211; Lambdas and JVM bytecode<\/li><\/ul>\n\n\n\n<p>These chapters were useful as references \u2013 these are mostly\ndocumentations of incremental changes in Java 8.&nbsp; <\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Summary<\/h1>\n\n\n\n<p>This book made Java 8 clear to me.&nbsp; With hundreds of annotated diagrams and code\nlistings, I was finally able to appreciate the value of the new Java 8\nfeatures.&nbsp; Thanks to this book, I can now\nread and appreciate Java 8 code without going to a search engine on every line.<\/p>\n\n\n\n<p>I highly recommend <a href=\"https:\/\/www.manning.com\/books\/java-8-in-action\">Java 8 In Action<\/a>, or\nthe newer edition <a href=\"https:\/\/www.manning.com\/books\/modern-java-in-action\">Modern\nJava in Action<\/a> (covers Java 8, 9, and 10), for anyone who wants to\nunderstand the new Java 8 features.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Java 8 has been out for long enough \u2013 I needed to go learn the new features!&nbsp; I read Java 8 In Action by Manning Publications.&nbsp; (There\u2019s a newer version, Modern Java in Action, covering&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/posts\/470"}],"collection":[{"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/comments?post=470"}],"version-history":[{"count":1,"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/posts\/470\/revisions"}],"predecessor-version":[{"id":471,"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/posts\/470\/revisions\/471"}],"wp:attachment":[{"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/media?parent=470"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/categories?post=470"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/freedville.com\/blog\/wp-json\/wp\/v2\/tags?post=470"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}