Some of the key takeaways from the document are the introduction of lambda expressions and functional programming concepts to Java with Java 8.
Some of the new functional programming features introduced in Java 8 include lambda expressions, method references, and streams.
Streams can be used to iterate over characters in a string by calling chars() on the string to get a stream of ints, and then mapping or filtering as needed.
Functional Programming in Java
Harnessing the Power of Java 8 Lambda Expressions
Venkat Subramaniam The Pragmatic Bookshelf Dallas, Texas Raleigh, North Carolina Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and The Pragmatic Programmers, LLC was aware of a trademark claim, the designations have been printed in initial capital letters or in all capitals. The Pragmatic Starter Kit, The Pragmatic Programmer, Pragmatic Programming, Pragmatic Bookshelf, PragProg and the linking g device are trade- marks of The Pragmatic Programmers, LLC. Every precaution was taken in the preparation of this book. However, the publisher assumes no responsibility for errors or omissions, or for damages that may result from the use of information (including program listings) contained herein. Our Pragmatic courses, workshops, and other products can help you and your team create better software and have more fun. For more information, as well as the latest Pragmatic titles, please visit us at http://pragprog.com. Copyright 2013 The Pragmatic Programmers, LLC. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent of the publisher. Printed in the United States of America. ISBN-13: 978-1-937785-46-8 Encoded using the finest acid-free high-entropy binary digits. Book version: B1.0March 6, 2013 Preface Youre in for a treat. One of the most prominent and widely used languages in the world has evolved, for the better. Until now Java gave us one set of toolsOOand we did the best we could with it. Now, in addition, theres another way to solve more elegantly the common problems we encounter when developing applications. We can now do quite effectively in Java what was possible on the JVM only using other languagesthis means truly more power for everyone using Java. In the past few decades, Im thankful for the privilege to program with a few languages: C, C++, Java, C#, F#, Ruby, Groovy, Scala, Clojure, Erlang, JavaScript When asked which ones my favorite, my resounding answer has been: its not the language that excites me, but the way we program. The science and engineering in programming is what drew me in, but its the art in programming that keeps me. Coding has a lot in common with writing theres more than one way to express our ideas. Java helped us so far to write code using objects. Now we have an additional way to implement our designs and ideas. This is a new way in Java, one that will make our code more expressive, easier to write, less error-prone, and easier to parallelize than we were able to do with Java until now. This way has been around for decades and widely used in languages like Lisp, Clojure, Erlang, Scala, Groovy, Ruby This is not only a new way in Java, but youll find it to be a better way as well. Since coding is like writing, we can learn a few things from that field. William Zinsser recommends simplicity, clarity, and brevity in On Writing Well [Zin01]. To create better applications, we can start by making the code simpler, clearer, and concise. The new style of programming in Java provides exactly that, as we will explore throughout this book. Click HERE to purchase this book now. discuss Whos this book for This book is for programmers well versed with object-oriented programming in Java who are keen to learn and apply the new facilities of lambda expres- sions. Youll need good experience programming in previous versions of Java, especially Java 5, to make the best use of this book. Programmers mostly interested in other JVM languages like Scala, Groovy, JRuby, and Closure can benefit from the examples in this book and can relate back to the facilities offered in the respective languages. They can also use the examples to help fellow Java programmers in their teams. Programmers experienced with the functional style of programming in other languages who are now involved in Java projects can use this book as well. They can learn how what they know translates to the specifics of the lambda expressions usage in Java. Programmers whore familiar with lambda expressions in Java can use this book to help coach and train their team members who are getting up to speed in this area. Whats in this book This book will help you get up to speed with Java 8 lambda expressions, to think in the elegant style, and benefit from the additions to the Java JDK library. Well take an example driven approach to explore the concepts. Rather than discuss the theory of functional programming, well dive into specific day-to-day tasks to apply the elegant style. This approach will quickly help to get these concepts under our belts, so we can put them to real use on projects right away. On the first read, take the time to go over the chapters sequentially, as we build upon previously discussed concepts and examples. Later, when working on applications, take a quick glance at any relevant example or section in the book. Theres also an appendix of syntax for quick reference. Heres how the rest of the book is organized: We discuss the functional style of programming, its benefits, and how it differs from the prevalent imperative style in Chapter 1, Hello Lambda Expressions, on page ?. We also look into how Java supports lambda expressions in this chapter. The JDK collections have received some special treatment in Java 8, with new interfaces, classes, and methods that support functional style operations. We will explore these in Chapter 2, Using Collections, on page ?. Preface vi Click HERE to purchase this book now. discuss In Chapter 3, Strings, Comparators, and Filters, on page ? we exploit func- tional style and lambda expressions to work with strings, implement the Comparator interface, and filters for file selection. In addition to using the functional style facilities in the JDK, we can benefit from applying the elegant style in the design of methods and classes we create. Well pick up functional style design techniques in Chapter 4, Designing with Lambda Expressions, on page ?. The lambda expressions facilitate a code structure that helps delineate oper- ations to manage object lifetimes and resource clean up as well see in Chapter 5, Working with Resources, on page ?. Well see lambda expressions shine in Chapter 6, Being Lazy, on page ?, to provide us the ability to postpone instance creation and method evaluations, create infinite lazy collections, and thereby improve the performance of the code. In Chapter 7, Optimizing Recursions, on page ? we will use lambda expres- sions to optimize recursions and achieve stellar performance using memoiza- tion techniques. Well put the techniques we cover in the book to some real use in Chapter 8, Composing with Lambda Expressions, on page ? where we will transform objects, implement map-reduce, and safely parallelize a program with little effort. Finally, in Chapter 9, Bringing it all Together, on page ? we will go over the key concepts and the practices needed to adopt them. In Appendix 1, Starter Set of Functional Interfaces, on page ? well take a glance at some of the most popular functional interfaces. A quick overview of the Java 8 syntax for functional interfaces, lambda expressions, and method/constructor references is in Appendix 2, Syntax Overview, on page ?. The URLs mentioned throughout the book are gathered together for conve- nience in Appendix 3, Web Resources, on page ?. Java Version used in this book To run the examples in this book you need Java 8 with support for lambda expressions. Using automated scripts, the examples in this book have been tried out with the following version of Java: Click HERE to purchase this book now. discuss Java Version used in this book vii openjdk version "1.8.0-ea" OpenJDK Runtime Environment (build 1.8.0-ea-lambda-nightly-h3419-20130219-b78-b00) OpenJDK 64-Bit Server VM (build 25.0-b15, mixed mode) Take a few minutes to download the appropriate version of Java depending on the system. This will help you practice the examples in the book as you follow along. How to read the code examples When writing code in Java, we place classes in packages and executable statements and expressions in methods. In order to reduce clutter and save pages in the book, well skip the package names and imports in the code listing. All code in this book belong to a package: package fpij; Any executable code not listed within a method is part of an undisplayed main() method. When going through the code listings, if theres an urge to look at the full source code, remember its only a click away at the website for the book. Online Resources A number of web resources referenced through out the book are collected in Appendix 3, Web Resources, on page ?. Here are a few that will help you get started with this book: The Oracle website for downloading the version of Java used in this book: http://jdk8.java.net/lambda The official homepage for this book at the Pragmatic Bookshelf website is http://www.pragprog.com/titles/vsjava8. From there you can download all the example source code for this book. You can also offer feedback by submitting errata entries or posting your comments and questions in the forum for the book. If youre reading the book in the PDF form, you can click on the link above a code listing to view or download the specific examples. Now for some fun with lambda expressions Preface viii Click HERE to purchase this book now. discuss Our Java coding style is ready for a remarkable makeover. The common everyday tasks we perform just got simpler, easier, and more expressive. The new way of programming thats now part of Java has been around for decades in other languages. With these facilities in Java we can write concise, elegant, and expressive code, with fewer errors. We can make use of this to easily enforce policies and implement common design patterns with fewer lines of code. In this book well explore the functional style of programming using direct examples of everyday tasks we do as programmers. Before we take the leap to this elegant style, and this new way to design and program, lets discuss why this change is better. 1.1 Why embrace another paradigm? Imperative stylethats what Java has provided us since its inception. In this style, we tell Java every step of what we want it to do and then watch it faithfully exercise those steps. Thats worked fine, but its a bit low level. The code tends to get verbose, and we often wish the language were a tad more intelligent; we could then tell it, declaratively, what we want rather than delve into how to do it. Thankfully, Java can now help us do that. Lets take a look at a few examples, to see the benefits and the differences in style. Lets start from familiar grounds to see the two paradigms in action. Heres an imperative way to find if Chicago is in a collection of given citiesremember, the listings in this book only have snippets of code (see Section 4, How to read the code examples, on page ?). introduction/fpij/Cities.java boolean found = false; for(String city : cities) { if(city.equals("Chicago")) { found = true; break; } } System.out.println("Found chicago?:" + found); This imperative version is noisy and low level, it has several moving parts. We first initialize a smelly boolean flag named found and then walk through each element in the collection. If we found the city were looking for, then we set the flag and break out of the loop. Finally we print out the result of our finding. As observant Java programmers, the minute we set our eyes on this code wed quickly turn it into something more concise and easier to read, like so: Click HERE to purchase this book now. discuss introduction/fpij/Cities.java System.out.println("Found chicago?:" + cities.contains("Chicago")); Thats one example of declarative style. Instead of beating around a mutable variable with low level commands, the contains() method helped us get directly to our business. It wrapped under the covers the steps necessary to loop through the elements; the declarative style removed the clutter and let us focus on the core behavior we like to implement. The benefitthe code reads pretty close to our business intent. Fewer lines of infrastructure code means the code is less error-prone and easier to maintain. That declarative function to check if an element is present in a collection has been around in Java for a very long time. Now imagine not having to write imperative code for more advanced operations, like parsing files, working with databases, making calls to web services, concurrent programming, etc. Java now makes it possible to write concise, elegant, less error-prone code, not just for simple cases, but throughout our applications. Lets look at another example. Well define a collection of prices and try out a few ways to total discounted price values. final List<Integer> prices = Arrays.asList(10, 15, 20, 25, 30, 45, 50); Suppose were asked to total the prices discounted by 10%. Lets do that in the habitual Java way first. introduction/fpij/DiscountImperative.java double totalOfDiscountedPrices = 0.0; for(int price : prices) { totalOfDiscountedPrices += price * 0.9; } System.out.println("Total of discounted prices: " + totalOfDiscountedPrices); Thats familiar code; we start with a mutable variable to hold the total of the discounted prices. We then loop through the prices, compute the discounted value for each price, one at a time, and add that to the total. Finally we print the total value of the discounted prices. And heres the output from the code. Total of discounted prices: 175.5 It worked, but writing it feels dirty. Its no fault of ours, we had to make use of what was available. But, the code is fairly low level, it suffers from primitive obsession. Those of us working from home have to keep this code away from 2 Click HERE to purchase this book now. discuss the eyes of kids aspiring to be programmers, for they may be dismayed and sigh thats what you do for a living? Now we can do better, a lot better, in such a way that the code resembles the requirement specification. This will help reduce the gap between the business needs and the code that implements it, further reducing the chances of the requirements being misinterpreted. Rather than tell Java to create a mutable variable and then to repeatedly assign to it, lets talk with it at a higher level of abstraction, as in the next code that works in Java 8. introduction/fpij/DiscountFunctional.java final double totalOfDiscountedPrices = prices.stream().map((Integer price) -> price * 0.9).sum(); System.out.println("Total of discounted prices: " + totalOfDiscountedPrices); Lets read that aloudmap the prices to discounted values and then sum them up. The code flows along with logic in the same way wed describe the requirements. The code is concise, but were making use of quite a number of new things from Java 8. First, we invoked a stream() method on the prices list. This opens the door to a special iterator with a wealth of convenience functions which we will discuss later. Instead of explicitly iterating through the prices list, were using a special map method. Unlike the methods were used to in Java and the JDK, this method takes an anonymous functiona lambda expressionas a parameter, within the parenthesis (). Well soon explore this further. On the result of the map() method we invoke the sum() method to compute the total. Much like the way the looping was concealed under the contains() method, the looping is concealed in this version also. The map() method, however, is more sophisticated, for each price in the prices list, it invokes the provided lambda expression and collects back the responses from these calls into a new collec- tion. The sum() method is finally invoked on this collection to get the final result. Heres the output from this version of code: Total of discounted prices: 175.5 Now that weve gotten a taste of the declarative and functional style, lets visit their benefits. Click HERE to purchase this book now. discuss Why embrace another paradigm? 3 The JDK has evolved to include convenience methods that promote functional style. When using familiar classes and interfaces from the library, like String for example, we need to look for opportunities to use these newer functions in place of the old style. Also, anywhere we used an anonymous inner class with just one method, we can now use lambda expressions to reduce clutter and ceremony. In this chapter well use lambda expressions and method references to iterate over a String, to implement Comparators, to list files in a directory, and to observe file and directory changes. Quite a few methods introduced in the previous chapter will appear here again to help with the current tasks on hand. Tech- niques we pick up along the way will help turn long mundane tasks into concise code snippets we can quickly write and easily maintain. 3.1 Iterating a String chars() is a new method in the String class from the CharSequence interface. Its useful to fluently iterate over the Strings characters. We can use this convenient internal iterator to apply an operation on the individual characters that make up the string. Lets make use of it in an example to process a string. Along the way we will pick up a few more useful ways to use method references. compare/fpij/IterateString.java final String str = "w00t"; str.chars().forEach(ch -> System.out.println(ch)); The chars() method returns a Stream over which we can iterate, using the forEach() internal iterator. We get direct read access to the characters in the String within the iterator. Heres the result when we iterate and print each character. Click HERE to purchase this book now. discuss 119 48 48 116 The result is not quite what wed expect. Instead of seeing characters were seeing some numbers. Thats because the chars() method returns a stream of Integers, representing the characters instead of a stream of Characters. Lets explore the API a bit further before we fix the output. In the previous code we created a lambda expression in the argument list for the forEach() method. The implementation was a simple call where we routed the parameter directly as an argument to the println() method. Since this is a trivial operation, we can eliminate this mundane code with the help of the Java compiler. We can rely on it to do this parameter routing for us, using a method reference like we did back in Using Method References, on page ?. We already saw how to create a method reference for an instance method. For example, for the call name.toUpperCase(), the method reference is String::toUp- perCase. In this example, however, we have a call on a static reference System.out. We can use either a class name or an expression to the left of the double colon in method references. Using this flexibility, its quite easy to provide a method reference to the println() method, as we see next. compare/fpij/IterateString.java str.chars().forEach(System.out::println); In this example we see the smarts of the Java compiler for parameter routing. Recall lambda expressions and method references may stand in where implementations of functional interfaces are expected and the Java compiler synthesizes the appropriate method in-place (see Section 1.5, Syntax Sugar with Functional Interfaces, on page ?). In the earlier method reference we used, String::toUppercase; the parameter to the synthesized method turned into the target of the method call, like so: parameter.toUppercase();. Thats because the method reference is based off a class name (String). In this example, the method reference, again to an instance method, is based off an expression, an instance of PrintStream accessed through the static reference System.out. Since we already provided a target for the method, the Java compiler decided to use the parameter of the synthesized method as an argument to the referenced method, like so: System.out.println(parameter);. Sweet. The code with method reference is quite concise, but we have to dig into it a bit more to understand whats going on here. Once we get used to method references, our brains will know to auto-parse these. 6 Click HERE to purchase this book now. discuss In this example, while the code is concise, the output is not satisfactory. We want to see characters and not numbers in their place. To fix that, lets write a convenience method that takes an int and prints it as a character. compare/fpij/IterateString.java private static void printChar(int aChar) { System.out.println((char)(aChar)); } We can use a method reference to this convenience method to fix the output. compare/fpij/IterateString.java str.chars().forEach(IterateString::printChar); We can continue to use the result of chars() as an int and when its time to print we can convert it to a character. The output of this version will display char- acters. w 0 0 t If we want to process characters and not int from the start, we can convert the ints to characters right after the call to the chars() method, like so: compare/fpij/IterateString.java str.chars() .map(ch -> Character.valueOf((char)ch)) .forEach(System.out::println); We used the internal iterator on the Stream returned by the chars() method, but were not limited to that method. Once we get a Stream we can use any methods available on it, like map(), filter(), reduce(), etc. to process the characters in the string. For example, we can filter out only digits from the string, like so, compare/fpij/IterateString.java str.chars() .filter(ch -> Character.isDigit(ch)) .forEach(ch -> printChar(ch)); We can see the filtered digits in the next output. 0 0 Once again, instead of the lambda expressions we passed to the filter() method and the forEach() method, we can replace them with method references to the respective methods. Click HERE to purchase this book now. discuss Iterating a String 7 compare/fpij/IterateString.java str.chars().filter(Character::isDigit).forEach(IterateString::printChar); The method references helped here again to remove the mundane parameter routing. In addition to that, in this example we see yet another variation of method references compared to the previous two instances where we used them. When we first saw method references, we created a method reference for an instance method. Later we created it for a call on a static reference. Now were creating a method reference for a static methodmethod references seem to keep on giving. The method reference for an instance method and a static method structurally look the same: for example, String::toUppercase and Character::isDigit. To decide how to route the parameter, the Java compiler will look up to see if the method is an instance method or a static method. If its an instance method, then the parameter of the synthesized method becomes the target of the call, like in parameter.toUppercase(); (the exception to this rule is if the target is already specified like in System.out::println). On the other hand, if the method is a static method, then the parameter to the synthesized method is routed as an argument to this method, like in Character.isDigit(parameter);. See Appendix 2, Syntax Overview, on page ? for a listing of method references variations and their syntax. While this parameter routing is quite convenient, there is one caveatmethod collisions and the resulting ambiguity. If theres both a matching instance method and a static method, we will get a compilation error due to the ambi- guity of the reference. For example, if we write Double::toString to convert an instance of Double to a String, the compiler would get confused whether to use the public String toString() instance method or the static method public static String toString(double value), both from the Double class. If we run into this, no sweat, simply switch back to using the appropriate lambda expression version to move on. Once we get used to the functional style, we can gradually switch between either the lambda expressions or the more concise method references, based on our comfort level. We used a new method in Java 8 to easily iterate over characters. Next well explore the enhancements to the Comparator interface. 8 Click HERE to purchase this book now. discuss
C++ Programming Cookbook: Proven solutions using C++ 20 across functions, file I/O, streams, memory management, STL, concurrency, type manipulation and error debugging
Building Modern Web Applications With JakartaEE, NoSQL Databases and Microservices: Create Web Applications Jakarta EE with Microservices, JNoSQL, ... and MicroProfile easily (English Edition)