Academia.eduAcademia.edu

Java-Java Script123uo00es

Title Page Java 9 Programming By Example Your guide to software development Peter Verhas BIRMINGHAM - MUMBAI Java 9 Programming By Example Copyright © 2017 Packt Publishing All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews. Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book. Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information. First published: April 2017 Production reference: 1240417 Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK. ISBN 978-1-78646-828-4 www.packtpub.com Credits Author Copy Editors Peter Verhas Muktikant Garimella Zainab Bootwala Reviewer Project Coordinator Jeff Friesen Ulhas Kambali Commissioning Editor Proofreader Kunal Parikh Safis Editing Acquisition Editor Indexer Denim Pinto Mariammal Chettiyar Content Development Editor Graphics Nikhil Borkar Abhinash Sahu Technical Editor Production Coordinator Hussain Kanchwala Melwyn Dsa About the Author Peter Verhas is a senior software engineer and software architect having electrical engineering and economics background from TU Budapest (MsC) and PTE Hungary (MBA), and also studied at TU Delft and TU Vienna. He created his first programs in 1979, and since then he has authored several open source programs. He has worked in several positions in the telecommunications and finance industries and was the CIO of the Hungarian start-up index.hu during its early days. Peter works for EPAM Systems in Switzerland, participating in software development projects at various customer sites, and he supports talent acquisition by interviewing candidates, training programs for developers, and internal mentoring programs. You can follow Peter on Twitter at @verhas, LinkedIn, and GitHub, or read his technical blog, Java Deep, at http://javax0.wordpress.com. Acknowledgement is the section of a book that everybody ignores by turning the pages. This time, this section is a bit different. I will mention a few people and their roles in the making of this book but, at the same time, I will explain why and how it is important to rely on people, being a software developer. Doing professional work is not possible without having a life. It is quite obvious if you take that literally, but it is just as true figuratively. If you do not find the balance between your personal and professional life, you will burn out and will not operate professionally. This is the place to mention my family, my parents whom I am lucky to still have around, my wife, and my already adult kids who never stopped believing in me being able to do this work, who know more than well what a hypocrite I am, advocating personal-professional life balance, and who continually pushed me closer to this equilibrium point in life so that I could keep performing professionally. For professional work, coworkers are almost as important as family support. It is important that you support your colleagues as much as you ask them for their support. You learn a lot from books and from experience, but you learn the most from other people. Pay attention to senior developers. You can, however, learn just as much from juniors. No matter how ace you are, from time to time, a rookie may shed light on a topic. During the years, I learned a lot from juniors who brought a fresh view to the table, asking shocking questions that were absolutely valid. I cannot name each and every junior who aided my work with fresh out-of-the-box thinking. I can, and should, however, name some peer professionals who actively participated in the creation of this book with their advice, discussions, and suggestions. I should certainly mention Károly Oláh who was very enthusiastic about my project, and he represented, supported, and encouraged the idea inside EPAM systems. He actively discussed with the upper management that the support for writing a book well fits the innovation line and development of the company, and the people who work together. Without the official support from the company providing extra time for the task, I would not have been able to create this book. Good company attracts good people who are clever and also good to work with. I had many discussions about the book, topics, and how to explain certain aspects with my fellow EPAMers: Krisztián Sallai, Peter Fodor, Sándor Szilágyi, Mantas Aleknavicius, Gábor Lénard, and many others. I will separately mention István Attila Kovács from our Budapest office with whom I discussed Chapter 5 in detail, and who gave me very valuable feedback about the topic. If he does not know something about Java parallel computing, then that something does not exist. As a summary and takeaway for the patient reader who read this section till the end, technology, knowledge, skills, and experience are extremely important for being a professional Java 9 developer, but it is the people who really matter. About the Reviewer Jeff Friesen is a freelance author and software developer who has taught Java in the classroom and by writing numerous articles and books since the late 1990s. He holds a Bachelor of Science degree in Computer Science and Mathematics. Prior to freelancing, Jeff worked for telecommunications, investment, and software development companies. Jeff freelances as a Java author and software developer. Jeff has written Java I/O, NIO and NIO.2 and Java Threads and the Concurrency Utilities for Apress. Full details are available on his website (http://javajeff.ca/cgi-bin/makepage.cgi?/books). I thank Nitin Dasan for the opportunity to tech review this book. I also thank Ulhas Kambali for assisting me with the tech review process. www.PacktPub.com For support files and downloads related to your book, please visit www.PacktPub.com. Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details. At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks. https://www.packtpub.com/mapt Get the most in-demand software skills with Mapt. Mapt gives you full access to all Packt books and video courses, as well as industry-leading tools to help you plan your personal development and advance your career. Why subscribe? Fully searchable across every book published by Packt Copy and paste, print, and bookmark content On demand and accessible via a web browser Customer Feedback Thanks for purchasing this Packt book. At Packt, quality is at the heart of our editorial process. To help us improve, please leave us an honest review on this book's Amazon page at https://www.amazon.com/dp/178646828X/. If you'd like to join our team of regular reviewers, you can e-mail us at [email protected]. We award our regular reviewers with free eBooks and videos in exchange for their valuable feedback. Help us be relentless in improving our products! Table of Contents Preface What this book covers What you need for this book Who this book is for Conventions Reader feedback Customer support Downloading the example code Errata Piracy Questions 1. Getting Started with Java 9 Getting started with Java Installing Java Installation on Windows Installation on MAC OS X Installation on Linux Setting JAVA_HOME Executing jshell Looking at the byte code Packaging classes into a JAR file Managing the running Java application Using an IDE NetBeans Eclipse IntelliJ IDE services IDE screen structure Editing files Managing projects Build the code and run it Debugging Java Summary 2. The First Real Java Program - Sorting Names Getting started with sorting Bubble sort Getting started with project structure and build tools Make Ant Installing Ant Using Ant Maven Installing Maven Using Maven Gradle Installing Gradle Setting up the project with Maven Coding the sort Understanding the algorithm and language constructs Blocks Variables Types Arrays Expressions Loops Conditional execution Final variables Classes Inner, nested, local, and anonymous classes Packages Methods Interfaces Argument passing Fields Modifiers Object initializers and constructors Compiling and running the program Summary 3. Optimizing the Sort - Making Code Professional The general sorting program A brief overview of various sorting algorithms Quick sort Project structure and build tools Maven dependency management Code the sort Creating the interfaces Creating BubbleSort Amending the interfaces Architectural considerations Creating unit tests Adding JUnit as dependency Writing the BubbleSortTest class Good unit tests A good unit test is readable Unit tests are fast Unit tests are deterministic Assertions should be as simple as possible Unit tests are isolated Unit tests cover the code Refactor the test Collections with wrong elements Handling exceptions Generics Test Driven Development Implementing QuickSort The partitioning class Recursive sorting Non-recursive sorting Implementing the API class Creating modules Why modules are needed What is a Java module Summary 4. Mastermind - Creating a Game The Game The model of the game Java collections Interface collection Set Hash functions Method equals Method hashCode Implementing equals and hashCode HashSet EnumSet LinkedHashSet SortedSet NavigableSet TreeSet List LinkedList ArrayList Queue Deque Map HashMap IdentityHashMap Dependency injection Implementing the game ColorManager The class color JavaDoc and code comments Row Table Guesser UniqueGuesser GeneralGuesser The Game class Creating an integration test Summary 5. Extending the Game - Run Parallel, Run Faster How to make Mastermind parallel Refactoring Processes Threads Fibers java.lang.Thread Pitfalls Deadlocks Race conditions Overused locks Starving ExecutorService ForkJoinPool Variable access The CPU heartbeat Volatile variables Synchronized block Wait and notify Lock Condition ReentrantLock ReentrantReadWriteLock Atomic classes BlockingQueue LinkedBlockingQueue LinkedBlockingDeque ArrayBlockingQueue LinkedTransferQueue IntervalGuesser ParallelGamePlayer Microbenchmarking Summary 6. Making Our Game Professional - Do it as a Webapp Web and network IP TCP/IP DNS The HTTP protocol HTTP methods Status codes HTTP/2.0 Cookies Client server and web architecture Writing servlets Hello world servlet Java Server Pages HTML, CSS, and JavaScript Mastermind servlet Storing state HTTP session Storing state on the client Dependency injection with Guice The MastermindHandler class Storing state on the server The GameSessionSaver class Running the Jetty web servlet Logging Configurability Performance Log frameworks Java 9 logging Logging practice Other technologies Summary 7. Building a Commercial Web Application Using REST The MyBusiness web shop Sample business architecture Microservices Service interface design JSON REST Model View Controller Spring framework Architecture of Spring Spring core Service classes Compiling and running the application Testing the application Integration test Application test Servlet filters Audit logging and AOP Dynamic proxy-based AOP Summary 8. Extending Our E-Commerce Application The MyBusiness ordering Setting up the project Order controller and DTOs Consistency checker Annotations Annotation retention Annotation target Annotation parameters Repeatable annotations Annotation inheritance @Documented annotations JDK annotations Using reflection Getting annotations Invoking methods Setting fields Functional programming in Java Lambda Streams Functional interfaces Method references Scripting in Java 9 Summary 9. Building an Accounting Application Using Reactive Programming Reactive... what? Reactive programming in a nutshell Reactive systems Responsive Resilient Elastic Message-driven Back-pressure Reactive streams Reactive programming in Java Implementing inventory Summary 10. Finalizing Java Knowledge to a Professional Level Java deep technologies Java agent Polyglot programming Polyglot configuration Polyglot scripting Business DSL Problems with polyglot Annotation processing Programming in the enterprise Static code analysis Source code version control Software versioning Code review Knowledge base Issue tracking Testing Types of tests Test automation Black box versus white box Selecting libraries Fit for the purpose License Documentation Project alive Maturity Number of users The "I like it" factor Continuous integration and deployment Release management Code repository Walking up the ladder Summary Preface Java drastically changed with the introduction of Java 8, and this change has been elevated to a whole new level with the new version, Java 9. Java has a well-established past, being more than 20 years old, but at the same time, it is new, functional, reactive, and sexy. This is a language that developers love, and at the same time, it is the number one choice of developer language for many enterprise projects. It is probably more lucrative to learn Java now than ever before, starting with Java 9. We encourage you to start your professional developer career by learning Java 9, and we have done our best in this book to help you along this road. We assembled the topics of the book so that it is easy to start, and you can feel the things working and moving very soon. At the same time, we have tried to reach very far, signaling the road ahead for a professional developer. The sands of time kept moving, and I discovered functional programming. I could very well see why writing side-effect-free code worked! I was hooked and started playing with Scala, Clojure, and Erlang. Immutability was the norm here. However, I wondered how traditional algorithms would look in a functional setting and started learning about it. A data structure is never mutated in place. Instead, a new version of the data structure is created. The strategy of copy and write with maximized sharing was an intriguing one! All that careful synchronization is simply not needed! The languages come equipped with garbage collection. So, if a version is not needed anymore, runtime would take care of reclaiming the memory. All in good time, though! Reading this book will help you see that we need not sacrifice algorithmic performance while avoiding in-place mutation! What this book covers Getting Started with Java 9, gives you a jump start in Java, helping you install it on your computer and run your first interactive programs using the new Jshell. Chapter 1, The First Real Java Program - Sorting Names, teaches you how to create a development project. This time, we will create program files and compile the code. Chapter 2, Optimizing the Sort - Making Code Professional, develops the code further so that the code is reusable and not only a toy. Chapter 3, Mastermind - Creating a Game, is when some fun starts. We develop a game application that is interesting and not as trivial as it first seems, but we will do it. Chapter 4, Extending the Game - Run Parallel, Run Faster, shows you how to utilize the multi-processor capabilities of modern architecture. This is a very important chapter that details technologies, that only a few developers truly understand. Chapter 5, Making Our Game Professional - Do it as a Webapp, transforms the user interface from command-line to web browser-based, delivering better user experience. Chapter 6, Building a Commercial Web Application Using REST, takes you through the development of an application that has the characteristics of many commercial applications. We will use the standard REST protocol which has gained ground in enterprise computing. Chapter 7, Extending Our E-Commerce Application, helps you develop the application further utilizing modern language features such as scripting and lambda expressions. Chapter 8, Building an Accounting Application Using Reactive Programming, teaches you how to approach some problems using reactive programming. Chapter 9, Finalizing Java Knowledge to a Professional Level, gives a bird's-eye view of developer topics that play an important role in the life of a Java developer, and which will guide you further in working as a professional developer. Chapter 10, What you need for this book To immerse into the content of this book and to soak up most of the skills and knowledge, we assume that you already have some experience with programming. We do not assume too much but hope that you already know what a variable is, that computers have memory, disk, network interfaces, and what they generally are. In addition to these basic skills, there are some technical requirements to try out the code and the examples of the book. You need a computer—something that is available today and can run Windows, Linux, or OSX. You need an operating system and, probably, that is all you need to pay for. All other tools and services that you will need are available as open source and free of charge. Some of them are also available as commercial products with an extended feature set, but for the scope of this book, starting to learn Java 9 programming, those features are not needed. Java, a development environment, build tools, and all other software components we use are open source. Who this book is for This book is for anyone who wants to learn the Java programming language. You are expected to have some prior programming experience with another language, such as JavaScript or Python, but no knowledge of earlier versions of Java is assumed. Conventions In this book, you will find a number of text styles that distinguish between different kinds of information. Here are some examples of these styles and an explanation of their meaning. Code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles are shown as follows: "The following function f has a side effect, though." A block of code is set as follows: package packt.java9.by.example.ch03; public interface Sort { void sort(SortableCollection collection); } If there is a line (or lines) of code that needs to be highlighted, it is set as follows: id=123 title=Book Java 9 by Example description=a new book to learn Java 9 weight=300 width=20 height=2 depth=18 New terms and important words are shown in bold. Words that you see on the screen, for example, in menus or dialog boxes, appear in the text like this: "Clicking the Next button moves you to the next screen." Warnings or important notes appear in a box like this. Tips and tricks appear like this. Reader feedback Feedback from our readers is always welcome. Let us know what you think about this book—what you liked or disliked. Reader feedback is important for us as it helps us develop titles that you will really get the most out of. To send us general feedback, simply e-mail [email protected], and mention the book's title in the subject of your message. If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide at www.packtpub.com/authors. Customer support Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase. Downloading the example code You can download the example code files for this book from your account at https://github.com/PacktPublishing/Java -9-Programming-By-Example. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you. You can download the code files by following these steps: 1. 2. 3. 4. 5. 6. 7. Log in or register to our website using your e-mail address and password. Hover the mouse pointer on the SUPPORT tab at the top. Click on Code Downloads & Errata. Enter the name of the book in the Search box. Select the book for which you're looking to download the code files. Choose from the drop-down menu where you purchased this book from. Click on Code Download. Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of: WinRAR / 7-Zip for Windows Zipeg / iZip / UnRarX for Mac 7-Zip / PeaZip for Linux The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Java-9Programming-By_Example. We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out! Errata Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books—maybe a mistake in the text or the code—we would be grateful if you could report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions of this book. If you find any errata, please report them by visiting http://www.packtpub.com/ submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded to our website or added to any list of existing errata under the Errata section of that title. To view the previously submitted errata, go to https://www.packtpub.com/books/content/support and enter the name of the book in the search field. The required information will appear under the Errata section. Piracy Piracy of copyrighted material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works in any form on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy. Please contact us at [email protected] with a link to the suspected pirated material. We appreciate your help in protecting our authors and our ability to bring you valuable content. Questions If you have a problem with any aspect of this book, you can contact us at [email protected], and we will do our best to address the problem. Getting Started with Java 9 You want to learn Java and you have a good reason for it. Java is a modern and well-established application programming language, which is widely used in many industries, be it telecommunication, finance, or something else. Java developer positions are the most numerous and, probably, the best paid. This, among other things, makes the language lucrative for young professionals to learn. On the other hand, this is not without reason. Java language, the tools, and the whole infrastructure around it is complex and compound. Becoming a Java professional does not happen in a day or week; it is a work of many years. To be a Java expert, you need to know not only about the programming language but also about objectoriented programming principles, open source libraries, application servers, network, databases, and many other things that you can become an expert in. Nevertheless, learning the language is an absolute must that all other practices should build on. Through this book, you will be able to learn Java version 9 and a bit more. In this chapter, you will be introduced to the Java environment and given step-by-step instructions on how to install it, edit sample code, compile, and run Java. You will get acquainted with the basic tools that help development, be they are a part of Java or are provided by other vendors. We will cover the following topics in this chapter: Introduction to Java Installing Windows, Linux, and Mac OS X Executing jshell Using other Java tools Using integrated development environment Getting started with Java It is like going through a path in a forest. You can focus on the gravel of the road but it is pointless. Instead, you can enjoy the view, the trees, the birds, and the environment around you, which is more enjoyable. This book is similar as I won't be focusing only on the language. From time to time, I will cover topics that are close to the road and will give you some overview and directions on where you can go further after you finish this book. I will not only teach you the language but also talk a bit about algorithms, object-oriented programming principles, tools that surround Java development, and how professionals work. This will be mixed with the coding examples that we will follow. Lastly, the final chapter will be fully devoted to the topic, what to learn next and how to go further to become a professional Java developer. By the time this book gets into print, Java will have completed 22 years. http://www.oracle.com/technetwork/java/jav ase/overview/javahistory-index-198355.html. The language has changed a lot during this period and got better. The real question to ask is not how long has it been here, but rather how long will it stay? Is it still worth learning this language? There are numerous new languages that have been developed since Java was born (http://blog.takipi.com/java-vs-net-vs-python-vs-ruby-vs-node-js-who-reigns-the-job-market/). These languages are more modern and have functional programming features, which, by the way, Java has also had since version 8. Many say that Java is the past—the future is Scala, Swift, Go, Kotlin, JavaScript, and so on. You can add many other languages to this list, and for each, you can find a blog article that celebrates the burial of Java. There are two answers to this concern-one is a pragmatic business approach, the other is more engineering: Considering that COBOL is still actively used in the finance industry and COBOL developers are perhaps better paid than Java developers, it is not too risky to say that as a Java developer, you will find positions in the next 40 years. Personally, I would bet more than a 100 years, but considering my age, it will not be fair predicting more than 20 to 40 years ahead. Java is not only a language; it is also a technology that you will learn a bit about from this book. The technology includes the Java Virtual Machine (JVM), which is usually referred to as JVM, and gives the runtime environment for many languages. Kotlin and Scala, for example, cannot run without JVM. Even if Java will be adumbrated, JVM will still be a number one player in the enterprise scene. To understand and learn the basic operation of JVM is almost as important as the language itself. Java is a compiled and interpreted language. It is a special beast that forges the best of both worlds. Before Java, there were interpreted and compiled languages. Interpreted languages are read from the source code by the interpreter and then the interpreter executes the code. In each of these languages, there is some preliminary lexical and syntax analysis step; however, after that, the interpreter, which, as a program itself, is executed by the processor and the interpreter continuously, interprets the program code to know what to do. Compiled languages are different. In such a case, the source code is compiled to binary (.exe file on Windows platforms), which the operating system loads and the processor directly executes. Compiled programs usually run faster, but there is usually a slower compilation phase that may make the development slower, and the execution environment is not so flexible. Java combined the two approaches. To execute a Java program, the Java source code has to be compiled to the JVM byte code (.class file), which is loaded by JVM and is interpreted or compiled. Hmm... is it interpreted or compiled? The thing that came with Java is the Just in Time (JIT) compiler. This makes the phase of the compilation that is calculation-intensive and the compilation for compiled languages relatively slow. JVM first starts to interpret the Java byte code and, while doing that, it keeps track of execution statistics. When it gathers enough statistics about code executions, it compiles to native code (for example, x86 code on an Intel/AMD platform) for direct execution of the parts of code that are executed frequently and keeps interpreting the code fragments that are rarely used. After all, why waste expensive CPU time to compile some code that is hardly ever used? (For example, code that reads configuration during startup and does not execute again unless the application server is restarted.) Compilation to the byte code is fast and code generation is done only for the segments that pay off. It is also interesting that JIT uses the statistics of the code execution to optimize the code. If, for example, it sees that some conditional branch is executed in 99% of the cases and the other branch is executed only in 1%, then it will generate native code that runs fast, thus favoring the frequent branch. If the behavior of that part of the program changes by time and the statistic shows that the ratios changed, the JIT automatically recompiles the byte code from time to time. This is all automatic and behind the scenes. In addition to the automatic compilation, there is also an extremely important feature of JVM-it manages the memory for the Java program. The execution environment of modern languages do that and Java was the first mainstream language that had an automatic garbage collection (GC). Before Java, I was programming in C for 20 years and it was a great pain to keep track of all memory allocation and not to forget to release the memory when the program no longer needed it. Forgetting memory allocation at a single point in the code and the long running program was eating up all memory slowly. Such problems practically ceased to exist in Java. There is a price that we have to pay for it—GC needs processor capacity and some extra memory, but that is something we are not short of in most of the enterprise applications. Some special programs, like real-time embedded systems that control the brakes of a heavyduty lorry may not have that luxury. Those are still programmed in assembly or C. For the rest of us, we have Java, and though it may seem strange for many professionals, even almost-real-time programs, such as high-frequency trading applications, are written in Java. These applications connect through the network to the stock exchange and they sell and buy stocks responding to market change in milliseconds. Java is capable of doing that. The runtime environment of Java that you will need to execute a compiled Java code, which also includes the JVM itself, contains code that lets Java programs access the network, files on disks, and other resources. To do this, the runtime contains high-level classes that the code can instantiate, execute, and which do the low-level jobs. You will also do this. It means that the actual Java code does not need to handle IP packets, TCP connections, or even HTTP handling when it wants to use or provide a REST service in some microservices architecture. It is already implemented in the runtime libraries, and all the application programmer has to do is to include the classes in the code and use the APIs they provide on an abstraction level that matches the program. When you program in Java, you can focus on the actual problem you want to solve, which is the business code and not the low-level system code. If it is not in the standard library, you will find it in some product in some external library, and it is also very probable that you will find an open source solution for the problem. This is also a strong point of Java. There is a vast number of open source libraries available for all the different purposes. If you cannot find a library fitting your problem if you start to code some low-level code, then probably you are doing something wrong. There are topics in this book that are important, such as class loaders or reflection, not because you have to use them every day but rather because they are used by frameworks, and knowing them helps understand how these frameworks work. If you cannot solve your problem without using reflection or writing your own class loader or program multithread directly, then you probably chose the wrong framework. There is almost certainly a good one: Apache project, Google, and many other important players in the software industry publish their Java libraries as open source. This is also true for multithread programming. Java is a multithread programming environment from the very beginning. The JVM and the runtime supports programs that execute the code. The execution runs parallel on multiple threads. There are runtime language constructs that support parallel executing programs starting at the very low level to high abstraction. Multithread code utilizes the multicore processors, which are more effective. These processors are more and more common. 20 years ago, only high-end servers had multiple processors and only Digital Alpha processors had 64-bit architecture and CPU clock above 100 MHz. 10 years ago, multiprocessor structure was common on the server side, and about 5 years ago, multicore processors were on some desktops and on notebooks. Today, even mobile phones have them. When Java was started in 1995, the geniuses who created it had seen this future. They envisioned Java to be a write once, run anywhere language. At that time, the first target for the language was applet running in the browser. Today, many think (and I also share this opinion) that applets were a wrong target, or at least things were not done in the right way. As for now, you will meet applets on the Internet less frequently than Flash applications or dinosaurs. However, at the same time, the Java interpreter was also executing server and client applications without any browser; furthermore, as the language and the executing environment developed, these application areas became more and more relevant. Today, the main use of Java is enterprise computing and mobile applications mainly for the Android platform; for the future, the use of the environment is growing in embedded systems as the Internet of things (IoT) comes more and more into picture. Installing Java To develop, compile, and execute Java programs, you will need the Java execution environment. As the operating systems that we usually use for software development do not contain the language preinstalled, you will have to download it. Although, there is multiple implementation of the language, I recommend that you download the official version of the software from Oracle. The official site for java is http://java.co m and this is the site from where the latest release of the language can be downloaded. At the time of writing this book, the 9th version of Java is not yet released. An early pre-release version is accessible via http://jdk9.java.net/download. Later the release versions will also be available from here. What you can download from here is a so called early access version of the code that is available only to experiment with it, and no professionals should use it for real professional purposes On the page, you have to click on the radio button to accept the license. After that, you can click on the link that directly starts the download of the installation kit. The license is a special early access license version that you, as a professional, should carefully read, understand, and accept only if you are agreeable with the terms. There is a separate installation kit for Windows 32 and 64 bit systems, Mac OS X, Linux 32 and 64 bit versions, Linux for ARM processor, Solaris for SPARC processor systems, and Solaris x86 versions. As it is not likely that you will use Solaris, I will detail the installation procedure only for Windows, Linux, and Mac OS X. In later chapters, the samples will always be Mac OS X, but since Java is a write once, run anywhere language, there is no difference after the installation. The directory separator may be slanted differently, the classpath separator character is a semicolon on Windows instead of a colon, and the look and feel of the Terminal or command application is also different. However, where it is important, I will try not to forget to mention it. To confuse you, the Java download for each of these operating system versions lists a link for the JRE and one for the JDK. JRE stands for Java Runtime Environment and it contains all the tools and executables that are needed to run Java programs. JDK is the Java Development Kit that contains all the tools and executables that are needed to develop Java programs including the execution of the Java program. In other words, JDK contains its own JRE. For now, all you need to do is download the JDK. There is one important point of the installation that is the same on each of the three operating systems that you have to be prepared for before the installation: to install Java, you should have administrative privileges. Installation on Windows The installation process on Windows starts by double clicking on the downloaded file. It will start the installer that will present you a welcome screen. Pressing the Next button we get a window where you can select the parts you want to install. Let's leave here the default selection, which means that we install all the downloaded parts of Java and press the button Next. The following window is where we can select the destination folder for the installation. As for now we do not change the directory selected by the installer. Press Next. Later, when you become a professional Java developer, you may decide to install Java to a different location but then you will already have to know what you are doing. You may need to click the Next button a few times and then the installer finishes. Provide the administrative password when asked and voila! Java is installed. This is really the very usual Windows installation process. The last step is to set the environment variable JAVA_HOME. To do that in Windows we have to open the control center and select the Edit environment variables for your account menu. This will open a new window that we should use to create a new environment variable for the current user. The name of the new variable has to be JAVA_HOME and the value should point to the installation directory of the JDK. This value on most of the systems is C:Program FilesJavajdk-9. This is used by many Java programs and tools to locate the Java runtime. Installation on MAC OS X In this section, we will take look at how to install Java step-by-step on an OS X platform. I will describe the installation process for the released version available at the time of writing this book. As for now, the Java 9 early access version is a bit tricky to install. It is probable that version Java 9 will have similar or the same install steps as Java 8 update 92 has. The OS X version of Java comes in the form of a .dmg file. This is a packaging format of OS X. To open it, simply double click on the file in the Download folder where the browser saves it and the operating system will mount the file as a read-only disk image. There is only one file on this disk: the installation image. Double click on the file name or icon in the Finder application and the installation process will start. The first screen opening is a welcome screen. Click Continue and you will see the Summary page that displays what will be installed. It is not a surprise that you will see a standard Java installation. This time, the button is called Install. Click on it and you will see the following: This is the time when you have to provide the login parameters for the administrative user—a username and password. When provided, installation starts and, in a few seconds, you will see a Summary page. Click Close and you are ready. You have Java installed on your Mac. Optionally, you can dismount the installation disk and, sometime later, you can also delete the .dmg file. You will not need that, and in case you do, you can download it any time from Oracle. The last thing is to check whether the installation was okay. Proof of the pudding is eating it. Start a Terminal window and type java -version at the prompt and Java will tell you the version installed. On the next screenshot you can see the output on my workstation and also the Mac OS commands that are handy to switch between the different versions of Java: On the screenshot, you can see that I have installed the Java JDK 1.8u92 version and, at the same time, I also have a Java 9 early release installation, which I will use to test the new features of Java for this book. Installation on Linux There are several ways to install Java on Linux, depending on its flavor. Here, I will describe an installation method that works more or less the same way on all flavors. The one I used is Debian. First step is the same as in any other operating system: download the installation kit. In the case of Linux, you should select a package that has a tar.gz ending. This is a compressed archive format. You should also carefully select the package that matches the processor in your machine and the 32/64 bit version of the operating system. After the package is downloaded, you have to switch to root mode, issuing the su command. This the first command you can see on the screenshot that shows the installation commands. The tar command uncompressed the archive into a subfolder. In Debian, this subfolder has to be moved to /opt/jdk and the mv command is used for this purpose. The two update-alternatives command is Debianspecific. These tell the operating system to use this newly installed Java in case there is already an older Java installed. The Debian I was using to test and demonstrate the installation process on a virtual machine came with a 7 year old version of Java. The final step of the installation is the same as any other operating system: checking that the installation was successful in issuing the java -version command. In the case of Linux, this is even more important because the installation process does not check that the downloaded version matches the operating system and the processor architecture. Setting JAVA_HOME The JAVA_HOME environment variable plays a special role for Java. Even though the JVM executable, java.exe or java, is on the PATH (thus you can execute it by typing the name java without specifying directory on the Command Prompt) (Terminal), it is recommended that you use the correct Java installation to set this environment variable. The value of the variable should point to the installed JDK. There are many Javarelated programs, for example, Tomcat or Maven, that use this variable to locate the installed and currently used Java version. In Mac OS X, setting this variable is unavoidable. In OS X, the program that starts to execute when you type java is a wrapper that first looks at JAVA_HOME to decide which Java version to start. If this variable is not set, then OS X will decide on its own, selecting from the available installed JDK versions. To see the available versions, you can issue the following command: ~$ /usr/libexec/java_home -V Matching Java Virtual Machines (10): 9, x86_64: "Java SE 9-ea" /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home 1.8.0_92, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home 1.7.0_60, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_60.jdk/Contents/Home /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home You will then get the list of installed JDKs. Note that the command is lowercase, but the option is capital. If you do not provide any options and argument to the program, it will simply return the JDK it thinks is the newest and most appropriate for the purpose. As I copied the output of the command from my Terminal window, you can see that I have quite a few versions of Java installed on my machine. The last line of the program response is the home directory of JDK, which is the default. You can use this to set your JAVA_HOME variable using some bash programming: export JAVA_HOME=$(/usr/libexec/java_home) You can place this file in your .bashrc file, which is executed each time you start Terminal application and thus JAVA_HOME will always be set. If you want to use a different version, you can use -v, with the lower case option this time, to the same utility, as follows: export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) The argument is the version of Java you want to use. Note that this versioning becomes: export JAVA_HOME=$(/usr/libexec/java_home -v 9) If you want to use Java JDK Early Access version and not 1.9, there is no explanation for the same—fact of life. Note that there is another environment variable that is important for Java-CLASSPATH. We will talk about it later. Executing jshell Now that we have spent a lot of time installing Java, it is time to get the fingers burnt a bit. As we are using Java 9, there is a new tool that helps developers to play around with the language. This is a ReadEval-Print-Loop (REPL) tool that many language toolsets contain and there were also implementations from Java, but version 9 is the first that contains this feature off the shelf. REPL is a tool that has interactive prompt and language commands that can be directly entered without editing some standalone file. The entered commands are executed directly and then the loop starts again, waiting for the user to type in the next command. This is a very effective tool to try out some language constructs without the delay of editing, compiling, and loading. The steps are automatically and transparently done by the REPL tool. The REPL tool in Java 9 is called jshell. To start it, just type its name. If it is not on the PATH, then type the full path to jshell that comes installed with Java 9, as shown in the following example: $ jshell | Welcome to JShell -- Version 9-ea | For an introduction type: /help intro jshell> The jshell starts up in an interactive way and the prompt it displays is jshell> to help you recognize that jshell is running and what you type is read by the program and not the operating system shell. As this is the first time you will start jshell, it tells you to type /help intro. Let's do it. It will print out a short text about what jshell is, as shown in the following code: jshell> /help intro | | intro | | The jshell tool allows you to execute Java code, getting immediate results. | You can enter a Java definition (variable, method, class, etc), like: int x = 8 | or a Java expression, like: x + x | or a Java statement or import. | These little chunks of Java code are called 'snippets'. | | There are also jshell commands that allow you to understand and | control what you are doing, like: /list | | For a list of commands: /help Okay, so we can type Java snippets and /list, but that is only one example of the available commands. We can hope for more information by typing /help, as shown in the following code: jshell> /help | Type a Java language expression, statement, or declaration. | Or type one of the following commands: | /list [<name or id>|-all|-start] | /edit <name or id> | /drop <name or id> | /save [-all|-history|-start] <file> ... ----- list the source you have typed edit a source entry referenced by name or id delete a source entry referenced by name or id Save snippet source to a file. What you get is a long list of commands. Most of it is not presented here to save paper and your attention. We will use many of these commands on our journey through the next few pages. Let's start with a small Java snippet that is the ageless Hello World example: jshell> System.out.println("Hello World!") Hello World! This is the shortest ever Hello World program in Java. Till Java 9, if you wanted to do nothing more than print out Hello World!, you had to create a program file. It had to contain the source code of a class including the public static main method, which contained the one line we had to type in with Java 9 jshell. It was cumbersome just for a simple printout of sample code. Now it is much easier and jshell is also lenient, forgiving us the missing semicolon at the end of the line. The next thing we should try is declaring a variable, as follows: jshell> int a = 13 a ==> 13 jshell> We declared a variable, named a, and assigned the value to it-13. The type of the variable is int, which is an abbreviation for integer types in Java. Now we have this variable already in our snippet, so we can print it out if we want to as shown: jshell> System.out.println(a) 13 It is time to write something more complex into jshell than a one liner. jshell> void main(String[] args){ ...> System.out.println("Hello World") ...> } | Error: | ';' expected | System.out.println("Hello World") | The jshell recognizes that this is not a one-liner and that it cannot process what we typed so far, when we press Enter at the end of the first line, and it signals that it expects more characters from us, so it displays ...> as a continuation prompt. We type in the commands that make up the whole hello world main method, but this time jshell does not let us miss the semicolon. That is allowed only in the case of one-line snippets. As jshell is interactive, it is easy to correct the mistake; press the up arrow key a few times to get back the previous lines and, this time, add the semicolon at the end of the second line: jshell> void main(String[] args){ ...> System.out.println("Hello World"); ...> } | created method main(String[]) This method was created for us as a snippet and now we can call it: jshell> main(null) Hello World And it works. You can list all the snippets that were created, as follows: jshell> /list 1 : System.out.println("Hello World!") 2 : int a = 13; 3 : System.out.println(a) 4 : void main(String[] args){ System.out.println("Hello World"); } And, as we want to go on writing a full Java version of hello world, we can save our work from jshell to a file, as follows: jshell> /save HelloWorld.java Finally, we exited from jshell by typing /exit. As you get back to the system prompt, type cat (or type HelloWorld.java on Windows) to see the content of the file. It is as follows: HelloWorld.java $ cat HelloWorld.java System.out.println("Hello World!") int a = 13; System.out.println(a) void main(String[] args){ System.out.println("Hello World"); } The file contains all the snippets that we typed in one after the other. If you think that you have messed up the shell with lots of variables and code snippets that you do not need anymore, you can issue the /reset command: jshell> /reset | Resetting state. After this command, the jshell is as clean as when it was started earlier jshell> /list jshell> Listing just does not produce anything as we deleted it all. Fortunately, we saved the state of jshell to a file and we can also load the content of the file issuing the /open command: jshell> /open HelloWorld.java Hello World! 13 It loads the line from the file and executes it just as the characters were typed into the Command Prompt. You may recall that the /list command printed a number in front of each snippet. We can use it to edit the snippets individually. To do so, issue the /edit command followed by the number of the snippet: jshell> /edit 1 You may recall that the first command we entered was the System.out.println system call that prints out the argument to the console. When you press Enter after the /edit 1 command, you do not get the prompt back. Instead, jshell opens a separate graphical editor that contains the snippet to edit as shown in the following image: Edit the text in the box so that it will look like this: printf("Hello World!") Click on Accept and then Exit. When you click on Accept, the Terminal will execute the snippet and display the following result: Hello World! The method that we used, printf, stands for formatted printing. This may be well known from many other languages. It was first introduced by the C language and though cryptic, the name survived. This is also part of the standard Java class, PrintStream, just like println. In case of println, we had to write System.out in front of the method name. In case of printf, we did not. Why? The reason is that jshell defines a few snippets that are automatically loaded when jshell starts or resets. You can see these if you issue the /list command with the -start option, as follows: jshell> /list -start s1 s2 s3 s4 s5 s6 s7 s8 : : : : : : : : import java.util.*; import java.io.*; import java.math.*; import java.net.*; import java.util.concurrent.*; import java.util.prefs.*; import java.util.regex.*; void printf(String format, Object... args) { System.out.printf(format, args); } These predefined snippets help the use of jshell. Most of the users will import these classes, and to ease the print to screen, it defines a method snippet that happens to have the name, printf, which is also the name of a method in the PrintStream class. If you want to list all the snippets you entered as well as the predefined snippets and also those that contained some error and thus were not executed, you can use the -all option to the /list command, as follows: jshell> /list -all ... s7 : import java.util.regex.*; ... 1 : System.out.println("Hello World!") ... e1 : System.out.println("Hello World!") int a = 14; 5 : System.out.println("Hello World!"); ... Some of the lines were deleted from the actual output for brevity. The lines that are preloaded are numbered with the s prefix. The snippets that contain an error have a number prefixed with e. If you want to execute some of the snippets again, you only have to type /n where n is the number of the snippet, as follows: jshell> /1 System.out.println("Hello World!") Hello World! You cannot re-execute the preloaded snippets or snippets that contained errors. There is no need for any of those anyway. Preloaded snippets declare some imports and define a snippet method; erroneous snippets do not execute because they are, well...erroneous. You need not rely on the number of jshell when you want to re-execute a snippet. When you already have a lot of snippets in your jshell session, listing them all would be too cumbersome; there is a shortcut to reexecute the last n-th snippet. You have to write /-n. Here, n is the number of the snippet counting from the last one. So, if you want to execute the very last snippet, then you have to write /-1. If you want to execute the one before the last one, you have to write /-2. Note that if you already typed /-1, then the last one is the re-execution of the last snippet and snippet number -2 will become number -3. Listing all the snippets can also be avoided in other ways. When you are interested only in certain types of snippets, you can have special commands. If we want to see only the variables that we defined in the snippets, then we can issue the /vars command, as follows: jshell> /vars | int a = 13 If we want to see only the classes, the command/types will do that: jshell> class s {} | created class s jshell> /types | class s Here, we just created an empty class and then we listed it. To list the methods that were defined in the snippets, the /methods command can be issued: jshell> /methods | printf (String,Object...)void | main (String[])void You can see in the output that there are only two methods, which are as follows: : This is defined in a preloaded snippet main: This, we defined printf If you want to see everything you typed, you have to issue the /history command for all the snippets and commands that you typed. (I will not copy the output here; I do not want to shame myself. You should try yourself and see your own history.) Recall that we can delete all the snippets issuing the /reset command. You can also delete snippets individually. To do so, you should issue the /drop n command, where n is the snipped number: jshell> /drop 1 | This command does not accept the snippet '1' : System.out.println("Hello World!") | See /types, /methods, /vars, or /list Oops! Something went wrong. There is nothing defined when snippet number 1 was executed and the /drop command actually drops the defined variable, type, or method. There is nothing to be dropped in the first snippet. But, if we reissue the /list command, we will get the following results: jshell> /list 1 2 3 4 : : : : System.out.println("Hello World!") int a = 13; System.out.println(a) void main(String[] args){ System.out.println("Hello World"); } We can see that we can drop the second or the fourth snippet, too: jshell> /drop 2 | dropped variable a jshell> /drop 4 | dropped method main(String[]) The jshell error message says to see the output of the /types, /methods, /vars, or /list commands. The problem with this is that /types, /methods, and /vars do not display the number of the snippet. This is most probably a small bug in the jshell prerelease version and may be fixed by the time the JDK is released. When we were editing the snippets, jshell opened a separate graphical editor. It may happen that you are running jshell using ssh on a remote server and where it is not possible to open a separate window. You can set the editor using the /set command. This command can set quite a few configuration options of the jshell. To set the editor to use the ubiquitous vi, issue the following command: jshell> /set editor "vi" | Editor set to: vi After this, jshell will open the snipped-in vi in the same Terminal window where you issue the /edit command. It is not only the editor that you can set. You can set the startup file, and the way jshell prints the feedback to the console after a command was executed. If you set the startup file, then the commands listed in the startup file will be executed instead of the builtin commands of jshell after the /reset command. This also means that you will not be able to use the classes directly that are imported by default and you will not have the printf method snippet, unless your own startup file contains the imports and the definition of the snippet. Create the sample.startup file with the following content: void println(String message) { System.out.println(message); } Starting up a new jshell and executing it is done as follows: jshell> /set start sample.startup jshell> /reset | Resetting state. jshell> println("wuff") wuff jshell> printf("This won't work...") | Error: | cannot find symbol | symbol: method printf(java.lang.String) | printf("This won't work...") | ^----^ The println method is defined but the printf method, which was defined in the default startup, is not. The feedback defines the prompt jshell prints and then waits for the input, the prompt for the continuation lines, and the message details after each command. There are predefined modes, which are as follows: Normal Silent Concise Verbose Normal is selected by default. If you issue /set feedback silent, then prompt becomes -> and jshell will not print details about the commands. The /set feedback concise code prints a bit more information and /set feedback verbose prints verbose information about the commands executed: jshell> /set feedback verbose | Feedback mode: verbose jshell> int z = 13 z ==> 13 | modified variable z : int | update overwrote variable z : int You can also define your own modes, giving a name to the new mode using the /set mode xyz command where xyz is the name of the new mode. After this, you can set prompt, truncation, and format for the mode. When the format is defined, you can use it the same way as the built-in modes. Last, but not least, the most important command of jshell is /exit. This will just terminate the program and you will return to the operating system shell prompt. Now, let's edit the HelloWorld.java file to create our first Java program. To do so, you can use vi, notepad, Emacs, or whatever is available on your machine and fits you. Later on, we will use some integrated development environment (IDE), NetBeans, Eclipse, or IntelliJ; however, for now, a simple text editor is enough. Edit the file so that the content will be as follows: public class HelloWorld { public static void main(String[] args){ System.out.println("Hello World"); } } To compile the source code to byte code, which is executable by JVM, we have to use the Java compiler named javac: javac HelloWorld.java This generates the java.class file in the current directory. This is a compiled code that can be executed as follows: $ java HelloWorld Hello World With this one, you have created and executed your first full Java program. You may still wonder what we were doing. How and why, I will explain it; but first, I wanted you to have a feeling that it works. The file we edited contained only the snippet and we deleted most of the lines, except the declaration of the main method and we inserted the declaration of the class around it. In Java, you cannot have standalone methods or functions, like in many other languages. Every method belongs to some class and every class should be declared in a separate file (well, almost, but for now, let's skip the exceptions). The name of the file has to be the same as the name of the class. The compiler requires this for public classes. Even for non-public classes we usually follow this convention. If you renamed the file from HelloWorld.java to Hello.java, the compiler will display an error when you try to compile the file with the new name. $ mv HelloWorld.java Hello.java ~/Dropbox/java_9-by_Example$ javac Hello.java Hello.java:2: error: class HelloWorld is public, should be declared in a file named HelloWorld.java public class HelloWorld { ^ 1 error So, let's move it back to the original name: mv . Hello.java HelloWorld.java The declaration of the class starts with the keyword class, then the name of the class, an opening curly brace, and lasts until the matching closing brace. Everything in between belongs to the class. For now, let's skip why I wrote public in front of the class and focus on the main method in it. The method does not return any value, therefore; the return value of it is void. The argument, named args, is a string array. When JVM starts the main method, it passes the command-line arguments to the program in this array. However, this time we do not use it. The main method contains the line that prints out Hello World. Now, let's examine this line a bit more. In other languages, printing something to the console requires only a print statement or a very similar command. I remember that some BASIC interpreters even allowed us to type ? instead of print because printing to the screen was so common. This has changed a lot during the last 40 years. We use graphical screens, Internet, and many other input and output channels. These days, it is not very common to write to the console. Usually, in professional large-scale enterprise applications, there is not even a single line that does that. Instead, we will direct the text to log files, send messages to message queues, and send requests and reply with responses over TCP/IP protocol. As this is so infrequently used, there is no reason to create a shortcut for the purpose in the language. After the first few programs, when you get acquainted with the debugger and logging possibilities, you will not print anything directly to the console yourself. Still, Java has features that let you send text directly to the standard output of a process the good old way, as it was invented originally for UNIX. This is implemented in a Java way where everything has to be an object or class. To get access to the system output, there is a class named System and it, among other things, has the following three variables: : This is the standard input stream out: This is the standard output stream err: This is the standard error stream in To refer to the output stream variable, because it is not in our class but in System, we will have to specify the class name so we will refer to it as System.out in our program. The type of this variable is PrintStream, which is also a class. Class and type are synonyms in Java. Every object that is of type PrintStream has a method named println that accepts a String. If the actual print stream is the standard output, and we are executing our Java code from the command line, then the string is sent to the console. The method is named main and this is a special name in Java programs. When we start a Java program from the command line, JVM invokes the method named main from the class that we specify on the command line. It can do that because we declared this method public so that anyone can see and invoke it. If it was private, it would be seen and callable only from within the same class, or classes, that are defined in the same source file. The method is also declared as static, which means that it can be invoked without an actual instance of the class that contains the methods. Using static methods is usually seen as not a good practice these days, unless they are implementing functions that cannot really ever be related to an instance, or have different implementations such as the functions in the java.lang.Math class; but, somewhere, the code execution has to start and the Java runtime will not usually create instances of classes for us automatically. To start the code, the command line should be as follows: java -cp . HelloWorld The -cp option stands for classpath. The classpath is a fairly complex idea for java but, for now, let's make it simple and say that it is a list of directories and JAR files that contain our classes. The list separator for the classpath is : (colon) on UNIX-like systems and ; (semicolon) on Windows. In our case, the classpath is the actual directory, as that is the place where the Java compiler created HelloWorld.class. If we do not specify classpath on the command line, Java will use the current directory as a default. That is the reason our program was working without the -cp option in the first place. Both java and javac handle many options. To get a list of the options type javac -help or java -help. We use the IDE to edit the code and, many times, to compile, build, and run it during development. The environment in this case sets the reasonable parameters. For production we use build tools that also support the configuration of the environment. Because of this, we rarely meet these command line options. Nevertheless, professionals have to understand their meanings at least and know where to learn their actual use in case it is needed. Looking at the byte code The class file is a binary file. The main role of this format is to be executed by the JVM and to provide symbolic information for the Java compiler when a code uses some of the classes from a library. When we compile our program that contains System.out.println, the compiler looks at the compiled .class files and not at the source code. It has to find the class named System, the field named out, and the method println. When we debug a piece of code or try to find out why a program does not find a class or method, we will need a way to look into the binary of the .class files. This is not an everyday task and it takes some advanced knowledge To do so, there is a decompiler that can display the content of a .class file in a more or less readable format. This command is called javap. To execute it, you can issue the following command: $ javap HelloWorld.class Compiled from "HelloWorld.java" public class HelloWorld { public HelloWorld(); public static void main(java.lang.String[]); } The output of the program shows that the class file contains Java class that has something called HelloWorld(); it seems to be a method having the same name as the class and it also contains the method we have written. The method that has the same name as the class is the constructor of the class. As every class in java can be instantiated, there is a need for a constructor. If we do not give one, then the Java compiler will create one for us. This is the default constructor. The default constructor does nothing special but returns a new instance of the class. If we provide a constructor on our own, then the Java compiler will not have bothered creating one. The javap decompiler does not show what is inside the methods or what Java code it contains unless we provide the -c option: $ javap -c HelloWorld.class Compiled from "HelloWorld.java" public class HelloWorld { public HelloWorld(); Code: 0: aload_0 1: invokespecial #1 // 4: return public static void main(java.lang.String[]); Code: 0: getstatic #2 // 3: ldc #3 // 5: invokevirtual #4 // 8: return } Method java/lang/Object."<init>":()V Field java/lang/System.out:Ljava/io/PrintStream; String hali Method java/io/PrintStream.println:(Ljava/lang/String;)V It is very cryptic and is not for ordinary humans. Only a few experts, who deal with the Java code generation, can fluently read that. But, to have a look at it helps you get a glimpse of what byte code means. It is something like a good old assembly. Although this is binary code, there is nothing secret in it: Java is open source, the class file format is well documented and debuggable for the experts. Packaging classes into a JAR file When you deliver a Java application, usually the code is packaged into JAR, WAR, EAR, or some other packaged format. We learn something again that seems to be obscure at first sight, but in reality, this is not that complex. They are all ZIP files. You can open any of these files using WinZip or some other zip manager that you have a license for. The extra requirement is that, for example, in the case of a JAR file, the archive should contain a directory named META-INF and inside it a file named MANIFEST.MF. This file is a text file and contains meta information in the format, which is as follows: Manifest-Version: 1.0 Created-By: 9-ea (Oracle Corporation) There can be a lot of other information in the file, but this is the minimum that the Java provided tool jar puts there if we package our class file into a jar issuing the following command: jar -cf hello.jar HelloWorld.class The -c option tells the JAR archiver to create a new JAR file and the option f is used to specify the name of the new archive. The one we specified here is hello.jar and the file added to it is the class file. The packaged JAR file can also be used to start the Java application. Java can read directly from JAR archives and load classes from there. The only requirement is that they are on the classpath. Note that you cannot put individual classes on the classpath, only directories. As JAR files are archives with an internal directory structure in them, they behave like a directory. Check that the JAR file was created using ls hello.jar and remove the rm HelloWorld.class class file just to ensure that when we issue the command line, the code is executed from the JAR file and not the class. $ java -cp hello.jar HelloWorld Hello World To see the content of the JAR file, however, it is recommended that you use the JAR tool and not WinZip even though that may be cozier. Real professionals use the Java tools to handle Java files. $ jar -tf hello.jar META-INF/ META-INF/MANIFEST.MF HelloWorld.class Managing the running Java application The Java toolset that comes with the JDK supports the execution and management of running Java applications as well. To have some program that we can manage while executing, we will need a code that runs not only for a few milliseconds but, while it runs, it also prints something to the console. Let's create a new program called HelloWorldLoop.java with the following content: public class HelloWorldLoop { public static void main(String[] args){ for( ;; ){ System.out.println("Hello World"); } } } The program contains a for loop. Loops allow repeated execution of a code block, and we will discuss them in Chapter 2, The First Real Java Program - Sorting Names. The loop we created here is a special one that never terminates but repeats the printing method call, printing Hello World until we kill the program by pressing Ctrl + c or issuing a kill command on Linux or on OSX, or terminate the program in the task manager under Windows. Compile and start it in one window and open another Terminal window to manage the application. The first command that we should get familiar with is jps. http://docs.oracle.com/javase/7/docs/technotes/tools/share/jps.ht ml It lists the Java processes that run on the machine, which are as follows: $ jps 21873 sun.tools.jps.Jps 21871 HelloWorldLoop You can see that there are two processes—one is the program we execute and the other is the jps program itself. Not surprisingly, the jps tool is also written in Java. You can also pass options to jps, which are documented on the web. There are many other tools and we will examine one of them, which is a very powerful and easy-to-use tool—Java VisualVM. VisualVM is a command-line graphical tool that connects to the running Java process and displays the different performance parameters. To start the VisualVM tool, you will issue the jvisualvm command without any parameters. Soon, a window will appear with an exploring tree on the left-hand side and a welcome pane on the right. The left side shows all the running Java processes under the branch named Local. If you double click on HelloWorldLoop, it will open the details of the process on the right pane. On the header tabs, you can select Overview, Monitor, Threads, Sampler, and Profiler. The first three tabs are the most important and give you a good view of what is happening in JVM regarding the number of threads, CPU usage, memory consumption, and so on. Using an IDE Integrated development environments are outstanding tools that help the development by offloading the mechanical tasks from the developer's shoulders. They recognize many of the programming errors as we type the code, help us find the needed library methods, display the documentation of the libraries, and provide extra tools for style checking, debugging, and so on. In this section, we will look at some IDEs and how to leverage the functions they provide. To get an IDE, you will have to download and install it. It does not come with the Java development tools because they are not part of the language environment. But, don't worry. They can be downloaded free of charge and are easy to install. They may be more complex to start up than a notepad editor, but even after a few hours of work, they will pay back the time you devote to learning them. After all, it is not without reason that no developer is coding Java in notepad or vi. The three topmost IDEs are NetBeans, Eclipse, and IntelliJ. All are available in community versions, which means that you need not pay for them. IntelliJ has a full version that you can also buy. The community edition will be usable for learning the language. In case you do not like IntelliJ, you can use Eclipse or NetBeans. These are all free of charge. Personally, I use the IntelliJ community edition for most of my projects and the screen samples that show an IDE in this book will feature this IDE. But, it does not necessarily mean that you have to stick to this IDE. In the developer community, there are topics that can be heavily debated. These topics are about opinions. Were they about facts the debate would easily be soon over. One such topic is: "Which is the best IDE?" It is a matter of taste. There is no definite answer. If you learn how to use one, you will like that and you will be reluctant to learn another one, unless you see that the other one is so much better. That is the reason developers love the IDE they use (or just hate, depending on their personality), but they keep using the same IDE usually for a long time. There is no best IDE. To download the IDE of your choice, you can visit either one of the following websites: for NetBeans http://www.eclipse.org/ for Eclipse https://www.jetbrains.com/idea/ for IntelliJ https://netbeans.org/ NetBeans NetBeans is supported by Oracle and is continuously developed. It contains components, such as the NetBeans profiler, that became part of the Oracle Java distribution. You may notice that when you start Visual VM and start the profiling, the Java process started has netbeans in its name. Generally, NetBeans is a framework to develop rich client applications and the IDE is only one application of the many that are built on top of the framework. It supports many languages, not only Java. You can develop PHP, C, or JavaScript code using NetBeans and have similar services for Java. For the support of different languages, you can download plugins or a special version of NetBeans. These special versions are available from the download page of the IDE and they are nothing more than the basic IDE with some preconfigured plugins. In the C package, the developers configure the plugins that are needed when you want to develop C; in the PHP version, they plugin for PHP. Eclipse Eclipse is supported by IBM. Similar to NetBeans, it is also a platform for rich client application and it is built around the OSGi container architecture, which itself is a topic that can fill a book like this. Most of the developers use Eclipse and, almost exclusively, it is the choice when developers create code for the IBM WebSphere application server. The Eclipse special version contains a developer version of WebSphere. Eclipse also has plugins to support different programming languages and also has different variations similar to NetBeans. The variations are plugins prepackaged with the basic IDE. IntelliJ The last one in the preceding enumeration is IntelliJ. This IDE is the only one that does not want to be a framework. IntelliJ is an IDE. It also has plugins, but most of the plugins that you will need to download to use in NetBeans or Eclipse are preconfigured. When you want to use some more advanced plugin, it may however be something you have to pay for, which should not be a problem when you are doing professional, paid work, should it? These things are not that expensive. For learning the subjects in this book, you will not need any plugin that is not in the community edition. As in this book, I will develop the samples using IntelliJ and I recommend that you follow me during your learning experience. I want to emphasize that the examples in this book are independent of the actual IDE to be used. You can follow the book using NetBeans, Eclipse, or even Emacs, notepad, or vi. IDE services Integrated development environments provide us with services. The most basic service is that you can edit files with them, but they also help build the code, find bugs, run the code, deploy to the application server in development mode, debug, and so on. In the following sections, we will look at these features. I will not give an exact and precise introduction on how to use one or the other IDE. A book like this is not a good medium for such a tutorial. IDEs differ on menu placement, keyboard shortcuts, and they may even change as newer versions are released. It is best to look at the actual IDE tutorial video or online help. Their features, on the other hand, are very similar. IntelliJ has the video documentation at https://www.jetbrains.com/idea/documentation/. IDE screen structure The different IDEs look similar, and have the same screen structure more or less. In the following screenshot, you can see an IntelliJ IDE: On the left side, you can see the file structure of a Java project. A Java project typically contains many files in different directories which we will discuss in the next chapter. The simple HelloWorld application contains a pom.xml project description file. This file is needed for the Maven build tool, which is also a topic for the next chapter. For now, you should only know that it is a file that describes the project structure for maven. The IDE also keeps track of some administrative data for itself. It is stored in HelloWorld.iml. The main program file is stored in the src/main/java directory and named HelloWorld.java. On the right side, you can see the files. In the screenshot, we have only one file opened. In case there is more than one file opened, then there are tabs-one for each file. Now, the active file is HelloWorld.java that can be edited in the source code editor. Editing files When editing, you can type in characters or delete characters, words, and lines, but this is something that all editors can do. IDEs offer extra. IDEs analyze the source code and format it, which, in turn, automatically indents the lines. It also continuously compiles the code in the background while you edit it and if there is some syntax error, then it underlines it with a red waiving line. When you fix the error, the red underlining disappears. The editor also automatically gives suggestions for further characters as you type. You can ignore the window that pops up and continue typing. However, many times, it is easier to stop after a character and use the up and down arrows to select the word that needs finishing before pressing Enter: the word will be inserted into the source code automatically. In the screenshot, you can see that I wrote System.o and the editor immediately suggested that I wanted to write out. The other alternatives are the other static fields and methods that are in the class System and which contain the letter o. The IDE editor gives you hints not only when it can type for you, but also when it cannot type instead of you. In the screenshot, the IDE tells you to type some expression as argument to the println()method that is boolean, char, int, and so on. The IDE has absolutely no idea what to type there. You have to construct the expression. Still, it can tell you that it needs to be of a certain type. It is not only the built-in types that the editor knows. The editor integrated with the JDK continuously scans the source files and knows what classes, methods, and fields are there in the source code which are usable at the place of editing. This knowledge is also heavily used when you want to rename a method or variable. The old method was to rename the field or method in the source file and then do an exhaustive search for all references to the variable. Using the IDE, the mechanical work is done by it. It knows all the uses of a field or method and automatically replaces the old identifier with the new one. It also recognizes whether a local variable happens to have the same name as the one that we rename, and the IDE only renames those occurrences that are really referring to the one we are renaming. You can usually do more than just renaming. There are more or less mechanical tasks that programmers call refactoring. These are supported by the IDEs using some keyboard shortcut and context sensitive menu in the editor—right click on the mouse and click Menu. The IDE also helps you to read the documentation of the libraries and source code as shown in the following image: Libraries provide Javadoc documentation for the public methods and you should also write Javadoc for your own method. Javadoc documentation is extracted from special comments in the source code and we will learn how to create those in Chapter 4, Mastermind - Creating a Game. These are located in comments in front of the actual method head. As creating compiled documentation is part of the compilation flow, the IDE also knows the documentation and it displays as a hovering box over the method names, class names, or whatever element you want to use in the source file when you position the cursor on the element. Managing projects On the left side of the IDE window, you can see the directory structure of the project. The IDE knows the different types of files and shows them in a way that is meaningful from the programming point of view. For example, it does not display Main.java as a filename. Instead, it displays Main and an icon that signals that Main is a class. It can also be an interface still in a file named Main.java but, in that case, the icon will show that this is an interface. This is again done by the IDE continuously scanning and compiling the code. The files are structured into subdirectories when we develop a Java code. These subdirectories follow the packaging structure of the code. Many times, in Java, we use compound and long package names, and displaying it as a deep and nested directory structure will not be so easy to handle. Packages are used to group the source files. The source files for classes that are related in some way should go into one package. We will discuss the notion of packages and how to use them in the next chapter The IDE is capable of showing the package structure instead of the nested directories for those directories of the project that contain source files. When you move a class or an interface from one package to another, it happens in a similar way as renaming or other refactoring. All references to the class or interface in the source files get renamed to the new package. If a file contains an import statement referring to the class, the name of the class in the statement is corrected. To move a class, you can open the package and use the good old drag and drop. Package hierarchy is not the only hierarchy displayed in the IDE. The classes are in packages but, at the same time, there is an inheritance hierarchy. Classes may implement interfaces and can extend other classes. The Java IDEs help us by showing type hierarchies where you can navigate across a graphical interface along the inheritance relations. There is another hierarchy that IDEs can show to help us with development: method call hierarchy. After analyzing the code, the IDE can show us the graph displaying the relations between the methods: which method calls which other methods. Sometimes, this call graph is also important in showing the dependencies of methods on each other. Build the code and run it The IDEs usually compile the code for analysis to help us spot syntax errors or undefined classes and methods on the fly. This compilation is usually partial, covering a part of the code, and as it runs all the time, the source code changes and is never actually complete. To create the deployable file, that is, the final deliverable code of the project, a separate build process has to be started. Most of the IDEs have some built-in tool for that, but it's not recommended to use these except for the smallest projects. Professional development projects use Ant, Maven, or Gradle instead. Here is an example of Maven. The IDEs are prepared to use such an external tool, and they can help us in starting them. This way, the build process can run on the developer machine without starting a new shell window. IDEs can also import the settings from the configuration file of these external build tools to recognize the project structure, where source files are, and what to compile to support the error checking while editing. The building process usually contains the execution of certain checks on the code. A bunch of the Java source file may compile smoothly and the code may still contain a lot of bugs and may be written in bad style, which will make the project becomes unmaintainable in the long run. To avoid such problems, we will use unit tests and static code analysis tools. These do not guarantee error free code but the chances are much better. IDEs have plugins to run the static code analysis tools as well as unit tests. Being integrated into the IDE has a huge advantage. When there is any problem identified by the analysis tool, or by some unit tests, the IDE provides an error message that also functions like a link on a web page. If you click on the message, usually blue and underlined, exactly like on a web page, the editor opens the problematic file and places the cursor where the issue is. Debugging Java Developing code needs debugging. Java has very good facilities to debug code during development. JVM supports debuggers via the Java Platform Debugger Architecture. This lets you execute code in debug mode and JVM will accept external debugger tools to attach to it via a network, or it will try to attach to a debugger depending on command-line options. JDK contains a client, the jdb tool, which contains a debugger; however, it is so cumbersome to use when compared to the graphical client built into the IDEs that I have never heard of anyone using it for real work. To start a Java program in debug mode so that JVM will accept a debugger client to attach the options to it, execute the following command: Xagentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=7896 The Xagentlib option instructs the Java runtime to load the jdwp agent. The part of the option that follows Xagentlib:jdwp= is interpreted by the debugger agent. These options are as follows: : This should specify which transport to use. It can be a shared memory (dt_shmem) socket or a TCP/IP socket transport but, in practice, you will always use the latter. This is specified in the preceding dt_socket sample. server: This specifies if the debugged JVM starts in server mode or client mode. When you start the JVM in server mode, it starts to listen on a socket and accepts the debugger to connect to it. If it is started in client mode, then it tries to connect a debugger that is supposed to be started in server mode, listening on a port. The value of the option is y meaning server mode or n meaning nonserver, a.k.a. client mode. suspend: This can also be y or n. If JVM is started in suspend mode, it will not start the Java code until a debugger is attached to it. If it is started with suspend=n, then the JVM starts and when a debugger attaches, it stops as soon as a breakpoint is reached. If you start a standalone Java application, you will usually start the debugging with suspend=y, which is the default. If you want to debug an application in an application server or servlet-container environment, then it is better to start with suspend=n; otherwise, the server does not start until the debugger attaches to it. Starting the Java process in suspend=y mode in case servlet application is only useful when you want to debug the servlet static initializer code, which is executed when the server is starting up. Without suspend mode, you will be required to attach the debugger very fast. It is better that JVM just waits for you in that situation. address: This should specify the address that JVM communicates with. If the JVM started in client mode, then it will start to connect to this address. If the JVM runs in server mode, then it will accept connections from the debugger on that address. The address may specify only the port. In this case, the IP address is that of the local machine. transport The other options the debugger agent may handle are for special cases. For the topics covered in this book, the preceding options are enough. The following screenshot shows a typical debugging session where we debug the simplest program in IntelliJ IDE: When you start a program from the IDE in debug mode, all these options are automatically set for you. You can set breakpoint just by clicking on the source code in the editor. You can have a separate form to add, remove, and edit breakpoints. Breakpoints can be attached to specific lines or specific events, like when an exception is thrown. Breakpoints attached to a specific line can also have conditions that tell the debugger to stop the execution of the code only when the condition is true; for example, if a variable has some predefined value. Summary In this chapter we were introduced to each other with Java. We do not know too much from each other but we got acquainted. We have installed the Java environment: Java, JDK and integrated development environment. We have written a small program and had a brief look at what can be done using the development tools. This is far from mastery but even the longest journey starts with a first step, which is sometimes the hardest to make. We have done it in our Java journey. We started rolling and for the enthusiasts that we are, nothing can stop us walking all the way long. The First Real Java Program - Sorting Names In the previous chapter, we got acquainted with Java, and especially with using the REPL tool and interactively executing some simple code. That is a good start, but we need more. In this chapter, we will develop a simple sort program. Using this code as an example, we will look at different build tools, which are frequently used for Java projects, and learn the basic features of the Java language. This chapter will cover the following topics: The sorting problem The project structure and build tools The Make, Ant, Maven, and Gradle build tools Java language features related to the code example Getting started with sorting The sorting problem is one of the oldest programming tasks that an engineer deals with. We have a set of records and we know that we want to find a specific one sometime later, and we want to find that one fast. To find it, we sort the records in a specific order that helps us find the record we want quickly. As an example, we have the names of students with their marks on some cards. When students come to the office asking for their results, we look through all of the cards one after the other to find the name of the enquiring student. However, it is better if we sort the cards by the names of the students alphabetically. When a student makes an enquiry, we can search the mark attached to the name much faster. We can look at the middle card; if it shows the name of the student, then we are happy to have found the name and the mark. If the card precedes the name of the student alphabetically, then we will continue searching in the second half; otherwise, we will check the first half. Following that approach, we can find the name of the student in a few steps. The number of steps can not be more than the number as many times the pack of cards can be halved. If we have two cards, then it is two steps at most. If it is four, then we will need three steps at most. If there are eight cards, then we may need four steps, but not more. If there are 1,000 cards, then we may need at most 11 steps, while the original, non-sorted set will need 1,000 steps, worst case. That is, approximately, it speeds up the search 100 times, so this is worth sorting the cards, unless the sorting itself takes too much time. The algorithm finding an element in the already sorted set we just described is called binary search (https://en.wikipedia.org/w iki/Binary_search_algorithm). In many cases, it is worth sorting the dataset, and there are many sorting algorithms to do that. There are simpler and more complex algorithms, and, as in many cases, more complex algorithms are the ones that run faster. As we are focusing on the Java programming part and not the algorithm forging, in this chapter, we will develop a Java code that implements a simple and not-that-fast algorithm. Bubble sort The algorithm that we will implement in this chapter is well-known as bubble sort. The approach is very simple. Begin at the start of the cards and compare the first and the second card. If the first card is later in lexicographic order than the second one, then swap the two cards. Then repeat this for the card that is at the second place now, then the third, and so on. There is a card that is lexicographically the latest, say Wilson. When we get this card and start to compare it with the next one, we will always swap them; this way, Wilson's card will travel to the last place where it has to be after the sort. All we have to do is repeat this travelling from the start and do the occasional swapping of cards again, but this time only to the last but one element. This time, the second latest element will get to its place—say, Wilkinson will be right before Wilson. If we have n cards, and we repeat this n-1 times, all cards will get to their place. In the following sections, we will create a Java project that implements this algorithm. Getting started with project structure and build tools When a project is more complex than a single class, and it usually is, then it is wise to define a project structure. We will have to decide where we store the source files, where the resource files (those that contain some resource for the program, but are not Java source) are, where the .class files should be written by the compiler, and so on. Generally, the structure is mainly the directory setup and the configuration of the tools that perform the build. The compilation of complex programs cannot be feasibly done using the command line issuing javac commands. If we have 100 Java source files, the compilation will require that many javac commands to be issued. It can be shortened using wild cards, such as javac *.java ,or we can write a simple bash script or a BAT command file that does that. First, it will be just 100 lines, each compiling one source Java file to class file. Then, we will realize that it is only time, CPU, and power consuming to compile the files that are not changed since the last compilations so we can add some bash programming that checks the time stamp on the source and generated files. Then, we will probably realize that... whatever. At the end, we will end up with a tool that is essentially a build tool. Build tools are available ready made; it is not worth reinventing the wheel. Instead of creating one, we will use a build tool that is ready. There are a few of them that can be found at https://en.wikipedia.org/wiki/List_of_build_automation_software. In this chapter, we will use one called Maven; however, before jumping into the details of this tool, we will look at some other tools that you are likely to meet as a Java professional in enterprise projects. In the following sections, we will discuss a bit of the four build tools: Make Ant Maven Gradle We will mention Make only briefly because it is not used in Java environments these days. However, Make was the first build tool, and many ideas that modern Java build tools are based on come from the good old make. You, as a professional Java developer, should also be familiar with Make so that you will not freak out if you happen to see the use of it in a project for some purpose, and can know what it is and where its detailed documentation can be found. Ant was the first build tool widely used for Java many years ago, and it is still used in many projects. Maven is newer than Ant, and it uses a different approach. We will look at it in detail. Maven is also the official build tool of the Apache software foundation for the Java project. We will also use Maven as a build tool in this chapter. Gradle is even newer, and it has started to catch up to Maven these days. We will use this tool in later chapters in more detail. Make The make program was originally created in April 1976, so this is not a new tool. It is included in the Unix system, so this tool is available without any extra installation on Linux, Mac OS X, or any other Unixbased system. Additionally, there are numerous ports of the tool on Windows, and some version is/was included in the Visual Studio compiler toolset. The Make is not tied to Java. It was created when the major programming language was C, but it is not tied to C or any other language. The make is a dependency description language that has a very simple syntax. The make, just like any other build tool, is controlled by a project description file. In the case of make, this file contains a rule set. The description file is usually named Makefile, but in case the name of the description file is different, it can be specified as a command-line option to the make command. Rules in Makefile follow each other and consist of one or more lines. The first line starts at the first position (there is no tab or space at the start of the line) and the following lines start with a tab character. Thus, Makefile may look something like the following code: run : hello.jar java -cp hello.jar HelloWorld hello.jar : HelloWorld.class jar -cf hello.jar HelloWorld.class HelloWorld.class : HelloWorld.java javac HelloWorld.java This file defines three so-called targets: run, hello.jar, and HelloWorld.class. To create HelloWorld.class, type the following line at the command prompt: make HelloWorld.class Make will look at the rule and see that it depends on HelloWorld.java. If the HelloWorld.class file does not exist, or HelloWorld.java is newer than the Java class file, make will execute the command that is written on the next line and it will compile the Java source file. If the class file was created following the last modification of HelloWorld.java, then make knows that there is no need to run the command. In the case of creating HelloWorld.class, the make program has an easy task. The source file was already there. If you issue the make hello.jar command, the procedure is more complex. The make command sees that in order to create hello.jar, it needs HelloWorld.class, which itself is also a target on another rule. Thus, it may need to be created. First, it starts the problem the same way as before. If HelloWorld.class is there, and is older than hello.jar, there is nothing to do. If it is not there, or is newer than hello.jar, then the jar -cf hello.jar HelloWorld.class command needs to be executed, although not necessarily at the moment when it realizes that it has to be performed. The make program remembers that this command has to be executed sometime in the future when all the commands that are needed to create HelloWorld.class are already executed successfully. Thus, it continues to create the class file exactly the same way as I described earlier. In general, a rule can have the following format: target : dependencies command The make command can create any target using the make target command by first calculating which commands to execute and then executing them one by one. The commands are shell commands executing in a different process and may pose problems under Windows, which may render the Makefile files' operating system dependent. Note that the run target is not an actual file that make creates. A target can be a file name or just a name for the target. In the latter case, make will never consider the target to be readily available. As we do not use make for a Java project, there is no reason to get into more details. Additionally, I cheated a bit by making the description of a rule simpler than it should be. The make tool has many powerful features out of the scope of this book. There are also several implementations that differ a little from each other. You will most probably meet the one made by the Free Software Foundation—the GNU make. And, of course, just in case of any Unix command-line tool, man is your friend. The man make command will display the documentation of the tool on the screen. The main points that you should remember about make are as follows: It defines the dependencies of the individual artifacts (targets) in a declarative way It defines the actions to create the missing artifacts in an imperative way This structure was invented decades ago and has survived up until now for most of the build tools, as you will see in the next few chapters. Ant The ant build tool was built especially for Java projects around the year 2000. The aim of Java to be a write-once-run-anywhere language needed a tool that can also be used in different environments. Although make is available on Unix machines, and Windows as well, Makefiles were not always compatible. There was a small problem with the use of the tab character that some editors replaced with space, rendering Makefile unusable, but this was not the major reason. The main problem with make that ignited the development of Ant is that the commands are shell commands. Even if the implementation of the make program was made to be compatible on different operating systems, the used commands were many times incompatible, and that was something make itself could not change. Because make issues external commands to build the targets, developers are free to use any external tool that is available for them on the development machine. Another machine using the same operating system just may not have the same set of tools invoked by make. This undermines the portability of the make built projects. At the same time, Ant is following the major principles of make. There are targets that may depend on each other and there are commands that need to be executed in an appropriate sequence to create the targets one after the other, following the dependency order. The description of the dependencies and the commands is XML (tab issue solved) and the commands are implemented in Java (system dependency is solved, well... more or less). As Ant is neither part of the operating system nor the JDK, you will have to download and install it separately if you want to use it. Installing Ant Ant can be downloaded from its official website (http://ant.apache.org). You can download the source or the precompiled version. The easiest way is to download the binary in a tar.gz format. Whenever you download software from the Internet, it is highly recommended that you check the integrity of the downloaded file. The HTTP protocol does not contain error checking, and it may happen that a network error remains hidden or a malevolent internal proxy modifies the downloaded file. Download sites usually provide checksums for the downloadable files. These are usually MD5, SHA1, SHA512, or some other checksums. When I downloaded the Apache Ant 1.9.7 version in tar.gz format, I also opened the page that led to the MD5 checksum. The checksum value is bc1d9e5fe73eee5c50b26ed411fb0119. The downloaded file can be checked using the following command line: $ md5 apache-ant-1.9.7-bin.tar.gz MD5 (apache-ant-1.9.7-bin.tar.gz) = bc1d9e5fe73eee5c50b26ed411fb0119 The calculated MD5 checksum is the same as the one on the website, which says that the file integrity is not harmed. On the Windows operating system, no tool to calculate MD5 digest is included. There is a tool that Microsoft provides, called File Integrity Checksum Verifier Utility, which is available via the page https://support.microsoft.com/en-us/help/841290/availability-and-description-of-the-fil e-checksum-integrity-verifier-utility. If you use Linux, it may happen that the md5 or md5sum utility is not installed. In that case, you can install it using the command apt-get or whatever installation tool your Linux distribution supports. After the file is downloaded, you can explode it to a subdirectory using the following command: tar xfz apache-ant-1.9.7-bin.tar.gz The created subdirectory is the usable binary distribution of Ant. Usually, I move it under ~/bin, making it available only for my user on OS X. After that, you should set the environment variable as ANT_HOME to point to this directory and also add the bin directory of the installation to the PATH. To do that, you should edit the ~/.bashrc file and add the following lines to it: export ANT_HOME=~/bin/apache-ant-1.9.7/ export PATH=${ANT_HOME}bin:$PATH Then, restart the terminal application, or just type . following command: ~/.bashrc and test the installation of Ant by typing the $ ant Buildfile: build.xml does not exist! Build failed If the installation was correct, you should see the preceding error message. Using Ant When you see a project to be built by Ant, you will see a build.xml file. This is the project build file, the one that Ant was missing when you checked that the installation was correct. It can have any other name, and you can specify the name of the file as a command-line option for Ant, but this is the default file name, as Makefile was for make. A build.xml sample looks like the following: <project name="HelloWorld" default="jar" basedir="."> <description> This is a sample HelloWorld project build file. </description> <property name="buildDir" value="build"/> <property name="srcDir" value="src"/> <property name="classesDir" value="${buildDir}/classes"/> <property name="jarDir" value="${buildDir}/jar"/> <target name="dirs"> <mkdir dir="${classesDir}"/> <mkdir dir="${jarDir}"/> </target> <target name="compile" depends="dirs"> <javac srcdir="${srcDir}" destdir="${classesDir}"/> </target> <target name="jar" depends="dirs,compile"> <jar destfile="${jarDir}/HelloWorld.jar" basedir="${classesDir}"/> </target> </project> The top-level XML tag is project. Each build file describes one project, hence the name. There are three possible attributes to the tag, which are as follows: : This defines the name of the project and is used by some IDEs to display it in the left panel identifying the project default: This names the target to use when no target is defined on the command line starting Ant basedir: This defines the initial directory used for any other directory name calculation in the build file name The build file can contain a description for the project, as well as properties in property tags. These properties can be used as variables in the attributes of the tasks between the ${ and } characters, and play an important role in the build process. The targets are defined in target XML tags. Each tag should have a name that uniquely identifies the target in the build file and may have a depends tag that specifies one or more other targets that this target depends on. In case there is more than one target, the targets are comma separated in the attribute. The tasks belonging to the targets are executed in the same order as the targets dependency chain requires, in a very similar way as we saw in the case of make. You can also add a description attribute to a target that is printed by Ant when the command-line option, projecthelp, is used. This helps the users of the build file to know what targets are there and which does what. Build files tend to grow large with many targets, and when you have ten or more targets, it is hard to remember each and every target. The sample project with HelloWorld.java is now arranged in the following directories: in the root folder of the project HelloWorld.java in the src folder of the project The build/ folder does not exist; it will be created during the build process The build/classes and build/jar also do not exist yet, and will be created during the build process build.xml When you start the build for the HelloWorld project the first time, you will see the following output: $ ant Buildfile: /Users/verhasp/Dropbox/java_9-by_Example/sources/ch02/build.xml dirs: [mkdir] Created dir: /Users/verhasp/Dropbox/java_9-by_Example/sources/ch02/build/classes [mkdir] Created dir: /Users/verhasp/Dropbox/java_9-by_Example/sources/ch02/build/jar compile: ... [javac] Compiling 1 source file to /Users/verhasp/Dropbox/java_9-by_Example/sources/ch02/build/classes jar: [jar] Building jar: /Users/verhasp/Dropbox/java_9-by_Example/sources/ch02/build/jar/HelloWorld.jar BUILD SUCCESSFUL Total time: 0 seconds Some unimportant lines are deleted from the actual output. Ant realizes that first it has to create the directories, then it has to compile the source code, and finally it can pack the .class files into a .jar file. Now it is up to you to remember the command to execute the HelloWorld application. It was listed already in the first chapter. Note that this time, the JAR file is named HelloWorld.jar, and it is not in the current directory. You can also try to read the online documentation of Ant and create a target run that executes the compiled and packed program. Ant has a built-in task named java that executes a Java class in almost the same way as you typed the java command in the terminal. Maven As Ant was created to overcome the shortages of make, Maven was created with a similar intention—to overcome the shortages of Ant. You may recall that make could not guarantee build portability because the commands make executes are arbitrary shell commands that may be system specific. An Ant build, if all the tasks are available on the classpath, is portable as long as Java runs the same way on the different platforms. The problem with Ant is a bit different. When you download the source code of a project and you want to build, what will the command be? You should ask Ant to list all the targets and select the one that seems to be the most suitable. The name of the task depends on the engineer who crafted the build.xml file. There are some conventions, but they are not strict rules. Where will you find the Java source files? Are they in the src directory or not? Will there also be some Groovy or other programming language files in case the project is polyglot? That depends. Again, there may be some conventions that some groups or company cultures suggest, but there is no general best industry practice. When you start a new project with Ant, you will have to create the targets for compilation, test execution, and packaging. It is something that you will have already done for other projects. After the second or third project, you will just copy and paste your previous build.xml to your new project. Is that a problem? Yes, it is. It is copy/paste programming, even if it is only some build files. Developers realized that a significant effort of the projects utilizing Ant is devoted to project build tool configuration, including repetitive tasks. When a new joiner comes to the team, they will first have to learn how the build is configured. If a new project is started, the build configuration has to be created. If it is a repetitive task, then better let the computers do it. That is generally what programming is all about, isn't it? Maven approaches the build issue a bit differently. We want to build Java projects. Sometimes, some Groovy or Jython things, but they are also JVM languages; thus, saying that we want to build Java projects is not really a huge restriction. Java projects contain Java files, sometimes some other programming language's source files, resource files, and generally, that is it. Ant can do anything, but we do not want to do just anything with a build tool. We want to build projects. Okay, after we restricted ourselves and accepted that we do not need a build tool that can be used for anything, we can go on. We can require that the source files be under the src directory. There are files that are needed for the operational code and there are files that contain some test code and data. Therefore, we will have two directories, src/test and src/main. Java files are in src/main/java as well as src/test/java. Resource files are under src/main/resources and src/test/resources. If you want to put your source files somewhere else, then don't. I mean it. It is possible, but I will not even tell you how. Nobody does it. I do not even have any idea why Maven makes it possible. Whenever you see a project that is using Maven as a build tool, the sources are organized like that. There is no need to understand the directory structure envisioned by the project's build engineer. It is always the same. How about the targets and the tasks? They are also the same for all Maven-based projects. What else would you like to do with a Java project other than compile, test, package, or deploy it? Maven defines these project life cycles for us. When you want to compile a project using Maven as a build tool, you will have to type $ mvn compile to compile the project. You can do that even before understanding what the project actually is. As we have the same directory structure and the same goals, the actual tasks leading to the goals are also all the same. When we create a Maven project, we do not have to describe what the build process has to do and how it has to do it. We will have to describe the project, and only the parts that are project specific. The build configuration of a Maven project is given in an XML file. The name of this file is usually pom.xml, and it should be in the root directory of the project, which should be the current working directory when firing up Maven. The word POM stands for Project Object Model, and it describes the projects in a hierarchical way. The source directories, the packaging, and other things are defined in a so-called super POM. This POM is part of the Maven program. Anything that the POM defines, overrides the defaults defined in the super POM. When there is a project with multiple modules, the POMs are arranged into a hierarchy, and they inherit the configuration values from the parent down to the modules. As we will use Maven to develop our sorting code, we will see some more details later. Installing Maven Maven is neither a part of the operating system nor the JDK. It has to be downloaded and installed in a very similar way to Ant. You can download Maven from its official website (https://maven.apache.org/) under the download section. Currently, the latest stable version is 3.3.9. When you download it, the actual release may be different; instead, use the latest stable version. You can download the source or the precompiled version. The easiest way is to download the binary in tar.gz format. I cannot skip drawing your attention to the importance of checking the download integrity using checksums. I have detailed the way to do it in the section about Ant installation. After the file is downloaded, you can explode it to a subdirectory using the following command: tar xfz apache-maven-3.3.9-bin.tar.gz The created subdirectory is the usable binary distribution of Maven. Usually, I move it under ~/bin, making it available only for my user on OS X. After that, you should add the bin directory of the installation to the PATH. To do that, you should edit the ~/.bashrc file and add the following lines to it: export M2_HOME=~/bin/apache-maven-3.3.9/ export PATH=${M2_HOME}bin:$PATH Then, restart the terminal application, or just type . follows: ~/.bashrc and test the installation of Maven typing, as $ mvn -v Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-10T17:41:47+01:00) Maven home: /Users/verhasp/bin/apache-maven-3.3.9 Java version: 9-ea, vendor: Oracle Corporation Java home: /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home Default locale: en_US, platform encoding: UTF-8 OS name: "mac os x", version: "10.11.6", arch: "x86_64", family: "mac" You should see a similar message on the screen that displays the installed Maven version and other information. Using Maven Unlike Ant, Maven helps you create the skeleton of a new project. To do that, you will have to type the following command: $ mvn archetype:generate Maven will first download the actually available project types from the network and prompt you to select the one you want to use. This approach seemed to be a good idea while Maven was new. When I first started Maven, the number of listed projects was somewhere between 10 and 20. Today, as I write this book, it lists 1,635 different archetypes. This number seems more like a historical date (the constitution of the French Academy of Science) than a usable size list of different archetypes. However, do not freak out. Maven offers a default value when it asks for your choice, and it is good for the HelloWorld we go for. Choose a number: 817: The actual number may be different on your installation. Whatever it is, accept the suggestion and press Enter. After that, Maven will ask you for the version of the project: Choose version: 1: 1.0-alpha-1 2: 1.0-alpha-2 3: 1.0-alpha-3 4: 1.0-alpha-4 5: 1.0 6: 1.1 Choose a number: 6: 5 Select the 1.0 version that is listed as number 5. The next thing Maven asks for is the group ID and the artifact ID of the project. The dependency management that we will discuss later uses these. I selected a group ID based on the book and the publisher. The artifact of the project is SortTutorial as we will start our chapter example in this project. Define value for property 'groupId': : packt.java9.by.example Define value for property 'artifactId': : SortTutorial The next question is the current version of the project. We have already selected 1.0 and Maven offers 1.0SNAPSHOT. Here, I selected 1.0.0-SNAPSHOT because I prefer semantic versioning. Define value for property 'version': 1.0-SNAPSHOT: : 1.0.0-SNAPSHOT Semantic versioning, defined on http://semver.org/, is a versioning scheme that suggests three digit version numbers as M.m.p. for Major, minor, and patch version numbers. This is very useful for libraries. You will increment the last version number if there is only a bug fix since the previous release. You will increment the minor number when the new release also contains new features, but the library is compatible with the previous version; in other words, any program that is using the older version can still use the newer version. The major release number is increased when the new version is significantly different from the previous one. In the case of application programs, there is no code that uses the application API; thus, the minor version number is not that important. It does not hurt, though, and it often proves to be useful to signal smaller changes in the application. We will discuss how to version software in the last chapter. Maven handles the versions that have the -SNAPSHOT postfix as non-release versions. While we develop the code, we will have many versions of our code, all having the same snapshot version number. On the other hand, non-snapshot version numbers can only be used only for a single version. Define value for property 'package': packt.java9.by.example: : The last question from the program skeleton generation is the name of the Java package. The default is the value we gave for groupId, and we will use this. It is a rare exception to use something else. When we have specified all the parameters that are needed, the final request is to confirm the setting: Confirm properties configuration: groupId: packt.java9.by.example artifactId: SortTutorial version: 1.0.0-SNAPSHOT package: packt.java9.by.example Y: : Y After entering Y, Maven will generate the files that are needed for the project and display the report about this: [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] ----------------------------------------------------------Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0 ----------------------------------------------------------Parameter: basedir, Value: .../mavenHelloWorld Parameter: package, Value: packt.java9.by.example Parameter: groupId, Value: packt.java9.by.example Parameter: artifactId, Value: SortTutorial Parameter: packageName, Value: packt.java9.by.example Parameter: version, Value: 1.0.0-SNAPSHOT *** End of debug info from resources from generated POM *** project created from Old (1.x) Archetype in dir: .../mavenHelloWorld/SortTutorial ----------------------------------------------------------BUILD SUCCESS ----------------------------------------------------------Total time: 01:27 min Finished at: 2016-07-24T14:22:36+02:00 Final Memory: 11M/153M ----------------------------------------------------------- You can take look at the following generated directory structure: You can also see that it generated the following three files: SortTutorial/pom.xml that contains the Project Object Model that contains a HelloWorld sample application SortTutorial/src/test/java/packt/java9/by/example/AppTest.java that contains a unit test skeleton utilizing the junit4 library SortTutorial/src/main/java/packt/java9/by/example/App.java We will discuss unit tests in the next chapter. For now, we will focus on the sorting application. As Maven was so kind and generated a sample class for the app, we can compile and run it without actual coding, just to see how we can build the project using Maven. Change the default directory to SortTutorial issuing cd SortTutorial and issue the following command: $ mvn package We will get the following output: Maven fires up, compiles, and packages the project automatically. If not, please read the next info box. When you first start Maven, it downloads a lot of dependencies from the central repository. These downloads take time, and are reported on the screen, so the actual output may be different from what you saw in the preceding code. Maven compiles code with the default settings for Java version 1.5. It means that the generated class file is compatible with Java version 1.5, and also that the compiler only accepts language constructs that were available already in Java 1.5. If we want to use newer language features, and in this book we use a lot, the pom.xml file should be edited to contain the following lines: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.9</source> <target>1.9</target> </configuration> </plugin> </plugins> </build> When using Java 9's default settings for Maven, it becomes even more complex, because Java 9 does not generate class format nor restrict source compatibility earlier than Java 1.6. At this very moment, as I write these lines, the latest Maven release is 3.3.9. When I try to compile the preceding code without the modifications, the Java compiler stops with an error displaying the following: [ERROR] Source option 1.5 is no longer supported. Use 1.6 or later. [ERROR] Target option 1.5 is no longer supported. Use 1.6 or later. Later, Maven releases may behave differently in the future. Now, you can start the code using the following command: $ java -cp target/SortTutorial-1.0.0-SNAPSHOT.jar packt.java9.by.example.App You can see the result of a sample run in the following picture: Gradle Ant and Maven are two worlds, and using one or the other may lead to heated debates on Internet forums. Ant gives freedom to developers to create a build process that fits their taste. Maven restricts the team to use a build process that is more standard. Some special processes that do not match any standard build, but which are sometimes needed in some environments, are hard to implement using Maven. In Ant, you can script almost anything using the built-in tasks, almost the same way as you can program bash. Utilizing Maven is not that simple, and, it often requires writing a plugin. Even though writing a plugin is not rocket science, developers usually like to have the possibility of making things in a simpler way: Scripting. We have two approaches, two mindsets and styles, and not a single tool to fulfill all the needs. No surprise that by the Java technologies were developed, a new build tool was emerging. Gradle tries to use the best of both worlds, utilizing techniques that were not available by the time Maven and Ant were first developed. Gradle has built-in targets and life cycle, but at the same time, you can also write your own targets. You can configure a project, just like using Maven, without scripting the tasks to do so, but at the same time, you can also script your own target just like in Ant. What is more, Gradle integrated Ant, so any task implemented for Ant is available for Gradle as well. Maven and Ant use XML files to describe the build. Today, XML is a technology of the past. We still use it, and a developer should be fluent in handling, reading, and writing XML files, but a modern tool does not use XML for configuration. New, fancy formats such as JSON are more popular. Gradle is no exception. The configuration file of Gradle uses a domain-specific language (DSL) based on Groovy. This language is more readable for programmers and gives more freedom to program build processes. And, this is also the danger of Gradle. Having the powerful JVM language Groovy in the hands of developers to create build tools gives a freedom and temptation to create complex build processes that seem to be a good idea at the start, but later may prove to be just too complex and hard, and, therefore, expensive to maintain. This is exactly why Maven was implemented in the first place. I have to stop before getting into another area that is the ground for heated and pointless debates. Gradle is an extremely powerful build tool. You should use it carefully, just like you would use a weapon—don't shoot your legs. Installing Gradle To install Gradle, you will have to download the compiled binaries from the https://gradle.org/gradle-download/ website. Again, I'd like to emphasize the importance of checking the download integrity using checksums. I have given a detailed way to do it in the section about Ant installation. Unfortunately, the Gradle website does not provide the checksum values for the downloadable files. Gradle is downloadable in the ZIP format. To unpack the file, you will have to use the unzip command: $ unzip gradle-3.3-bin.zip The created subdirectory is the usable binary distribution of Gradle. Usually, I move it under ~/bin, making it available only for my user on OS X. After that, you should add the bin directory of the installation to the PATH. To do that, you should edit the ~/.bashrc file and add the following lines: export GRADLE_HOME=~/bin/gradle-3.3/ export PATH=${GRADLE_HOME}bin:$PATH Then, restart the terminal application, or just type . following: ~/.bashrc and test the installation of Gradle, typing the $ gradle -version We get to the following output, as can be seen in this screenshot: Setting up the project with Maven To start the project, we will use the directory structure and pom.xml that was created by Maven itself when we started with the following command line: $ mvn archetype:generate It created the directories, the pom.xml file, and an App.java file. Now, we will extend this project by creating new files. We will code the sorting algorithm first in the packt.java9.by.example.stringsort package: When we create the new package in the IDE, the editor will automatically create the stringsort subdirectory under the already existing src/main/java/packt/java9/by/example directory: Creating the new Sort class using the IDE will also automatically create a new file named Sort.java in this directory, and it will fill in the skeleton of the class: package packt.java9.by.example.stringsort; public class Sort { } We will now have App.java containing the following code: package packt.java9.by.example; public class App { public static void main( String[] args ) { System.out.println( "Hello World!" ); } } Maven created it as a starting version. We will edit this file to provide a sample list that the sorting algorithm can sort. I recommend that you use the IDE to edit the file and also to compile and run the code. The IDE provides a shortcut menu to start the code and this is a bit easier than typing the command in Terminal. Generally, it is recommended that you get acquainted with the IDE features to save time avoiding repetitive tasks, such as typing terminal commands. Professional developers use the command line almost exclusively to test command-line features and use the IDE whenever it is possible. Coding the sort Maven and the IDE created the files for the sort program. They form the skeleton for our code, and now it is time to grow some muscles on them to let it move. We spent quite some time to set up the project by visiting the different build tools, only to learn how to compile the code. I hope that this did not distract you much, but anyhow, we deserve to see some real code. First, we will create the code for the sorting code, and after that, the code that invokes the sorting. The code that invokes the sorting is a kind of testing code. For simplicity, we will now simply use a public static void main method to start the code. We will use the test framework in later chapters. As for now, the code for the sorting will look like this: package packt.java9.by.example.stringsort; public class Sort { public void sort(String[] names) { int n = names.length; while (n > 1) { for (int j = 0; j < n - 1; j++) { if (names[j].compareTo(names[j + 1]) > 0) { final String tmp = names[j + 1]; names[j + 1] = names[j]; names[j] = tmp; } } n--; } } } This is the class that does the sorting. There is only one method in this class that does the sorting. The argument to the method is an array containing the strings, and the method sorts this array. The method has no return value. This is denoted in the declaration using the pseudo type void. Methods use their arguments to perform some tasks, and may return one value. The arguments to the method are passed by value, which means that the method cannot modify the variable passed as argument. However, it can modify the objects the arguments contain. In this case, the array is modified and we will sort it. On the other hand, the actualNames variable will point to the same array and the sort method cannot do anything to make this variable point to a different array. There is no main method in this class, which means that it cannot be started from the command line on its own. This class can only be used from some other class, as every Java program should have a class that has a public static void main method that we created separately. I could also put a main method into the class to make it executable, but that is not a good practice. Real programs are composed of many classes, and one class should not do many things. Rather, it's the opposite. The single responsibility principle says that a single class should be responsible for one single thing; therefore, class sort does the sorting. Executing the application is a different task, and thus it has to be implemented in a different class. Often, we do not implement the class containing the main method. Often, a framework provides it. For example, writing a servlet that runs in a servlet container requires containing a class that implements the javax.servlet.Servlet interface. In this case, the program seemingly does not have a main method. The actual implementation of the servlet container does. The Java command line starts the container and the container loads the servlets when they are needed. In the following example code, we implemented the App class containing the main method: package packt.java9.by.example; import packt.java9.by.example.stringsort.Sort; public class App { public static void main(String[] args) { String[] actualNames = new String[]{ "Johnson", "Wilson", "Wilkinson", "Abraham", "Dagobert" }; final Sort sorter = new Sort(); sorter.sort(actualNames); for (final String name : actualNames) { System.out.println(name); } } } This code contains a string array initialized to contain constant values, creates a new instance of the Sort class, invokes the sort method, and then prints out the code to the standard output. In real programs, we almost never have such constants in program codes; we put them into resource files and have some code to read the actual values. This separates the code from data and eases maintenance, eliminating the risk of accidental modification of code structure when only the data is to be changed. Similarly, we will almost never write anything to standard output using System.out. Usually, we will use logging possibilities that are available from different sources. There are different libraries that provide logging functionalities and logging is also available from the JDK itself. As for now, we will focus on simple solutions so as to not distract your focus from Java by the plethora of different libraries and tools. In the following section, we will look at the Java language constructs that we used to code the algorithm. First, we will look at them generally, and then, in a bit more detail. These language features are not independent of each other: one builds up on the other, and therefore, the explanation will first be general, and we will go into details in the subsections. int n = names.length; <br/> while (n > 1) { <br/> for (int j = 0; j < n - 1; j++) { <br/> if (names[j].compareTo(names[j + 1]) > 0) { <br/> final String tmp = names[j + 1]; <br/> names[j + 1] = names[j]; <br/> names[j] = tmp; <br/> } <br/> } <br/> n--; <br/> } The n variable holds the length of the array at the start of the sorting. Arrays in Java always have a property that gives the length and it is called length. When we start the sorting, we will go from the start of the array to the end of it and, as you may recall, the last element, Wilson, will walk up to the last position during this first iteration. Subsequent iterations will be shorter and, therefore, the variable n will be decreased. Blocks The code in Java is created in code blocks. Anything that is between the { and } characters is a block. In the preceding example, the code of the method is a block. It contains commands, and some of them, like the while loop, also contain a block. Inside that block, there are two commands. One of them is a for loop, again with a block. Although we can have single expressions to form the body of a loop, we usually use blocks. We will discuss loops in detail in just a few pages. As we could see in the preceding example, the loops can be nested, and thus the { and } characters form pairs. A block can be inside another block, but two blocks cannot overlap. When the code contains a } character, it is closing the block that was opened last. Variables In Java, just like in almost any programming language, we use variables. The variables in Java are typed. It means that a variable can hold a value of a single type. It is not possible for a variable to hold an int type at some point in the program and later a String type. When variables are declared, their type is written in front of the variable name. Variables also have visibility scope. Local variables in methods can only be used inside the block in which they are defined. A variable can be used inside methods or they can belong to a class or an object. To differentiate the two, we usually call these variables fields. Types Each variable has one type. In Java, there are two major groups of type: primitive and reference types. The primitive types are predefined, and you cannot define or create a new primitive type. There are eight primitive types: byte, short, int, long, float, double, boolean, and char. The first four types, byte, short, int, and long, are signed numeric integer types, capable of storing positive and negative numbers on 8, 16, 32, and 64 bits. The float and double types store floating point numbers on 32 and 64 bits in the IEEE 754 floating-point format. The boolean type is a primitive type that can only be true or false. The char type is a character data type that stores a single 16-bit Unicode character. For each primitive type, there is a class that can store the same type of value. When a primitive type has to be converted to the matching class type it is done automatically. It is called auto boxing. These types are Byte, Short, Integer, Long, Float, Double, Boolean, and Character. Take, for example, the following variable declaration: Integer a = 113; This converts the value 113, which is an int number, to an Integer object. These types are part of the runtime, and also part of the language. Although there is no primitive counterpart of it, there is a very important and ubiquitous class that we have already used: String. A string contains characters. The major differences between primitive types and objects are that primitive types cannot be used to invoke methods, but they consume less memory. The difference between the memory consumption and its consequences for speed is important in the case of arrays. Arrays Variables can be a primitive type according to their declaration, or they may hold a reference to an object. A special object type is an array. When a variable holds a reference to an array, then it can be indexed with the [ and ] characters, along with an integral value consisting of 0 or a positive value ranging to one less than the array's length, to access a certain element of the array. Multi-dimensional arrays are also supported by Java when an array has elements that are also arrays. Arrays are indexed from zero in Java. Under or over indexing is checked at runtime, and the result is an exception. An exception is special condition that interrupts the normal execution flow and stops the execution of the code or jumps to the closest enclosing catch statement. We will discuss exceptions and how to handle them in the next chapter. When a code has an array of a primitive type, the array contains many memory slots, each holding the value of the type. When the array has a reference type, in other words, when it is an array of objects, then the array elements are references to objects, each containing the type. In the case of int for example, each element of the array is 32-bit, which is 4 bytes. If the array is a type of Integer, then the elements are references to objects, pointers, so to say, which is usually 64-bit using 64-bit JVM and 32-bit on 32-bit JVM. In addition to that, there is an Integer object somewhere in memory that contains the 4-byte value and also an object header that may be as much as 24 bytes. The actual size of the extra information needed to administer each object is not defined in the standard. It may be different on different implementations of the JVM. The actual coding, or even the optimization of the code in an environment, should not depend on the actual size. However, the developers should be aware that this overhead exists and is in the range of around 20 or so bytes for every object. Objects are expensive in terms of memory consumption. Memory consumption is one issue, but there is something else. When the program works with a large amount of data and the work needs the consecutive elements of the array, then the CPU loads a chunk of memory into the processor cache. It means that the CPU can access elements of the array that are consecutively faster. If the array is of a primitive type, it is fast. If the array is of some class type, then the CPU has to access memory to get the actual value, which may be as much as 50 times slower. Expressions Expressions in Java are very much like in other programming languages. You can use the operators that may be similar from languages such as C or C++. They are as follows: Unary prefix and postfix increment operators ( -- and ++ before and after a variable) Unary sign (+ and -) operators Logical (!) and bitwise (~) negation Multiplication (*), division (/), and modulo (%) Addition and subtraction (+ and - again, but this time as binary operators) Shift operators move the values bitwise, and there is left (<<) and right (>>) shift and unsigned right shift (>>>) The comparing operators are <, >, <=, >=, ==, != and instanceof that result in boolean value There are bitwise or (|), and (&), exclusive or (^) operators, and similarly logical or (||), and (&&) operators When logical operators are evaluated, they are shortcut evaluated. It means the right-hand operand is evaluated only if the result cannot be identified from the result of the left operand. The ternary operator is also similar to the one, like it is on C, selecting from one of the expressions based on some condition: condition ? expression 1 : expression 2. Usually, there is no problem with the ternary operator, but sometimes you have to be careful as there is a complex rule controlling the type conversions in case the two expressions are not of the same type. It's always better to have the two expressions be of the same type. Finally, there is an assignment operator (=) that assigns the value of an expression to a variable. For each binary operator, there is an assignment version that combines = with a binary operator to perform an operation involving the right operand and assign the result to the left operand, which must be a variable. These are +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, and >>>=. The operators have precedence and can be overridden by parentheses, as usual. An important part of expressions is invoking methods. Static methods can be invoked by the name of the class and the name of the method. For example, to calculate the sine of 1.22, we can write the following line: double z = Math.sin(1.22); Here, Math is the class from the package java.lang. The method sin is invoked without using any instance of Math. This method is static, and it is not likely that we will ever need any other implementation of it than the one provided in the class Math. Non-static methods can be invoked using an instance and the name of the method with a dot separating the two. For example, take the following code line as an example: System.out.println("Hello World"); The preceding code uses an instance of the class PrintStream that is readily available through a static field in the class System. This variable is called out, and when we write our code, we have to reference it as System.out. The method println is defined in the class PrintStream and we invoke it on the object referenced by the variable out. This example also shows that static fields can also be referenced through the name of the class and the field separated by a dot. Similarly, when we need to reference a non-static field, we can do it through an instance of the class. Static methods defined in the same class from where it is invoked or inherited can be invoked without the class name. Invoking a non-static method defined in the same class or being inherited can be invoked without an instance. In this case, the instance is the current object the execution is in. This object is also available through the this keyword. Similarly, when we use a field of the same class where our code is, we simply use the name. In case of a static field, the class we are in by default. In the case of a non-static field, the instance is the object referenced by the this keyword. You can also import a static method into your code using the importstatic language feature, in which case you can invoke the method without the name of the class. The arguments of the method calls are separated using commas. Methods and method argument passing is an important topic that we will mention in detail in a separate subsection. Loops The for loop inside the while loop will go through all the elements from the first (indexed with zero in Java) up till the last (indexed with n-1). Generally, the for loop has the same syntax as in C: for( initial expression ; condition ; increment expression ) block First, the initial expression is evaluated. It may contain variable declaration, as in our example. The variable j in the preceding example is visible only inside the block of the loop. After this, the condition is evaluated, and after each execution of the block, the increment expression is executed. The loop repeats so long as the condition is true. If the condition is false right after the execution of the initial expression, the loop does not execute at all. The block is a list of commands separated by semicolons and enclosed between the { and } characters. Instead of { and }, enclosed block Java lets you use a single command following the head of the for loop. The same is true in the case of the while loop, and also for the if...else constructs. Practice shows that this is not something a professional should use. Professional code always uses curly braces, even when there is only a single command where the block is in place. This prevents the dangling else problem and generally makes the code more readable. This is similar to many C-like languages. Most of them allow a single command at these places, and professional programmers avoid using a single command in these languages for readability purposes. It is ironic that the only language that strictly requires the use of the { and } braces at these places is Perl—the one language infamous for unreadable code. The loop in the for (int j = 0; j < n - 1; j++) { sample starts from zero and goes to n-2. Writing j < n-1 is the same, in this case, as j <= n-2. We will limit j to stop in the loop before the end of the section of the array, because we reach beyond the index j by one comparing and conditionally swapping the elements indexed by j and j+1. If we went one element further, we would try to access an element of the array that does not exist, and it would cause a runtime exception. Try and modify the loop condition to j < n or j <= n-1 and you will get the following error message: It is an important feature of Java that the runtime checks memory access and throws an exception in the case of bad array indexing. In the good old days, while coding in C, often, we faced unexplainable errors that stopped our code much later and at totally different code locations from where the real error was. Array index in C silently corrupted the memory. Java stops you as soon as you make a mistake. It follows the fail-fast approach that you also should use in your code. If something is wrong, the program should fail. No code should try to live with or overcome an error that comes from a coding error. Coding errors should be fixed before they cause even more damage. There are also two more loop constructs in Java: the while loop and the do loop. The example contains a while loop: it is the outer loop that runs so long as there are at least two elements that may need swapping in the array: while (n > 1) { The general syntax and semantics of the while loop is very simple, as seen here: while ( condition ) block Repeat the execution of the block so long as the condition is true. If the condition is not true at the very start of the loop, then do not execute the block at all. The do loop is also similar, but it checks the condition after each execution of the block: do block while( condition ); For some reason, programmers rarely use do loops. Conditional execution The heart of the sort is the condition and the value swapping inside the loop. if (names[j].compareTo(names[j + 1]) > 0) { final String tmp = names[j + 1]; names[j + 1] = names[j]; names[j] = tmp; } There is only one conditional command in Java, the if command. It has the following format: if( condition ) block else block The meaning of the code structure is quite straightforward. If the condition is true, then the first block is executed, otherwise, the second block is executed. The else keyword, along with the second block, is optional. If there is nothing to be executed in case that the condition is false, then there is no need for the else branch, just like in the example. If the array element indexed with j is later in the sort order than the element j+1, then we swap them, but if they are already in order, there is nothing to do with them. To swap the two array elements, we will use a temporary variable named tmp. The type of this variable is String, and this variable is declared to be final. The final keyword has different meanings depending on where it is used in Java. This may be confusing for beginners unless you are warned about it, just like now. A final class or method is a totally different thing than a final field, which is again different than a final local variable. Final variables In our case, tmp is a final local variable. The scope of this variable is limited to the block following the if statement, and inside this block, this variable gets a value only once. The block is executed many times during the code execution, and each time the variable gets into scope, it gets a value. However, this value cannot be changed in the block. This may be a bit confusing. You can think about it as having a new tmp each time the block executes. The variable gets declared and has an undefined value and can get a value only once. Final local variables do not need to get the value where they are declared. You can assign a value to a final variable some time later. It is important that there should not be a code execution that assigns a value to a final variable that was already assigned a value before. The compiler checks it and does not compile the code if there is a possibility of the reassignment of a final variable. To declare a variable to be final is generally to ease readability of the code. When you see a variable in a code declared to be final, you can assume that the value of the variable will not change and the meaning of the variable will always be the same wherever it was used in the method. It will also help you avoid some bugs when you try to modify some final variables and the IDE will immediately complain about it. In such situations, it is likely to be a programming mistake that is discovered extremely early. In principle, it is possible to write a program where all variables are final. It is generally a good practice to declare all final variables that can be declared to be final and, in case some variable may not be declared final, then try to find some way of coding the method a bit differently. If you need to introduce a new variable to do that, it probably means you were using one variable to store two different things. These things are of the same type and stored in the same variable at different times but, logically, they still are different things. Do not try to optimize the use of variables. Never use a variable because you already have a variable of the type in your code that is available. If it is logically a different thing, then declare a new variable. While coding, always prefer source code clarity and readability. In Java, especially, the Just In Time compiler will optimize all this for you. Although we do not explicitly tend to use the final keyword on the argument list of a method, it is good practice to make sure that your methods compile and work if the arguments are declared final. Some experts, including me, believe that the method parameters should have been made final by default in the language. This is something that will not happen in any version of Java, so long as Java follows the backward compatibility philosophy. Classes Now that we have looked at the actual code lines and have understood how the algorithm works, let's look at the more global structures of the code that brings it together: classes and packages enclosing the methods. Every file in a Java program defines a class. Any code in a Java program is inside a class. There is nothing like global variables or global functions as in C, Python, Go, or other languages. Java is totally object oriented. There can be more than one class in a single file, but usually one file is one class. Later, we will see that there are inner classes when a class is inside another class, but, for now, we will put one class into one file. There are some features in the Java language that we do not use. When the language was created, these features seemed to be a good idea. CPU, memory, and other resources, including mediocre developers, were also more limited than today. Some of the features, perhaps, made more sense because of these environmental constraints. Sometimes, I will mention these. In the case of classes, you can put more than one class into a single file so long as only one is public. That is bad practice, and we will never do that. Java never obsoletes these features. It is a philosophy of Java to remain compatible with all previous versions. This philosophy is good for the already written, huge amount of legacy code. Java code written and tested with an old version will work in a newer environment. At the same time, those features lure beginners to a wrong style. For this reason, sometimes, I will not even mention these features. For example, here, I could say: There is one class in a file. This would not be absolutely correct. At the same time, it is more or less pointless to explain in great detail a feature that I recommend not to be used. Later, I may simply skip them and "lie". There are not too many of those features. A class is defined using the class keyword and each class has to have a name. The name should be unique within the package (see the next section) and has to be the same as the name of the file. A class can implement an interface or extend another class, for which we will see an example later. A class can also be abstract, final, and public. These are defined with the appropriate keywords, as you will see in examples. Our program has two classes. Both of them are public. The public classes are accessible from anywhere. Classes that are not public are visible only inside the package. Inner and nested classes can also be private visible only inside the top-level class defined on the file level. Classes that contain a main method to be invoked by the Java environment should be public. That is because they are invoked by the JVM. The class starts at the beginning of the file right after the package declaration and everything between the { and } characters belong to the class. The methods, fields, inner or nested classes, and so on are part of the class. Generally, curly braces denote some block in Java. This was invented in the C language, and many languages follow this notation. Class declaration is some block, methods are defined using some block, loops, and conditional commands use blocks. When we use the classes, we will have to create instances of classes. These instances are objects. In other words, objects are created instantiating a class. To do that, the new keyword is used in Java. When the line final Sort sorter = new Sort(); is executed in the App class, it creates a new object instantiating the Sort class. We will also say that we created a new Sort object or that the type of the object is Sort. When a new object is created, a constructor of the object is invoked. A bit sloppy, I may say, that the constructor is a special method in the class that has the same name as the class itself and has no return value. That is because it returns the created object. To be precise, constructors are not methods. They are initializers and they do not return the new object. They work on the not-ready-yet object. When a constructor executing the object is not fully initialized, some of the final fields may not be initialized and the overall initialization still can fail if the constructor throws an exception. In our example, we do not have any constructor in the code. In such a case, Java creates a default constructor that accepts no argument and does not modify the already allocated but uninitialized object. If the Java code defines an initializer, then the Java compiler does not create a default one. A class can have many constructors, each having different parameter list. In addition to constructors Java classes can contain initializer blocks. They are blocks on the class level, the same level as the constructor and methods. The code in these blocks is compiled into the constructors and is executed when the constructor is executing. It is also possible to initialize static fields in static initializer blocks. These are the blocks on the top level inside the class with the static keyword in front of them. They are executed only once when the class is loaded. We named the classes in our example App and Sort. This is a convention in Java to name almost everything in CamelCase. CamelCase is when the words are written without spaces between them. The first word may start with lowercase or uppercase, and, to denote the start of the second and subsequent words, they start with uppercase. ForExampleThisIsALongCamelCase name. Class names start with an uppercase letter. This is not a requirement of the language formally, but this is a convention that every programmer should follow. These coding conventions help you create code that is easier to understand by other programmers, and lead to easier maintenance. Static code analyzer tools, such as Checkstyle (http://checkstyle.sourceforge.net/), also check that the programmers follow the conventions. Inner, nested, local, and anonymous classes I have already mentioned inner and nested classes in the previous section. Now we look at them in bit more detail. The details of inner and nested classes at this point may be difficult. Don't feel ashamed if you do not understand this section fully. If it is too difficult, skip to the next section and read about packages and return here later. Nested, inner, and local classes are rarely used, though they have their roles and use in Java. Anonymous classes were very popular in GUI programming with the Swing user interface that allowed developers to create Java GUI applications. With Java 8 and the lambda feature, anonymous classes are not so important these days, and with the emerging JavaScript and browser technology, the Java GUI became less popular. When a class is defined in a file on its own, it is called a top-level class. Classes that are inside another class are, obviously, not top-level classes. If they are defined inside a class on the same level as fields (variables that are not local to some method or other block), they are inner or nested classes. There are two differences between them. One is that nested classes have the static keyword before the class keyword at their definition, and inner classes don't. The other difference is that instances of nested classes can exist without an instance of the surrounding class. Inner class instances always have a reference to an instance of the surrounding class. Because inner class instances cannot exist without an instance of the surrounding class, their instance can only be created by providing an instance of the outer class. We will see no difference if the surrounding class instance is the actual this variable, but if we want to create an instance of an inner class from outside the surrounding class, then we have to provide an instance variable before the new keyword separated by a dot, just like if new were a method. For example, we could have a class named TopLevel that has a class named InnerClass, like in the following code snippet: public class TopLevel { class InnerClass { } } Then we can create an instance of the InnerClass from outside with only a TopLevel object, like in this snippet: TopLevel tl = new TopLevel(); InnerClass ic = tl.new InnerClass(); As inner classes have an implicit reference to an instance of the enclosing class, the code inside the inner class can access the fields and the methods of the enclosing class. Nested classes do not have an implicit reference to any instance of the enclosing class, and they may be instantiated with the new keyword without any reference to any instance of any other class. Because of that, they cannot access the fields of the enclosing class unless they are static fields. Local classes are classes that are defined inside a method, constructor, or an initializer block. We will soon talk about initializer blocks and constructors. Local classes can be used inside the block where they are defined. Anonymous classes are defined and instantiated in a single command. They are a short form of a nested, inner, or local class, and the instantiation of the class. Anonymous classes always implement an interface or extend a named class. The new keyword is followed by the name of the interface or the class with the argument list to the constructor between parentheses. The block that defines the body of the anonymous class stands immediately after the constructor call. In the case of extending an interface, the constructor can only be the one without argument. The anonymous class with no name cannot have its own constructors. In modern Java we usually use lambda instead of anonymous classes. Last but not least—well, actually, least I should mention that nested and inner classes can also be nested in deeper structures. Inner classes cannot contain nested classes, but nested classes can contain inner classes. Why? I have never met anyone who could reliably tell me the real reason. There is no architectural reason. It could be like that. Java does not permit that. However, it is not really interesting. If you happen to write code that has more than one level of class nesting then just stop doing it. Most probably you are doing something wrong. Packages Classes are organized into packages and the first code line in a file should specify the package that the class is in. package packt.java9.by.example.stringsort; If you do not specify the package, then the class will be in the default package. This should not be used, except in the simplest case when you want to try some code. With Java 9, you can use jshell for this purpose, so, as opposed to previous versions of Java, now the suggestion becomes very simple—never put any class in the default package. The name of the packages is hierarchical. The parts of the names are separated by dots. Using package names helps you avoid name collisions. Names of the classes are usually kept short and putting them into packages helps the organization of the program. The full name of a class includes the name of the package the class is in. Usually, we will put those classes into a package that are in some way related, and add something to a similar aspect of a program. For example, controllers in an MVC pattern program are kept in a single package. Packages also help you avoid name collision of classes. However, this only pushes the problem from class name collision to package name collision. We have to make sure that the name of the package is unique and does not cause any problem when our code is used together with any other library. When an application is developed, we just cannot know what other libraries will be used in later versions. To be prepared for the unexpected, the convention is to name the packages according to some Internet domain names. When a development company has the domain name acmecompany.com, then their software is usually under the com.acmecompany... packages. It is not a strict language requirement. It is only a convention to write the domain name from right to left, and use it as package name, but this proves to be fairly good in practice. Sometimes, like I do in this book, one can deviate from this practice so you can see that this rule is not carved in stone. When the rubber hits the road, and the code is compiled into byte code, the package becomes the name of the class. Thus, the full name of the Sort class is packt.java9.by.example.stringsort.Sort. When you use a class from another package, you can use this full name or import the class into your class. Again, this is on the language level. Using the fully qualified name or importing makes no difference when Java becomes byte code. Methods We have already discussed methods, but not in detail, and there are still some aspects that we should meet before we go on. There are two methods in the sample classes. There can be many methods in a class. Method names are also camel cased by convention, and the name starts with a lowercase letter, as opposed to classes. Methods may return a value. If a method returns a value, the method has to declare the type of the value it returns and, in that case, any execution of the code has to finish with a return statement. The return statement has an expression after the keyword, which is evaluated when the method is executed and is returned by the method. It is good practice to have only one single return from a method but, in some simple cases, breaking that coding convention may be forgiven. The compiler checks the possible method execution paths, and it is a compile-time error if some of the paths do not return a value. When a method does not return any value, it has to be declared to be void. This is a special type that means no value. Methods that are void, such as the public static void main method, may simply miss the return statement and just end. If there is a return statement, there is no place for any expression defining a return value after the return keyword. Again, this is a coding convention to not use the return statement in case of a method that does not return any value, but in some coding patterns, this may not be followed. Methods can be private, protected, public, and static, and we will discuss their meaning later. We have seen that the main method that was invoked when the program started is a static method. Such a method belongs to the class and can be invoked without having any instance of the class. Static methods are declared with the static modifier, and they cannot access any field or method that is not static. In our example, the sort method is not static, but as it does not access any field and does not call any nonstatic method (as a matter of fact, it does not call any method at all), it could just as well be static. If we change the declaration of the method to public static void sort(String[] names) { (note the word static), the program still works, but the IDE will give a warning while editing, for example: Static member 'packt.java9.by.example.stringsort.Sort.sort(java.lang.String[])' accessed via instance reference That is because you can access the method without an instance directly through the name of the Sort.sort(actualNames); class without the need of the sorter variable. Calling a static method via an instance variable is possible in Java (again something that seemed to be a good idea at the genesis of Java, but is probably not), but it may mislead the reader of the code into thinking that the method is an instance method. Making the sort method static, the main method can be as follows: public static void main(String[] args) { String[] actualNames = new String[]{ "Johnson", "Wilson", "Wilkinson", "Abraham", "Dagobert" }; Sort.sort(actualNames); for (final String name : actualNames) { System.out.println(name); } } It seems to be much simpler (it is), and, in case the method does not use any field, you may think that there is no reason to make a method non-static. During the first ten years of Java, static methods were in heavy use. There is even a term, utility class, which means a class that has only static methods and should not be instantiated. With the advent of Inversion of Control containers, we tend to use less static methods. When static methods are used, it is harder to use dependency injection, and it is also more difficult to create tests. We will discuss these advanced topics in the next few chapters. For now, you are informed as to what static methods are and that they can be used; however, usually, unless there is a very special need for them, we will avoid them. Later, we will look at how classes are implemented in the hierarchy, and how classes may implement interfaces and extend other classes. When these features are looked at, we will see that there are socalled abstract classes that may contain abstract methods. These methods have the abstract modifier, and they are not defined—only the name, argument types (and names), and return type are specified. A concrete (non-abstract) class extending the abstract class should define them. The opposite of abstract method is the final method declared with the final modifier. A final method cannot be overridden in subclasses. Interfaces Methods are also declared in interfaces. A method declared in an interface does not define the actual behavior of the method; they do not contain the code. They have only the head of the method; in other words, they are abstract implicitly. Although nobody does, you may even use the abstract keyword in an interface when you define a method. Interfaces look very similar to classes, but instead of using the class keyword, we use the interface keyword. Because interfaces are mainly used to define methods, the methods are public if no modifier is used. Interfaces can also define fields, but since interfaces cannot have instances (only implementing classes can have instances), these fields are all static and they also have to be final. This is the default for fields in interfaces, thus we do not need to write these if we defined fields in interfaces. It was a common practice to define only constants in some interfaces and then use these in classes. To do that, the easiest way was to implement the interface. Since these interfaces do not define any method, the implementation is nothing more than writing the implements keyword and the name of the interface into the header of the class declaration. This is bad practice because this way the interface becomes part of the public declaration of the class, although these constants are needed inside the class. If you need to define constants that are not local to a class but are used in many classes, then define them in a class and import the fields using import static or just use the name of the class and the field. Interfaces can also have nested classes, but they cannot have inner classes. The obvious reason for that is that inner class instances have a reference to an instance of the enclosing class. In the case of an interface, there are no instances, so an inner class could not have a reference to an instance of an enclosing interface, because that just does not exist. The joyful part of it is that we do not need to use the static keyword in the case of nested classes because that is the default, just as in the case of fields. With the advent of Java 8, you can also have default methods in interfaces that provide default implementation of the method for the classes that implement the interface. There can also be static and private methods in interfaces since Java 9. Methods are identified by their name and the argument list. You can reuse a name for a method and have different argument types; Java will identify which method to use based on the types of the actual arguments. This is called method overloading. Usually, it is easy to tell which method you call, but when there are types that extend each other, the situation becomes more complex. The standard defines very precise rules for the actual selection of the method that the compiler follows, so there is no ambiguity. However, fellow programmers who read the code may misinterpret overloaded methods or, at least, will have hard time identifying which method is actually called. Method overloading may also hinder backward compatibility when you want to extend your class. The general advice is to think twice before creating overloaded methods. They are lucrative, but may sometimes be costly. Argument passing In Java, arguments are passed by value. When the method modifies an argument variable, then only the copy of the original value is modified. Any primitive value is copied during the method call. When an object is passed as an argument, then the copy of the reference to the object is passed. That way, the object is available to be modified for the method. In the case of classes that have their primitive counterpart, and also in the case of String and some other class types, the objects simply do not provide methods or fields to modify the state. This is important for the integrity of the language, and to not get into trouble when objects and primitive values automatically get converted. In other cases, when the object is modifiable, the method can effectively work on the very object it was passed to. This is also the way the sort method in our example works on the array. The same array, which is also an object itself, is modified. This argument passing is much simpler than it is in other languages. Other languages let the developer mix the pass by reference and the pass by value argument passing. In Java, when you use a variable by itself as an expression to pass a parameter to a method, you can be sure that the variable itself is never modified. The object it refers to, however, in case it is mutable, may be modified. An object is mutable if it can be modified, altering the value of some of its field directly or via some method call. When a class is designed in a way that there is no normal way to modify the state of the object after the creation of the object, the object is immutable. The classes Byte, Short, Integer, Long, Float, Double, Boolean, Character, as well as String, are designed in the JDK so that the objects are immutable. It is possible to overcome the limitation of immutability implementation of certain classes using reflection, but doing that is hacking and not professional coding. Doing that can be done for one single purpose—getting a better knowledge and understanding of the inner workings of some Java classes, but nothing else. Fields Fields are variables on the class level. They represent the state of an object. They are variables, with defined type and possible initial value. Fields can be static, final, transient, and volatile, and the access may be modified with the public, protected, and private keywords. Static fields belong to the class. It means that there is one of them shared by all the instances of the class. Normal, non-static fields belong to the objects. If you have a field named f, then each instance of the class has its own f. If f is declared static, then the instances will share the very same f field. The final fields cannot be modified after they are initialized. Initialization can be done on the line where they are declared, in an initializer block or in the constructor code. The strict requirement is that the initialization has to happen before the constructor returns. This way, the meaning of the final keyword is very different, in this case, from what it means in the case of a class or a method. A final class cannot be extended and a final method cannot be overridden in an extending class, as we will see in the next chapter. The final fields are either uninitialized or get a value during instance creation. The compiler also checks that the code does initialize all final fields during the object-instance creation or during the class loading, in case the final field is static, and that the code is not accessing/reading any final field that was not yet initialized. It is a common misconception that the final fields have to be initialized at the declaration. It can be done in an initializer code or in a constructor. The restriction is that, no matter which constructor is called in case there are more, the final fields have to be initialized exactly once. The transient fields are not part of the serialized state of the object. Serialization is an act of converting the actual value of an object to physical bytes. Deserialization is the opposite when the object is created from the bytes. It is used to save the state in some frameworks. The code that does the serialization, java.lang.io.ObjectOutputStream, works only with classes that implement the Serializable interface, and uses only the fields from those objects that are not transient. Very obviously, transient fields are also not restored from the bytes that represent the serialized form of the object because their value is not there. Serialization is usually used in distributed programs. A good example is the session object of a servlet. When the servlet container runs on a clustered node, some fields of objects stored into the session object may magically disappear between HTTP hits. That is because serialization saves and reloads the session to move the session between the nodes. Serialization, in such a situation, may also be a performance issue if a developer does not know the side effects of the stored large objects in the session. The volatile keyword is a keyword that tells the compiler that the field may be used by different threads. When a volatile field is accessed by any code, the JIT compiler generates code which ensures that the value of the field accessed is up to date. When a field is not volatile, the compiler-generated code may store the value of the field in a processor cache or registry for faster access when it sees that the value will be needed soon by some subsequent code fragment. In the case of volatile fields, this optimization cannot be done. Additionally, note that saving the value to memory and loading from there all the time may be 50 or more times slower than accessing a value from a registry or cache. Modifiers Methods, constructors, fields, interfaces, and classes can have access modifiers. The general rule is that in case there is no modifier, the scope of the method, constructor, and so on, is the package. Any code in the same package can access it. When the private modifier is used, the scope is restricted to the so-called compilation unit. This means the class that is in one file. What is inside one file can see and use anything declared to be private. This way, inner and nested classes can have access to each other's private variables, which may not really be a good programming style, but Java permits that. The opposite of private is public. It extends the visibility to the whole Java program, or at least to the whole module, if the project is a Java 9 module. There is a middle way: protected. Anything with this modifier is accessible inside the package and also in classes that extend the class (regardless of package) that the protected method, field, and so on, is in. Object initializers and constructors When an object is instantiated, the appropriate constructor is called. The constructor declaration looks like a method with the following deviation: the constructor does not have a return value. That is because the constructors work on the not-fully-ready instance when the new command operator is invoked and does not return anything. Constructors, having the same name as the class, cannot be distinguished from each other. If there is a need for more than one constructor, they have to be overloaded. Constructors, thus, can call each other, almost as if they were void methods with different arguments. However, there is a restriction—when a constructor calls another, it has to be the very first instruction in the constructor. You use this() syntax with an appropriate argument list, which may be empty, to invoke a constructor from another constructor. The initialization of the object instance also executes initializer blocks. These are blocks containing executable code inside the { and } characters outside the methods and constructors. They are executed before the constructor in the order they appear in the code, together with the initialization of the fields in case their declarations contain value initialization. If you see the static keyword in front of an initializer block, the block belongs to the class and is executed when the class is loaded along with the static field initializers. Compiling and running the program Finally, we will compile and execute our program from the command line. There is nothing new in this one; we will only apply what we have learned in this chapter using the following two commands: $ mvn package This compiles the program, packages the result into a JAR file, and finally executes the following command: $ java -cp target/SortTutorial-1.0.0-SNAPSHOT.jar packt.java9.by.example.App This will print the following result on the command line: Summary In this chapter, we have developed a very basic sort algorithm. It was made purposefully simple so that we could reiterate the basic and most important Java language elements, classes, packages, variables, methods, and so on. We also looked at build tools, so we are not empty handed in the next chapters when projects will contain more than just two files. We will use Maven and Gradle in the following chapters. In the very next chapter, we will make the sort program more complex, implementing more effective algorithms and also making our code flexible, giving us the opportunity to learn more advanced Java language features. Optimizing the Sort - Making Code Professional In this chapter, we will develop the sorting code and make it more general. We want to sort not only an array of Strings. Essentially, we will write a program that can sort anything that is sortable. That way, we will bring the coding to its full extent toward one of the major strengths of Java: abstraction. Abstraction, however, does not come without a price tag. When you have a class that sorts strings and you accidentally mix an integer or something else, which is not a string, into the sortable data, then the compiler will complain about it: Java does not allow you to put an int into a String array. When the code is more abstract, such programming errors may slip in. We will look at how to handle such exceptional cases catching and throwing Exceptions. To identify the bugs, we will use unit testing, applying the industry standard JUnit version 4. As JUnit heavily uses annotation, and because annotations are important, you will learn about it a bit. After that, we will modify the code to use the generics feature of Java that was introduced into the language in version 5. Using that possibility, we will catch the coding error during compilation time, which is better than during run time. The earlier a bug is identified, the cheaper it is to fix. For the build, we will still use Maven, but this time, we will split the code into small modules. Thus, we will have a multi-module project. We will have separate modules for the definition of a sorting module and for the different implementations. That way, we will look at how classes can extend each other and implement interfaces, and, generally, we will really start to program in the object-oriented way. We will also discuss Test Driven Development (TDD), and at the end of the section, we will start using the brand new feature of Java 9: module support. In this chapter, we will cover the following topics: Object-oriented programming principles Unit testing practices Algorithmic complexity and quick sort Exception handling Recursive methods Module support The general sorting program In the previous chapter, we implemented a simple sort algorithm. The code can sort elements of a String array. We did this to learn. For practical use, there is a ready cooked sort solution in the JDK that can sort members of collections, which are comparable. The JDK contains a utility class called Collections. This class contains a static Collections.sort method that is capable of sorting any List that has members that are Comparable. List and Comparable are interfaces defined in the JDK. Thus, if we want to sort a list of Strings, the simplest solution is as follows: public class SimplestStringListSortTest { @Test public void canSortStrings() { ArrayList actualNames = new ArrayList(Arrays.asList( "Johnson", "Wilson", "Wilkinson", "Abraham", "Dagobert" )); Collections.sort(actualNames); Assert.assertEquals(new ArrayList<String>(Arrays.<String>asList( "Abraham", "Dagobert", "Johnson", "Wilkinson", "Wilson")), actualNames); } } This code fragment is from a sample JUnit test, which is the reason we have the @Test annotation in front of the method. We will discuss that in detail later. To execute that test, you can issue the following command: $ mvn -Dtest=SimplestStringListSortTest test This sort implementation, however, does not fit our needs. First of all, because it is there ready (no need to code) and using it does not need anything new that you have not learned in the previous chapters. Except for the annotation in front of the method, there is nothing new in the code that you cannot understand. You may refresh BY turning some pages back, or else consult the oracle online documentation of the JDK (https://docs.oracle.com/javase/8/docs/api/), but that is all. You already know these things. You may wonder why I wrote the URL for the Java version 8 API to the link. Well, then this is the moment of honesty and truth-when I wrote this book, the Java 9 JDK was not available in its final form. I created most of the examples on my Mac Book using Java 8 and I only tested the features that are Java 9 specific. Support at the moment for Java 9 in the IDEs is not perfect. When you read this book, Java 9 will be available, so you can try and change that one single digit from 8 to 9 in the URL and get to the documentation of the version 9. At the moment, I get HTTP ERROR 404. Sometimes, you may need the documentation of older versions. You can use 3, 4, 5, 6, or 7 instead of 8 in the URL. Documentation for 3 and 4 is not available to read online, but it can be downloaded. Hopefully, you will never need that anymore. Version 5, perhaps. Version 6 is still widely used at large corporations. Although you can learn a lot from reading code that was written by other programmers, I do not recommend trying to learn from the JDK source code at this early stage of your studies. These blocks of code are heavily optimized, not meant to be tutorial codes, and old. They do not get rusted during the years, but they were not refactored to follow the coding styles of Java as it matured. At some places, you can find really ugly code in the JDK. Okay, saying that we need to develop a new sort code because we can learn from it, is a bit contrived. The real reason why we need a sort implementation is that we want something that can sort not only List data types and a List of something that implements the Comparable interface. We want to sort a bunch of objects. All we require is that the bunch containing the objects provides simple methods that are just enough to sort them and have a sorted bunch. Originally I wanted to use the word collection instead of bunch, but there is a Collection interface in Java and I wanted to emphasize that we are not talking about java.util.Collection of objects. We also do not want the objects to implement the Comparable interface. If we require the object to implement the Comparable interface, it may violate the Single Responsibility Principle (SRP). When we design a class, it should model some object class of the real world. We will model the problem space with classes. The class should implement the features that represent the behavior of the objects that it models. If we look at the example of students from the second chapter, then a Student class should represent the features that all students share, and is important from the modeling point of view. A Student object should be able to tell the name of the student, the age, the average scores of the last year, and so on. All students have feet, and certainly each of those feet have size so we may think that a Student class should also implement a method that returns the size of the student's foot (one for the left and one for the right just to be precise), but we do not. We do not, because the size of the foot is irrelevant from the model point of view. If we want to sort a list containing Student objects, the Student class has to implement the Comparable interface. But wait! How do you compare two students? By names, by age. or by the average score of them? Comparing a student to another is not a feature of the Student. Every class, or for that matter, package, library, or programming unit should have one responsibility and it should implement only that and nothing else. It is not exact. This is not mathematics. Sometimes, it is hard to tell if a feature fits into the responsibility or not. There are simple techniques. For example, in case of a student, you can ask the real person about his name and age, and probably they can also tell you their average score. If you ask one of them to compareTo (another student), as the Comparable interface requires this method, they will probably ask back, but by what attribute? Or how? Or just, what? In such a case, you can suspect that implementing the feature is probably not in the area of that class and this concern; the comparison should be segregated from the implementation of the original class. This is also called Segregation of Concerns, which is closely related to SRP. JDK developers were aware of this. Collections.sort that sorts a List of Comparable elements is not the only sorting method in this class. There is another that just sorts any List if you pass a second argument and object that implements the Comparator interface and is capable of comparing two elements of List. This is a clean pattern to separate the concerns. In some cases, separating the comparison is not needed. In other cases, it is desirable. The Comparator interface declares one single method that the implementing classes have to provide: compare. If the two arguments are equal, then this method returns 0. If they are different, it should return a negative or a positive int depending on which argument precedes which one. There are also sort methods in the JDK class, java.util.Arrays. They sort arrays, or only a slice of an array. The method is a good example of method overloading. There are methods with the same name, but with different arguments to sort a whole array for each primitive type, for a slice of each, and also two for object array implementing the Comparable interface, and also for object array to be sorted using Comparator. As you see, there is a whole range of sort implementations available in the JDK, and in 99 percent of the cases, you will not need to implement a sort yourself. The sorts use the same algorithm, a stable merge sort with some optimization. What we will implement is a general approach that can be used to sort lists, arrays, or just anything that has elements and it is possible to swap any two elements of it; the solution will be able to use the bubble sort that we have already developed and also other algorithms. A brief overview of various sorting algorithms There are many different sorting algorithms. As I said, there are simpler and more complex algorithms and, in many cases, more complex algorithms are the ones that run faster. In this chapter, we will implement the bubble sort and quick sort. We have already implemented the bubble sort for strings in the previous chapter, so in this case, the implementation will mainly focus on the recoding for general sortable object sorting. Implementing quick sort will involve a bit of algorithmic interest. Be warned that this section is here to give you only a taste of algorithmic complexity. It is far from precise and I am in the vain hope that no mathematician reads this and puts a curse on me. Some of the explanations are vague. If you want to learn computer science in depth, then after reading this book, find some other books or visit online courses. When we talk about the general sorting problem, we will think about some general set of objects that can be compared and any two of them can be swapped while we sort. We will also assume that this is an inplace sort; thus, we do not create another list or array to collect the original objects in sorted order. When we talk about the speed of an algorithm, we are talking about some abstract thing and not milliseconds. When we want to talk about milliseconds, actual real-world duration, we should already have some implementation in some programming language running on a real computer. Algorithms, in their abstract form, don't do that without implementation. Still, it is worth talking about the time and memory need of an algorithm. When we do that, we will usually investigate how the algorithm behaves for a large set of data. For a small set of data, most algorithms are just fast. Sorting two numbers is usually not an issue, is it? In case of sorting, we will usually examine how many comparisons are needed to sort a collection of n elements. Bubble sort needs approximately n2 (n times n) comparisons. We cannot say that this is exactly n2 because in case of n=2, the result is 1, for n=3 it is 3, for n=4 it is 6, and so on. However, as n starts to get larger, the actual number of comparisons needed and n2 will asymptotically be of the same value. We say that the algorithmic complexity of the bubble sort is O(n2). This is also called the big-O notation. If you have an algorithm that is O(n2) and it works just fine for 1,000 elements finishing in a second, then you should expect the same algorithm finishing for 1 million elements in around ten days or in a month. If the algorithm is linear, say O(n), then finishing 1,000 element in one second should make you expect 1 million to be finished in 1,000 seconds. That is a bit longer than a coffee break and too short for lunch. This makes it feasible that if we want some serious business sorting objects, we will need something better than bubble sort. That many unnecessary comparisons are not only wasting our time, but also CPU power, consuming energy, and polluting the environment. The question, however, is: how fast can a sort be? Is there a provable minimum that we cannot overcome? The answer is yes. When we implement any sorting algorithm, the implementation will execute comparisons and element swaps. That is the only way to sort a collection of objects. The outcome of a comparison can have two values. Say, these values are 0 or 1. This is one bit of information. If the result of the comparison is 1, then we swap, if the result is 0, then we do not swap. We can have the objects in different orders before we start the comparison and the number of different orders is n! (n factorial). That is, the numbers multiplied from 1 to n, in other words n!=1*2*3*...*(n1)*n. Let's assume that we stored the result of the individual comparisons in a number as a series of bits for each possible input for the sort. Now, if we reverse the execution of the sort and run the algorithm starting from the sorted collection, control the swapping using the bits that described the results of the comparison, and we use the bits the other way around doing the last swap first and the one that was done first during the sorting first, we should get back the original order of the objects. This way, each original order is uniquely tied to a number expressed as an array of bits. Now, we can express the original question this way: how many bits are needed to describe n factorial different numbers? That is exactly the number of comparisons we will need to sort n elements. The number of bits is log2(n!) . Using some mathematics, we will know that log2(n!) is the same as log2(1)+ log2(2)+...+ log2(n). If we look at this expression's asymptotic value, then we can say that this is the same O(n*log n). We should not expect any general sorting algorithm to be faster. For special cases, there are faster algorithms. For example, if we want to sort 1 million numbers that are each between one and 10, then we only need to count the number of the different numbers and then create a collection that contains that many ones, twos, and so on. This is an O(n) algorithm, but this is not applicable for the general case. Again, this was not a formal mathematical proof. Quick sort Sir Charles Antony Richard Hoare developed the quick sort algorithm in 1959. It is a typical divide and conquer algorithm. To sort a long array, pick an element from the array that will be the pivot element. Then, partition the array so that the left side will contain all the elements that are smaller than the pivot and the right side will contain all the elements that are larger than, or equal to the pivot. When this is done, the left side and the right side of the array can be sorted by calling the sort recursively. To stop the recursion, when we have one single element in the array, we will declare it sorted. We talk about a recursive algorithm when the algorithm is defined partially using itself. The most famous recursive definition is the Fibonacci series that is 0 and 1 for the first two elements and any later element the nth element is the sum of the (n-1)th and the (n-2)th element. Recursive algorithms are many times implemented in modern programming languages implementing a method that does some calculation but sometimes calls itself. When designing recursive algorithms, it is of utmost importance to have something that stops the recursive calls; otherwise, recursive implementation will allocate all memory available for the program stack and stop the program with error. The partitioning algorithm goes the following way: we will start to read the array using two indices from the start and end. We will first start with the index that is small and increase the index until it is smaller than the large index, or until we find an element that is greater than or equal to the pivot. After this, we will start to decrease the larger index so long as it is greater than the small index and the element indexed is greater than or equal to the pivot. When we stop, we swap the two elements pointed by the two indices, if the indices are not the same, and we will start increasing and decreasing the small and large indices, respectively. If the indices are the same, then we are finished with the partitioning. The left side of the array is from the start to the index where the indices met minus one; the right side starts with the index and lasts until the end of the to-be-sorted array. This algorithm is usually O(n log n), but in some cases it can degrade to be O(n2), depending on how the pivot is chosen. There are different approaches for the selection of the pivot. In this book, we will use the simplest: we will select the first element of the sortable collection as a pivot. <project> <br/>... <br/> <modules> <br/> <module>SortInterface</module> <br/> <module>bubble</module> <br/> <module>quick</module> <br/> </modules> <br/> </project> $ tree <br/> |-SortInterface <br/> |---src/main/java/packt/java9/by/example/ch03 <br/> |bubble <br/> |---src <br/> |-----main/java/packt/java9/by/example/ch03/bubble <br/> |----test/java/packt/java9/by/example/ch03/bubble <br/> |-quick/src/ <br/> |-----main/java <br/> |-----test/java Maven dependency management Dependencies are also important in the POM file. The previous project did not have any dependency, but this time we will use JUnit. Dependencies are defined in pom.xml using the dependencies tag. For example, the bubble sort module contains the following piece of code: <dependencies> <dependency> <groupId>packt.java9.by.example</groupId> <artifactId>SortInterface</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies> The actual pom.xml in the code set you can download will contain more code than this. In print, we often present a version or only a fraction that helps the understanding of the topic that we are discussing at that point. It tells Maven that the module code uses classes, interfaces, and enum types that are defined in these modules that are available from some repository. When you use Maven to compile the code, the libraries that are used by your code are available from repositories. When Ant was developed, the notion of repositories was not invented. At that time, the developers copied the used version of the library into a folder in the source code structure. Usually, the directory lib was used for the purpose. There were two problems with this approach. One is the size of the source code repository. If, for example, 100 different projects used JUnit, then the JAR file of the JUnit library was copied there 100 times. The other problem was to gather all the libraries. When a library used another library, the developers had to read the documentation of the library that described (many times outdated and not precise) what other libraries are needed to use this library. Those libraries had to be downloaded and installed the same way. This was time consuming and error prone. When a library was missing and the developers just did not notice it, the error was manifested during compile time when the compiler could not find the class or even only at runtime when the JVM was not able to load the class. To solve this issue, Maven comes with a built-in repository manager client. The repository is a storage that contains the libraries. As there can be other types of files in a repository, not only libraries, Maven terminology is artifact. The groupId, the artifactId, and the version number identify an artifact. There is a very strict requirement that an artifact can only be put into a repository once. Even if there is an error during the release process that is identified after the erroneous release was uploaded, the artifact cannot be overwritten. For the same groupId, artifactId, and version, there can only be one single file that will never change. If there was an error, then a new artifact is to be created with new version number and the erroneous artifact may be deleted but not replaced. If the version number ends with -SNAPSHOT, then this uniqueness is not guaranteed or required. Snapshots are usually stored in separate repository and are not published for the world. Repositories contain the artifacts in directories that are organized in a defined way. When Maven runs, it can access different repositories using https protocol. Formerly, the http protocol was also used, and for non-paying customers, the central repository was available via http only. However, it was discovered that modules downloaded from the repository could be targets for men-in-the-middle security attacks and Sonatype (http://www.sonatype.com) changed the policy and used https protocol only. Never configure or use a repository with the http protocol. Never trust a file that you downloaded from HTTP. There is a local repository on the developer machine, usually under the ~/.m2/repository directory. When you issue the mvn install command, Maven stores the created artifact here. Maven also stores an artifact here when it is downloaded from a repository via HTTPS. This way, subsequent compilations do not need to go out to the network for the artifacts. Companies usually set up their own repository manager (the one that Sonatype, the company backing Maven, is providing Nexus). These applications can be configured to communicate with several other repositories and collect the artifacts from there on demand, essentially implementing proxy functionality. Artifacts travel to the build from the far end repositories to the closer ones in a hierarchical structure to the local repo and essentially to the final artifact if the packaging type of the project is war, ear, or some other format that encloses the dependent artifacts. This is essentially file caching without revalidation and cache eviction. This can be done because of the strict rules of artifact uniqueness. This is the reason for such a strict rule. If the project bubble were a standalone project, and not part of a multi-module one, then the dependency would look like this: <dependencies> <dependency> <groupId>packt.java9.by.example</groupId> <artifactId>SortInterface</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies> If version is not defined for a dependency, Maven will not be able to identify which artifact to use. In the case of a multi-module project, version can be defined in the parent and the modules can inherit the version. As the parent is not dependent on the actual dependency, it only defines the version attached to the groupId and artifactId; the XML tag is not dependencies, but dependencyManagement/dependencies under the toplevel project tag as in the following example: <dependencyManagement> <dependencies> <dependency> <groupId>packt.java9.by.example</groupId> <artifactId>SortInterface</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement> If the parent POM uses the dependencies tag directly, Maven is not able to decide if the parent depends on that artifact or some modules. When the modules want to use junit, they need not specify the version. They will get it from the parent project defined as 4.12, which is the latest from JUnit 4. If ever there will be a new version 4.12.1, with some serious bugs fixed, then the only place to modify the version number is the parent POM, and the modules will use the new version starting with the next execution of the Maven compilation. When the new version, JUnit 5, comes out, however, the modules will all have to be modified because JUnit is not just a new version. Version 5 of JUnit is split into several modules and, this way, groupId and artifactId will also change. It is also worth noting that the modules that implement the interfaces from the SortInterface module are eventually dependent on this module. In this case, the version is defined as follows: <version>${project.version}</version> That seems to be a bit tautological (it is, actually). The ${project.version} property is the version of the project and it is inherited by the SortInterface module. This is the version of the artifact that the other modules depend on. In other words, the modules always depend on the version that we are currently developing. Code the sort To implement the sort, first, we will define the interfaces that a sort library should implement. Defining the interface before the actual coding is a good practice. When there are many implementations, it is sometimes recommended to first create a simple one and start using it so that the interface may evolve during the phase, and when the more complex implementations are due, then the interface to be implemented is already fixed, more or less. package packt.java9.by.example.ch03; <br/><br/>public interface Sort { <br/> void sort(SortableCollection collection); <br/>} package packt.java9.by.example.ch03; <br/><br/>public interface SortableCollection { <br/>} Creating BubbleSort Now, we can start creating the bubble sort that implements the Sort interface: package packt.java9.by.example.ch03.bubble; import packt.java9.by.example.ch03.*; import java.util.Comparator; public class BubbleSort implements Sort { @Override public void sort(SortableCollection collection) { int n = collection.size(); while (n > 1) { for (int j = 0; j < n - 1; j++) { if (comparator.compare(collection.get(j), collection.get(j + 1)) > 0) { swapper.swap(j, j + 1); } } n--; } } Normally, the algorithm to execute needs two operations that we implemented in the code last time specific to a String array: comparing two elements and swapping two elements. As this time the sort implementation itself does not know what type the elements are used and also does not know if the something it sorts is an array, a lists or something else, it needs something that does it for the sort when needed. More precisely, it needs a comparator object capable of comparing two elements and it needs a swapper object that is capable of swapping two elements in the collection. To get those, we can implement two setter methods that can set the objects for the purpose before sort is invoked. As this is not specific to the bubble sort algorithm but is rather general, these two methods should also be made a part of the interface, so the implementation is overriding it. private Comparator comparator = null; @Override public void setComparator(Comparator comparator) { this.comparator = comparator; } private Swapper swapper = null; @Override public void setSwapper(Swapper swapper) { this.swapper = swapper; } } The @Override annotation signals for the Java compiler that the method is overriding a method of the parent class, or, as in this case, of the interface. A method can override a parent method without this annotation; however, if we use the annotation, the compilation fails if the method does actually not override something. This helps you discover during compile time that something was changed in the parent class or in the interface and we did not follow that change in the implementation, or that we just made some mistake thinking that we will override a method when we actually do not. As annotations are heavily used in unit tests, we will talk about annotations in a bit more detail later. Amending the interfaces The modified Sort interface will look like this: public interface Sort { void sort(SortableCollection collection); void setSwapper(Swapper swap); void setComparator(Comparator compare); } This also means that we will need two new interfaces: Swapper and Comparator. We are lucky that the Java runtime already defines a Comparator interface that just fits the purpose. You may have guessed that from the following import statement: import java.util.Comparator; When you need something very basic, like a comparator interface, it is most probably defined in the runtime. It is advisable to consult the runtime before writing your own version. The Swapper interface, however, we will have to create. package packt.java9.by.example.ch03; public interface Swapper { void swap(int i, int j); } As it is used to swap two elements specified by the indices in SortableCollection, there is a method, quite trivially named swap for the purpose. But, we are not ready yet. If you try to compile the preceding code, the compiler will complain about the get and size methods. They are needed by the algorithm to implement the sort, but they are not inherently part of the sorting itself. This is a responsibility that should not be implemented in the sort. As we do not know what type of collections we will sort, it is not only unadvisable but also impossible to implement these functionalities inside the sort. It seems that we just cannot sort anything. There are some restrictions we will have to set. The sorting algorithm must know the size of the collection we sort and also should have access to an element by index so that it can pass it on to the comparator. These restrictions are expressed in the SortableCollection interface that we just left empty not knowing before the first sort implementation what is required to be there. package packt.java9.by.example.ch03; public interface SortableCollection { Object get(int i); int size(); } Now, we are ready with the interfaces and the implementation and we can go on testing the code. But, before that, we will briefly reiterate what we did and why we did that. Architectural considerations We created an interface and a simple implementation of it. During the implementation, we discovered that the interface needs other interfaces and methods that are needed to support the algorithm. This usually happens during the architectural design of the code, before implementation. For didactical reasons, I followed the build-up of the interfaces while we developed the code. In real life, when I created the interfaces, I created them all in one step as I have enough experience. I wrote my first quick sort code around 1983 in Fortran. However, it does not mean that I hit the bull's eye with just any problem and come out with the final solution. It just happens that sort is a too well known problem. If you need to modify the interfaces or other aspects of your design during development, do not feel embarrassed. It is a natural consequence and a proof that you understand things better and better as time goes by. If the architecture needs change, it is better to be done than not, and the sooner it is, the better. In real life enterprise environments, we will design interfaces just to learn during development that there were some aspects that we forgot. They are very true and bit more complex operations than sorting a collection. In the case of the sorting problem, we abstracted the something we want to sort to the most possible extreme. The Java build in sort can sort arrays or lists. If you want to sort something that is not a list or an array, you have to create a class that implements the java.util.List interface with more than 24 methods it requires to wrap your sortable object to make it sortable by the JDK sort. To be honest, that is not too many, and in a real-world project, I would consider that as an option. However, we do not, and cannot know, what methods of the interface the built-in sort uses. Those that are used should be functionally implemented and those that are not, can contain a simple return statement because they are just never invoked. A developer can consult the source code of the JDK and see what methods are actually used, but that is not the contract of the search implementation. It is not guaranteed that a new version will still use only those methods. If a new version starts to use a method that we implemented with a single return statement, the sort will magically fail. It is also an interesting performance question how the swapping of two elements is implemented by the search using only the List interface. There is no put(int, Object) method in the List interface. There is add(int Object), but that inserts a new element and it may be extremely costly (burning CPU, disk, energy) to push all elements of the list up if the objects are stored, for example, on disk. Furthermore, the next step may be removing the element after the one we just inserted, doing the costly process of moving the tail of the list again. That is, the trivial implementation of put(int,Object) that the sort may or may not follow. Again, this is something that should not be assumed. When developers use libraries, classes, and methods from the JDK, open source, or commercial libraries, the developers may consult the source code but they should not rely on the implementation. You should rely only on the contract and the definition of the API that the library comes with. When you implement an interface from some external library, and you do not need to implement some part of it, and create some dummy methods, feel the danger in the air. It is an ambush. It is likely that either the library is poor quality or you did not understand how to use it. In our case, we separated the swapping and the comparison from the sort. The collection should implement these operations and provide them for the sort. The contract is the interface, and to use the sort, you have to implement all methods of the interfaces we defined. The interface of Sort defines setters that set Swapper and Comparator. Having dependencies set that way may lead to a code that creates a new instance of a class implementing the Sort interface, but does not set Swapper and Comparator before invoking Sort. This will lead to NullPointerException the first time the Comparator is invoked (or when the Swapper is invoked in case the implementation invokes that first, which is not likely, but possible). The calling method should inject the dependencies before using the class. When it is done through setters, it is called setter injection. This terminology is heavily used when we use frameworks such as Spring, Guice, or some other container. Creating these service classes and injecting the instance into our classes is fairly similar all the time. Container implementations contain the functionality in a general way and provide configuration options to configure what instances are to be injected into what other objects. Usually, this leads to shorter, more flexible, and more readable code. However, dependency injection is not exclusive to containers. When we write the testing code in the next section, and invoke the setters, we actually do dependency injection. There is another way of dependency injection that avoids the problem of dependencies not being set. This is called constructor injection. The dependencies are final private fields with no values. Remember that these fields should get their final values by the time the constructor finishes. Constructor injection passes the injected values to the constructor as arguments and the constructor sets the fields. This way, the fields are guaranteed to be set by the time the object was constructed. This injection, however, cannot be defined in an interface. Now, we already have the code, and we know the considerations of how the interfaces were created. This is the time to do some testing. Creating unit tests When we write code, we should test it. No code has ever gone into production before at least doing some test runs. There are different levels of tests having different aims, technologies, industry practices, and names. Unit tests, as the name suggests, test a unit of code. Integration tests test how the units integrate together. Smoke tests test a limited set of the features just to see that the code is not totally broken. There are other tests, until the final test, which is the proof of the work: user acceptance test. Proof of the pudding is eating it. A code is good if the user accepts it. Many times, I tell juniors that the name user acceptance test is a bit misleading, because it is not the user who accepts the result of a project, but the customer. By definition, the customer is the person who pays the bill. Professional development is paid; otherwise, it is not professional. The terminology is, however, user acceptance test. It just happens that customers accept the project only if the users can use the program. When we develop in Java, unit test is testing standalone classes. In other words, in Java development, a unit is a class when we talk about unit tests. To furnish unit tests, we usually use the JUnit library. There are other libraries, such as TestNG, but JUnit is the most widely used, so we will use JUnit. To use it as a library, first, we will have to add it to the Maven POM as a dependency. Adding JUnit as dependency Recall that we have a multi-module project, and the dependency versions are maintained in the parent POM under the dependencyManagement tag. <dependencyManagement> <dependencies> ... <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement> The scope of the dependency is test, which means that this library is needed only to compile the test code and during the execution of the test. The JUnit library will not make its way to the final released product; there is no need for it. If you find the JUnit library in some deployed production Web Archive (WAR) file, suspect that somebody was not properly managing the scopes of the libraries. Maven supports the compilation and the execution of JUnit tests in the lifecycle of the project. If we want to execute the tests, only we can issue the mvn test command. The IDEs also support the execution of the unit tests. Usually, the same menu item that can be used to execute a class that has a public static main method can be used. If the class is a unit test utilizing JUnit, the IDE will recognize it and execute the tests and usually give a graphical feedback on what test was executing fine and which ones failed, and how. Writing the BubbleSortTest class The test classes are separated from the production classes. They go into the src/test/java directory. When we have a class named, for example, BubbleSort, then the test will be named BubbleSortTest. This convention helps the executing environment to separate the tests from those classes that do not contain tests but are needed to execute the tests. To test the sort implementation we have just created, we can furnish a class that contains, for now, a single canSortStrings method. Unit test method names are used to document the functionality being tested. As the JUnit framework invokes each and every method that has the @Test annotation, the name of the test is not referenced anywhere in our code. We can bravely use arbitrary long method names; it will not hinder readability at the place where the method is invoked. package packt.java9.by.example.ch03.bubble; // imports deleted from print public class BubbleSortTest { @Test public void canSortStrings() { ArrayList actualNames = new ArrayList(Arrays.asList( "Johnson", "Wilson", "Wilkinson", "Abraham", "Dagobert" )); The method contains ArrayList with the actual names that we have already gotten familiar with. As we have a sort implementation and interface that needs SortableCollection, we will create one backed up by ArrayList. SortableCollection namesCollection = new SortableCollection() { @Override public Object get(int i) { return actualNames.get(i); } @Override public int size() { return actualNames.size(); } }; We declared a new object that has the SortableCollection type, which is an interface. To instantiate something that implements SortableCollection, we will need a class. We cannot instantiate an interface. In this case, define the class in the place of the instantiation. This is called an anonymous class in Java. The name comes from the fact that the name of the new class is not defined in the source code. The Java compiler will automatically create a name for the new class, but that is not interesting for the programmers. We will simply write new SortableCollection() and provide the needed implementation immediately following between { and }. It is very convenient to define this anonymous class inside the method as, this way, it can access ArrayList without passing a reference to ArrayList in the class. As a matter of fact, the reference is needed, but the Java compiler automatically does this. The Java compiler, in this case, also takes care that automatic reference passing this way can only be done using variables that were initialized and will not change during the execution of the code after the instantiation of the anonymous class. The variable actualNames was set and it should not be changed in the method later. As a matter of fact, we can even define actualNames to be final and this would have been a requirement if we used Java 1.7 or earlier. Starting with 1.8, the requirement is that the variable is effectively final, but you need not declare it to be final. The next thing that we need is a Swapper implementation for ArrayList. In this case, we will define a whole class inside the method. It can also be an anonymous class, but this time I decided to use a named class to demonstrate that a class can be defined inside a method. Usually, we do not do that in production projects. class SwapActualNamesArrayElements implements Swapper { @Override public void swap(int i, int j) { final Object tmp = actualNames.get(i); actualNames.set(i,actualNames.get(j)); actualNames.set(j, tmp); } } Last, but not least, we will need a comparator before we can invoke the sort. As we have Strings to compare, this is easy and straightforward. Comparator stringCompare = new Comparator() { @Override public int compare(Object first, Object second) { final String f = (String) first; final String s = (String) second; return f.compareTo(s); } }; Having everything prepared for the sorting, we will finally need an instance of the Sort implementation, set the comparator and the swapper, and invoke the sort. Sort sort = new BubbleSort(); sort.setComparator(stringCompare); sort.setSwapper(new SwapActualNamesArrayElements()); sort.sort(namesCollection); The last, but most important part of the test is to assert that the result is the one that we expect. JUnit helps us do that with the aid of the Assert class. Assert.assertEquals(Arrays.asList("Abraham", "Dagobert", "Johnson", "Wilkinson", "Wilson"), actualNames); } } The call to assertEquals checks that the first argument, the expected result, equals the second argument, the sorted actualNames. If they differ, then AssertionError is thrown; otherwise, the test just finishes fine. Good unit tests Is this a good unit test? If you read it in a tutorial book like this, it has to be. Actually, it is not. It is a good code to demonstrate some of the tools that JUnit provides and some Java language features, but as a real JUnit test, I will not use it in a real life project. What makes a unit test good? To answer this question, we will have to find what the unit test is good for and what it is that we use it for. We will create unit tests to validate the operation of the units and to document. Unit tests are not to find bugs. Developers eventually use unit tests during debugging sessions but, many times, the testing code created for the debugging is a temporary one. When the bug is fixed, the code used to find it will not get into the source code. For every new bug, there should be a new test created that covers the functionality that was not properly working, but it is hardly the test code that is used to find the bug. This is because unit tests are mainly for documentation. You can document a class using JavaDoc, but the experience shows that the documentation often becomes outdated. The developers modify the code, but they do not modify the documentation, and the documentation becomes obsolete and misleading. Unit tests, however, are executed by the build system and if Continuous Integration (CI) is in use (and it should be, in a professional environment), then the build will be broken if a test fails, all developers will get mail notification about it, and it will drive the developer breaking the build to fix the code or the test. This way, the tests verify that continuous development did not break anything in the code or, at least, not something that can be discovered using unit tests. A good unit test is readable Our test is far from being readable. A test case is readable if you look at it and in 15 seconds you can tell what it does. It assumes, of course, some experience in Java on behalf of the reader, but you get the point. Our test is cluttered with support classes that are not core to the test. Our test also hardly validates that the code is working properly. It actually does not. There are some bugs in it that I put there deliberately, which we will locate and zap in the following sections. One single test that sorts a single String array is far from validating a sort implementation. If I were to extend this test to a real-world test, we would need methods that would have the name canSortEmptyCollection, canSortOneElementCollection, canSortTwoElements, canSortReverseOrder, or canSortAlreadySorted. If you look at the names, you will see what tests we need. Coming from the nature of the sort problem, an implementation may be reasonably sensitive to errors in these special cases. What are the good points in our unit test, in addition to it being an acceptable demonstration tool? Unit tests are fast Our unit test runs fast. As we execute unit tests each time, the CI fires up a build and the execution of the tests should not last long. You should not create a unit test sorting billions of elements. That is a kind of stability or load test and they should run in separate test periods and not every time the build is running. Our unit test sorts five elements that are reasonable. Unit tests are deterministic Our unit test is deterministic. Non-deterministic unit tests are the nightmare of the developers. If you are in a group where some builds break on the CI server, and when a build breaks, your fellow developer says that you just have to try it again; no way! If a unit test runs, it should run all times. If it fails, it should fail no matter how many times you start it. A non-deterministic unit test, in our case, will be to render random numbers and have them sorted. We will end up with different arrays in each test run and, in case there is some bug in the code that manifests for some array, we will not be able to reproduce it. Not to mention that the assertion that the code was running fine is also difficult. If we sorted a random array in a unit test (something we do not), we could, hypothetically, assert that the array is sorted, comparing the elements one after the other checking that they are in ascending order. It would also be a totally wrong practice. Assertions should be as simple as possible If the assertion is complex, the risk of introducing bugs in the assertion is higher. The more complex the assertion, the higher the risk. We will write the unit tests to ease our lives and not to have more code to debug. Additionally, one test should assert only one thing. This one assertion may be coded with multiple Assert class methods, one after the other. Still, the aim of these is to assert the correctness of one single feature of the unit. Remember the SRP: one test, one feature. A good test is like a good sniper: one shot, one kill. Unit tests are isolated When we test a unit A, any change in another unit B, or a bug in a different unit should not affect our unit test that is for the unit A. In our case, it was easy because we have only one unit. Later, when we develop the test for the quick sort, we will see that this separation is not that simple. If the unit tests are properly separated, a failing unit test clearly points out the location of the problem. It is in the unit where the unit test failed. If tests do not separate the units, then a failure in one test may be caused by a bug in a different unit than we expect. In this case, these tests are not really unit tests. In practice, you should make a balance. If the isolation of the units will be too costly, you can decide to create integration tests; and, if they still run fast, have them executed by the CI system. At the same time, you should also try to find out why the isolation is hard. If you cannot easily isolate the units in the tests, it means that the units are too strongly coupled, which may not be a good design. Unit tests cover the code Unit tests should test all usual and also all special cases of the functionality. If there is a special case of code that is not covered by the unit test, the code is in danger. In case of a sort implementation, the general case is sorting, say five elements. The special cases are much more numerous usually. How does our code behave if there is only one element or if there are no elements? What if there are two? What if the elements are in reverse order? What if they are already sorted? Usually, the special cases are not defined in the specification. The programmer has to think about it before coding, and some special cases are discovered during coding. The hard thing is that you just cannot tell if you covered all special cases and the functionality of the code. What you can tell is if all the lines of code were executed during the testing or not. If 90% of the code lines are executed during the tests, then the code coverage is 90%, which is fairly good in real life, but you should never be content with anything less than 100%. Code coverage is not the same as functional coverage, but there is a correlation. If the code coverage is less than 100%, then at least one of the following two statements is true: The functional coverage is not 100% There is unused code in the tested unit, which can just be deleted The code coverage can be measured, the functional coverage cannot. The tools and IDEs support code coverage measurement. These measurements are integrated into the editor so you will not only get the percentage of the coverage, but the editor will show you exactly which lines are not covered by the coverage coloring the lines (in Eclipse, for example) or the gutter on the left side of the editor window (IntelliJ). The picture shows that in IntelliJ, the tests cover the lines indicated by a green color on the gutter. (In the print version this is just a grey rectangle). Refactor the test Now that we have discussed what a good unit test is, let's improve our test. The first thing is to move the supporting classes to separate files. We will create ArrayListSortableCollection: package packt.java9.by.example.ch03.bubble; import packt.java9.by.example.ch03.SortableCollection; import java.util.ArrayList; public class ArrayListSortableCollection implements SortableCollection { final private ArrayList actualNames; ArrayListSortableCollection(ArrayList actualNames) { this.actualNames = actualNames; } @Override public Object get(int i) { return actualNames.get(i); } @Override public int size() { return actualNames.size(); } } This class encapsulates ArrayList and then implements the get and size methods to ArrayList access. ArrayList itself is declared as final. Recall that a final field has to be defined by the time the constructor finishes. This guarantees that the field is there when we start to use the object and that it does not change during the object lifetime. Note, however, that the content of the object, in this case, the elements of ArrayList, may change. If it were not the case, we would not be able to sort it. The next class is StringComparator. This is so simple that I will not list it here; I will leave it to you to implement the java.util.Comparator interface that can compare two Strings. It should not be difficult, especially as this class was already a part of the previous version of the BubbleSortTest class (hint: it was an anonymous class that we stored in the variable named stringCompare). We also have to implement ArrayListSwapper, which also should not be a big surprise. package packt.java9.by.example.ch03.bubble; import packt.java9.by.example.ch03.Swapper; import java.util.ArrayList; public class ArrayListSwapper implements Swapper { final private ArrayList actualNames; ArrayListSwapper(ArrayList actualNames) { this.actualNames = actualNames; } @Override public void swap(int i, int j) { Object tmp = actualNames.get(i); actualNames.set(i, actualNames.get(j)); actualNames.set(j, tmp); } } Finally, our test will look this: package packt.java9.by.example.ch03.bubble; // ... imports deleted from print ... public class BubbleSortTest { @Test public void canSortStrings() { ArrayList actualNames = new ArrayList(Arrays.asList( "Johnson", "Wilson", "Wilkinson", "Abraham", "Dagobert" )); ArrayList expectedResult = new ArrayList(Arrays.asList( "Abraham", "Dagobert", "Johnson", "Wilkinson", "Wilson" )); SortableCollection names = new ArrayListSortableCollection(actualNames); Sort sort = new BubbleSort(); sort.setComparator( new StringComparator()); sort.setSwapper( new ArrayListSwapper(actualNames)); sort.sort(names); Assert.assertEquals(expectedResult, actualNames); } } Now this is already a test that can be understood in 15 seconds. It documents well how to use a sort implementation that we defined. It still works and does not reveal any bug, as I promised. Collections with wrong elements The bug is not trivial, and as usual, this is not in the implementation of the algorithm, but rather in the definition, or the lack of it. What should the program do if there are not only strings in the collection that we sort? If I create a new test that starts with the following lines, it will throw ClassCastException: @Test public void canNotSortMixedElements() { ArrayList actualNames = new ArrayList(Arrays.asList( 42, "Wilson", "Wilkinson", "Abraham", "Dagobert" )); ... the rest of the code is the same as the previous test The problem here is that Java collections can contain any type of elements. You cannot ever be sure that a collection, such as ArrayList, contains only the types that you expect. Even if you use generics (we have not learned that, but we will in this chapter), the chances of a bug somehow conjuring up some object of an inappropriate type into a collection, are smaller but are still there. Don't ask me how; I cannot tell you. This is the nature of the bugs—you cannot tell how they work until you zap them. The thing is that you have to be prepared for such an exceptional case. Handling exceptions Exceptional cases should be handled in Java using exceptions. The ClassCastException is there and it happens when the sort tries to compare String to Integer using StringComparator, and to do that, it tries to cast an Integer to String. When an exception is thrown by the program using the throw command, or by the Java runtime, the execution of the program stops at that point, and instead of executing the next command, it continues where the exception is caught. It can be in the same method, or in some calling method up in the call chain. To catch an exception, the code throwing the exception should be inside a try block, and the catch statement following the try block should specify an exception that is compatible with the exception thrown. If the exception is not caught, then the Java runtime will print out the message of the exception along with a stack trace that will contain all the classes, methods, and line numbers on the call stack at the time of the exception. In our case, the mvn test command will produce the following trace in the output: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at packt.java9.by.example.ch03.bubble.StringComparator.compare(StringComparator.java:9) at packt.java9.by.example.ch03.bubble.BubbleSort.sort(BubbleSort.java:13) at packt.java9.by.example.ch03.bubble.BubbleSortTest.canNotSortMixedElements(BubbleSortTest.java:49) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) ... some lines deleted from the print at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ... some lines deleted from the print at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85) at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75) This stack trace is not really long. In the production environment in an application that runs on an application server, the stack trace may contain a few hundred elements. In this trace, you can see that Maven was starting the test execution, involved Maven surefire plugin, and then the JUnit executor, until we get through the test to the comparator, where the actual exception was thrown. This exception was not printed by the Java runtime to the console. This exception is caught by the JUnit library code and the stack trace is logged out to the console using Maven logging facility. The problem with this approach is that the real issue is not the class casting failure. The real issue is that the collection contains mixed elements. It is only realized by the Java runtime when it tries to cast two incompatible classes. Our code can be smarter. We can amend the comparator. package packt.java9.by.example.ch03.bubble; import java.util.Comparator; public class StringComparator implements Comparator { @Override public int compare(Object first, Object second) { try { final String f = (String) first; final String s = (String) second; return f.compareTo(s); } catch (ClassCastException cce) { throw new NonStringElementInCollectionException ( "There are mixed elements in the collection.", cce); } } } This code catches the ClassCastException and throws a new one. The advantage of throwing a new exception is that you can be sure that this exception is thrown from the comparator and that the problem really is that there are mixed elements in the collection. Class casting problems may happen at other places of the code as well, inside some of the sort implementations. Some application code may want to catch the exception and want to handle the case; for example, sending an application-specific error message and not dumping only a stack trace to the user. This code can catch ClassCastException as well, but it cannot be sure what the real cause of the exception is. On the other hand, NonStringElementInCollectionException is definite. The NonStringElementInCollectionException is an exception that does not exist in the JDK. We will have to create it. Exceptions are Java classes and our exception looks as follows: package packt.java9.by.example.ch03.bubble; public class NonStringElementInCollectionException extends RuntimeException { public NonStringElementInCollectionException (String message, Throwable cause) { super(message, cause); } } Java has the notion of checked exceptions. It means that any exception that is not extending RuntimeException should be declared in the method definition. Suppose our exception was declared as follows: public class NonStringElementInCollectionException extends Exception Then, we will have to declare the compare method as follows: public int compare(Object first, Object second) throws NonStringElementInCollectionException The problem is that the exception a method throws is part of the method signature, and this way compare will not override the compare method of the interface, and, that way, the class will not implement the Comparator interface. Thus, our exception has to be a runtime exception. There can be a hierarchy of exceptions in an application, and often, novice programmers create huge hierarchies of them. If there is something you can do, it does not mean that you should do it. Hierarchies should be kept as flat as possible, and this is especially true for exceptions. If there is an exception in the JDK that describes the exceptional case, then use the readymade exception. Just as well as for any other class: if it is ready, do not implement it again. It is also important to note that throwing an exception should only be done in exceptional cases. It is not to signal some normal operational condition. Doing that hinders readability of the code and also eats CPU. Throwing an exception is not an easy task for the JVM. It is not only the exception that can be thrown. The throw command can throw, and the catch command can catch anything that extends the Throwable class. There are two subclasses of Throwable: Error, and Exception. The Error exception is thrown if some error happened during the execution of the Java code. The two most infamous errors are OutOfMemoryError and StackOverflowError. If any of these happens, you cannot do anything reliably to catch the error. There is also InternalError and UnknownError in the JVM, but since JVM is fairly stable, you will hardly ever meet these errors. When any of those errors happen, try to debug the code and try to find out why you use that much memory or such deep method calls and try to optimize your solution. What I have just said about creating exception hierarchies is true again to catch errors. The fact that you can catch errors does not mean that you should. On the contrary, you should never catch an error and, especially, never ever catch a Throwable. This way, we handled this special case when some programmer accidentally writes 42 among the names, but will it be nicer if the error was identified during compile time? To do that, we will introduce generics. Just a last thought before we go there. What class behavior do we test with the canNotSortMixedElements unit test? The test is inside the BubbleSortTest test class, but the functionality is in the comparator implementation, StringComparator. This test checks something that is out of the scope of the unit test class. I can use it for demonstration purposes, but this is not a unit test. The real functionality of the sort implementation can be formulized this way: whatever exception the comparator throws is thrown by the sort implementation. You can try to write this unit test, or read on; we will have it in the next section. The StringComparator class does not have a test class because StringComparator is part of the test and we will never write a test for a test. Otherwise, we will sink into an endless rabbit hole. Generics The generics feature was introduced into Java in version 5. To start with an example, our Sortable interface until now was this: package packt.java9.by.example.ch03; public interface SortableCollection { Object get(int i); int size(); } After introducing generics, it will be as follows: package packt.java9.by.example.ch03; public interface SortableCollection<E> { E get(int i); int size(); } The E identifier denotes a type. It can be any type. It says that a class is a sortable collection if it implements the interface, namely the two methods— size and get. The get method should return something that is of type E, whatever E is. This may not make too much sense up until now, but you will soon get the point. After all, generics is a difficult topic. The Sort interface will become the following: package packt.java9.by.example.ch03; import java.util.Comparator; public interface Sort<E> { void sort(SortableCollection<E> collection); void setSwapper(Swapper swap); void setComparator(Comparator<E> compare); } This still does not provide much more value than the previous version without generics, but, at least, it does something. In the actual class implementing the Sort interface, Comparator should accept the same type that SortableCollection uses. It is not possible that SortableCollection works on strings and we inject a comparator for integers. The implementation of BubbleSort is as follows: package packt.java9.by.example.ch03.bubble; import packt.java9.by.example.ch03.*; import java.util.Comparator; public class BubbleSort<E> implements Sort<E> { @Override public void sort(SortableCollection<E> collection) { ... sort code same as before } private Comparator<E> comparator = null; @Override public void setComparator(Comparator<E> comparator) { this.comparator = comparator; } ... method swapper same as before } The real power of generics will come when we will write the tests. The first test does not change much, although with the generics, it is more definite. @Test public void canSortStrings() { ArrayList<String> actualNames = new ArrayList< >(Arrays.asList( "Johnson", "Wilson", "Wilkinson", "Abraham", "Dagobert" )); ArrayList<String> expectedResult = new ArrayList<>(Arrays.asList( "Abraham", "Dagobert", "Johnson", "Wilkinson", "Wilson" )); SortableCollection<String> names = new ArrayListSortableCollection<>(actualNames); Sort<String> sort = new BubbleSort<>(); sort.setComparator(String::compareTo); sort.setSwapper(new ArrayListSwapper<>(actualNames)); sort.sort(names); Assert.assertEquals(expectedResult, actualNames); } When we define ArrayList, we will also declare that the elements of the list will be strings. When we allocate the new ArrayList, there is no need to specify again that the elements are strings because it comes from the actual elements there. Each of them is a string; therefore, the compiler knows that the only thing that can come between the < and > character is String. The two characters < and >, without the type definition in between, is called diamond operator. The type is inferred. If you get used to generics, this code brings you more information on the types that the collections work on and the code becomes more readable. The readability and the extra information is not the only point. As we know that the Comparator argument is Comparator<String> now, we can use advanced features of Java available since Java 8 and can pass the String::compareTo method reference to the comparator setter. The second test is the important one for us now. This is the test which ensures that Sort does not interfere with the exception that the comparator throws. @Test(expected = RuntimeException.class) public void throwsWhateverComparatorDoes () { ArrayList<String> actualNames = new ArrayList<>(Arrays.asList( 42, "Wilson", "Wilkinson", "Abraham", "Dagobert" )); SortableCollection<String> names = new ArrayListSortableCollection<>(actualNames); Sort<String> sort = new BubbleSort<>(); sort.setComparator((String a, String b) -> { throw new RuntimeException(); }); final Swapper neverInvoked = null; sort.setSwapper(neverInvoked); sort.sort(names); } The thing is, that it does not even compile. The compiler says that it cannot infer the type of ArrayList<> on the third line. When all the arguments of the asList method were strings, the method returned a list of String elements and therefore the new operator was known to generate ArrayList<String>. This time, there is an integer, and thus, the compiler cannot infer that ArrayList<> is for String elements. To change the type definition from ArrayList<> to ArrayList<String> is not a cure. In that case, the compiler will complain about the value 42. This is the power of generics. When you use classes that have type parameters, the compiler can detect when you provide a value of the wrong type. To get the value into ArrayList to check that the implementation really throws an exception, we will have to conjure the value into it. We can try to replace the value 42 with an empty String and then add the following line which will still not compile: actualNames.set(0,42); The compiler will still know that the value you want to set in ArrayList is supposed to be String. To get the array with the Integer element, you will have to explicitly unlock the safety handle and pull the trigger, shooting yourself: ((ArrayList)actualNames).set(0,42); Now, the test looks like this: @Test(expected = RuntimeException.class) public void throwsWhateverComparatorDoes() { ArrayList<String> actualNames = new ArrayList<>(Arrays.asList( "", "Wilson", "Wilkinson", "Abraham", "Dagobert" )); ((ArrayList) actualNames).set(0, 42); SortableCollection<String> names = new ArrayListSortableCollection<>(actualNames); Sort<String> sort = new BubbleSort<>(); sort.setComparator((a, b) -> { throw new RuntimeException(); }); final Swapper neverInvoked = null; sort.setSwapper(neverInvoked); sort.sort(names); } We will set the Swapper to be null because it is never invoked. When I first wrote this code, it was evident to me. A few days later, I read the code and I stopped. Why is swapper null? Then I remembered in a second or two. But any time, when reading and understanding the code hicks up, I tend to think about refactoring. I can add a comment to the line saying //never invoked, but comments tend to remain there even when functionality changes. I learned it the hard way in 2006, when a wrong comment prevented me from seeing how the code was executing. I was reading the comment while debugging, instead of the code, and bug fixing took two days while the system was down. Instead of a comment, I tend to use constructs that make the code express what happens. The extra variable may make the class file a few bytes bigger, but it is optimized out by the JIT compiler so the final code does not run slower. The comparator that throws an exception was provided as a lambda expression. Lambda expressions can be used in cases where an anonymous class or named class will be used having only one simple method. Lambda expressions are anonymous methods stored in variables or passed in argument for later invocation. We will discuss the details of lambda expressions in Chapter 8, Extending our E-Commerce Application. For now, we will go on implementing QuickSort, and to do that, we will use the TDD methodology. Test Driven Development Test Driven Development (TDD) is a code writing approach when the developers first write a test based on the specification and then write the code. This is just the opposite that the developer community got used to. The conventional approach that we followed was to write the code and then write tests for it. To be honest, the real practice many times was to write the code and test it with ad-hoc tests and no unit tests at all. Being a professional, you will never do that, by the way. You always write tests. (And now, write it down a hundred times: I will always write tests.) One of the advantages of TDD is that the tests do not depend on the code. As the code does not exist at the creation of the test, developers cannot rely on the implementation of the unit and, thus, it cannot influence the test creation process. This is generally good. Unit tests should be black box tests as much as possible. Black box test is a test that does not take into account the implementation of the tested system. If a system is refactored, implemented in a different way, but the interface it provides toward the external world is the same, then the black box tests should run just fine. A white box test depends on the internal working of the system tested. When the code changes the white box test, the code may also need tuning to follow the change. The advantage of a white box test can be the simpler test code. Not always. Gray box test is a mixture of the two. Unit tests should be black box tests, but, many times, it is not simple to write a black box test. Developers will write a test that they think is black box, but many times, this belief proves to be false. When the implementation changes, something is refactored and the test does not work anymore and it needs to be corrected. It just happens that knowing the implementation, the developers, especially those who wrote the unit, will write a test that depends on the internal working of the code. Writing the test before the code is a tool to prevent this. If there is no code, you cannot depend on it. TDD also says that the development should be an iterative approach. You write only one test at the start. If you run, it fails. Of course it fails! As there is no code yet, it has to fail. Then, you will write the code that fulfills this test. Nothing more, only the code that makes this test pass. Then, you will go on writing a new test for another part of the specification. You will run it and it fails. This proves that the new test does test something that was not developed yet. Then, you will develop the code to satisfy the new test and, possibly, you will also modify a block of code that you have already written in the previous iterations. When the code is ready, the tests will pass. Many times, developers are reluctant to modify the code. This is because they are afraid of breaking something that was already working. When you follow TDD, you should not, and at the same time, you need not be afraid of this. There are tests for all features that were already developed. If some of the code modification breaks some functionality, the tests will immediately signal the error. The key is that you run the tests as often as possible when the code is modified. Implementing QuickSort Quick sort, as we have already discussed, is made of two major parts. One is partitioning and the other one is doing the partitioning recursively until the whole array is sorted. To make our code modular and ready to demonstrate the Java 9 module-handling feature, we will develop the partitioning and the recursive sorting into separate classes and in a separate package. The complexity of the code will not justify this separation. The partitioning class The partitioning class should provide a method that moves the elements of the collection based on a pivot element, and we will need to know the position of the pivot element after the method finishes. The signature of the method should look something like this: public int partition(SortableCollection<E> sortable, int start, int end, E pivot); The class should also have access to Swapper and Comparator. In this case, we defined a class and not an interface; therefore, we will use constructor injection. These constructs, like setters and constructor injectors, are so common and happen so frequently that IDEs support the generation of these. You will need to create the final fields in the code and use the code generation menu to create the constructor. The partitioning class will look like the following: package packt.java9.by.example.ch03.qsort; import packt.java9.by.example.ch03.SortableCollection; import packt.java9.by.example.ch03.Swapper; import java.util.Comparator; public class Partitioner<E> { private final Comparator<E> comparator; private final Swapper swapper; public Partitioner(Comparator<E> comparator, Swapper swapper){ this.comparator = comparator; this.swapper = swapper; } public int partition(SortableCollection<E> sortable, int start, int end, E pivot){ return 0; } } This code does nothing, but that is how TDD starts. We will create the definition of a requirement providing the skeleton of the code and the test that will call it. To do that, we will need something that we can partition. The simplest choice is an Integer array. The partition method needs a object of type SortableCollection<E>, and we will need something that wraps the array and implements this interface. We name that class ArrayWrapper. This class serves a general purpose and it is not only for the test. Because of that, we create it as production code and as such we put it in the directory main and not in the directory test. As this wrapper is independent from the implementation of Sort, the proper position of this class is in a new SortSupportClasses module. We will create the new module as it is not part of the interface. Implementations depend on the interface, but not on the support classes. There can also be some application that uses our libraries and may need the interface module and some of the implementation but still does not need the support classes when they deliver the wrapping functionality themselves. After all, we cannot implement all possible wrapping functionality. The SRP also holds for the modules. Java libraries tend to contain unrelated functionalities. For the short run, it makes the use of the library simpler. You will only need to specify one dependency in your POM file and you will have all the classes and APIs that you need. In the long run, the application gets bigger, carrying a lot of classes that are part of some of the libraries but the application never uses them. To add the new module, the module directory has to be created along with the source directories and the POM file. The module has to be added to the parent POM and it also has to be added to the dependencyManagement section so that the test code of the QuickSort module can use it without specifying the version. The new module depends on the interface module, so this dependency has to be added to the POM of the support classes. The ArrayWrapper class is simple and general. package packt.java9.by.example.ch03.support; import packt.java9.by.example.ch03.SortableCollection; public class ArrayWrapper<E> implements SortableCollection<E> { private final E[] array; public ArrayWrapper(E[] array) { this.array = array; } public E[] getArray() { return array; } @Override public E get(int i) { return array[i]; } @Override public int size() { return array.length; } } The ArraySwapper class, which we also need, comes into the same module. It is just as simple as the wrapper. package packt.java9.by.example.ch03.support; import packt.java9.by.example.ch03.Swapper; public class ArraySwapper<E> implements Swapper { private final E[] array; public ArraySwapper(E[] array) { this.array = array; } @Override public void swap(int k, int r) { final E tmp = array[k]; array[k] = array[r]; array[r] = tmp; } } Having these classes, we can create our first test. package packt.java9.by.example.ch03.qsort; // imports deleted from print public class PartitionerTest { Before creating the @Test method, we will need two helper methods that make assertions. Assertions are not always simple, and in some cases, they may involve some coding. The general rule is that the test and the assertions in it should be as simple as possible; otherwise, they are just possible source of programming errors. Additionally, we created them to avoid programming errors, not to create new ones. The assertSmallElements method asserts that all elements before cutIndex are smaller than pivot. private void assertSmallElements(Integer[] array, int cutIndex, Integer pivot) { for (int i = 0; i < cutIndex; i++) { Assert.assertTrue(array[i] < pivot); } } The assertLargeElements method makes sure that all elements following cutIndex are at least as large as pivot. private void assertLargeElemenents(Integer[] array, int cutIndex, Integer pivot) { for (int i = cutIndex; i < array.length; i++) { Assert.assertTrue(pivot <= array[i]); } } The test uses a constant array of Integers and wraps it into an ArrayWrapper class. @Test public void partitionsIntArray() { Integer[] partitionThis = new Integer[]{0, 7, 6}; Swapper swapper = new ArraySwapper<>(partitionThis); Partitioner<Integer> partitioner = new Partitioner<>((a, b) -> a < b ? -1 : a > b ? +1 : 0, swapper); final Integer pivot = 6; final int cutIndex = partitioner.partition(new ArrayWrapper<>(partitionThis), 0, 2, pivot); Assert.assertEquals(1, cutIndex); assertSmallElements(partitionThis, cutIndex, pivot); assertLargeElemenents(partitionThis, cutIndex, pivot); } } There is no Comparator for Integer type in the JDK, but it is easy to define one as a lambda function. Now we can write the partition method, as follows: public int partition(SortableCollection<E> sortable, int start, int end, E pivot){ int small = start; int large = end; while( large > small ){ while( comparator.compare(sortable.get(small), pivot) < 0 && small < large ){ small ++; } while( comparator.compare(sortable.get(large), pivot) >= 0 && small < large ){ large--; } if( small < large ){ swapper.swap(small, large); } } return large; } If we run the test, it runs fine. However, if we run the test with coverage, then the IDE tells us that the coverage is only 92%. The test covered only 13 of the 14 lines of the partition method. There is a red rectangle on the gutter at line 28. This is because the test array is already partitioned. There is no need to swap any element in it when the pivot value is 6. It means that our test is good, but not good enough. What if there is an error on that line? To amend this problem, we will extend the test, changing the test array from { 0, 7, 6 } to { 0, 7, 6, 2}. Run the test and it fails. Why? After some debugging, we will realize that we invoke the method partition with the fixed parameter 2 as the last index of the array. But, we made the array longer. Why did we write a constant there in the first place? It is a bad practice. Let's replace it with partitionThis.length-1. Now, it says that cutIndex is 2, but we expected 1. We forgot to adjust the assertion to the new array. Let's fix it. Now it works. The last thing is to rethink the assertions. The less code the better. The assertion methods are quite general, and we will use it for one single test array. The assertion methods are so complex that they deserve their own test. But, we do not write code to test. Instead of that, we can simply delete the methods and have the final version of the test. @Test public void partitionsIntArray() { Integer[] partitionThis = new Integer[]{0, 7, 6, 2}; Swapper swapper = new ArraySwapper<>(partitionThis); Partitioner<Integer> partitioner = new Partitioner<>((a, b) -> a < b ? -1 : a > b ? +1 : 0, swapper); final Integer pivot = 6; final int cutIndex = partitioner.partition(new ArrayWrapper<>(partitionThis), 0, partitionThis.length-1, pivot); Assert.assertEquals(2, cutIndex); final Integer[] expected = new Integer[]{0, 2, 6, 7}; Assert.assertArrayEquals(expected,partitionThis); } And then again, is this a black-box test? What if the partitioning returns {2, 1, 7, 6}? It fits the definition. We can create more complex tests to cover such cases. But a more complex test may also have a bug in the test itself. As a different approach, we can create tests that may be simpler but rely on the internal structure of the implementation. These are not black-box tests and thus not ideal unit tests. I will go for the second one, but I will not argue if someone chooses the other. Recursive sorting We will implement the quick sort with an extra class that is in the qsort package along with the partitioning class, which is as follows: package packt.java9.by.example.ch03.qsort; // imports deleted from the print public class Qsort<E> { // constructor injected final fields deleted from the print public void qsort(SortableCollection<E> sortable, int start, int end) { if (start < end) { final E pivot = sortable.get(start); final Partitioner<E> partitioner = new Partitioner<>(comparator, swapper); int cutIndex = partitioner.partition(sortable, start, end, pivot); if (cutIndex == start) { cutIndex++; } qsort(sortable, start, cutIndex - 1); qsort(sortable, cutIndex, end); } } } The method gets SortableCollection<E> and two index parameters. It does not sort the whole collection; it sorts only the elements between the start and the end index. It is always important to be extremely precise with the indexing. Usually, there is no problem with the start index in Java, but a lot of bugs source from how the end index is interpreted. In this method, the value of end can mean that the index is already not part of the to-besorted interval. In that case, the partition method should be invoked with end-1 and the first recursive call with cutIndex as last parameter. It is a matter of taste. The important thing is to be precise and define the interpretation of index parameters. If there is only one element (start == end), then there is nothing to be sorted and the method returns. This is the end criterion of the recursion. The method also assumes that the end index is never smaller than the start index. As this method is used only inside the library that we are developing at the moment, such an assumption is not too risky to make. If there is something to be sorted, then the method takes the first element of the to-be-sorted interval and uses it as pivot and calls the partition method. When the partition is done, the method recursively calls itself for the two halves. This algorithm is recursive. This means that the method calls itself. When a method call is executed, the processor allocates some memory in an area called stack and it stores the local variables there. This area that belongs to the method in the stack is called stack frame. When the method returns, this area is released and the stack is restored, simply moving the stack pointer where it was to the previous state. This way a method can continue its execution after calling another method; the local variables are there. When a method calls itself, it is not different. The local variables are local to the actual call of the method. When the method calls itself, it allocates space for the local variables again on the stack. In other words, these are new instances of the local variables. We will use recursive methods in Java, and in other programming languages, when the definition of the algorithm is recursive. It is extremely important to understand that when the processor code runs, it is not recursive any more. On that level, there are instructions, register stores, and memory loads and jumps. There is nothing like function or method and therefore, on that level, there is nothing like recursion. If you get that, it is easy to understand that any recursion can be coded as a loop. As a matter of fact, it is also true the other way around—every loop can be coded as recursion but that is not really interesting until you start functional programming. The problem with the recursion in Java, and in many other programming languages, is that it may run out of stack space. In the case of quick sort, this is not the case. You can safely assume that the stack for method calling in Java is a few hundreds of levels. Quick sort needs a stack that is approximately log2n deep, where n is the number of elements to be sorted. In the case of one billion elements, this is 30 that should just fit. Why is the stack not moved or resized? That is because the code that runs out of the stack space is usually bad style. They can be expressed more readable in form of some loop. A more robust stack implementation would only lure the novice programmer to do some less readable recursive coding. There is a special case of recursion named tail recursion. A tail recursive method calls itself as the last instruction of the method. When the recursive call returns the code, executing the method does nothing else but release the stack frame that was used for this method invocation. In other words, we will keep the stack frame during the recursive call just to throw it away afterwards. Why not throw it away before the call? In that case, the actual frame, which has the same size and call, will allocate because this is just the same method that is kept and the recursive call is transformed into a jump instruction. This is an optimization that Java does not do. Functional languages are doing it, but Java is not really a functional language and therefore tail-recursive functions should rather be avoided and transformed to a loop in the Java source level. Non-recursive sorting To demonstrate that even non-tail recursive methods can be expressed in a non-recursive way, here is the quick sort that way: public class NonRecursiveQuickSort<E> { // injected final fields and constructor deleted from print private static class Stack { final int begin; final int fin; public Stack(int begin, int fin) { this.begin = begin; this.fin = fin; } } public void qsort(SortableCollection<E> sortable, int start, int end) { final List<Stack> stack = new LinkedList<>(); final Partitioner<E> partitioner = new Partitioner<>(comparator, swapper); stack.add(new Stack(start, end)); int i = 1; while (!stack.isEmpty()) { Stack iter = stack.remove(0); if (iter.begin < iter.fin) { final E pivot = sortable.get(iter.begin); int cutIndex = partitioner.partition(sortable, iter.begin, iter.fin, pivot); if( cutIndex == iter.begin ){ cutIndex++; } stack.add(new Stack(iter.begin, cutIndex - 1)); stack.add(new Stack(cutIndex, iter.fin)); } } } } This code implements a stack on the Java level. While it sees that there is still something scheduled to be sorted in stack, it fetched it from the stack and does the sort partitioning, and schedules the two parts for being sorted. This code is more complex than the previous one and you have to understand the role of the Stack class and how it works. On the other hand, the program uses only one instance of the Partitioner class and it is also possible to use a thread pool to schedule the subsequent sorts instead of handling the tasks in a single process. This may speed up the sort when it is executed on a multi-CPU machine. However, this is a bit more complex task and this chapter contains a lot of new things without multitasking; therefore, we will look at multithread code in two chapters later only. In the very first version of the sort, I was coding it without the three lines that compare cutIndex against the interval start and increments it in the if branch. It is needed very much. But, the unit tests we created in this book do not discover the bug if we miss those lines. I recommend that you just delete those lines and try to write some unit tests that fail. Then try to understand what the special case is when those lines are vital and try to modify your unit test so that it is the simplest possible that still discovers that bug. (Finally, put the four lines back and see if the code works.) Additionally, find some architectural reason why not to put this modification into the method partition. That method could just return large+1 in case large == start. Implementing the API class Having done all this, the last thing we will need is to have QuickSort as a simple class (all the real work was already done in different classes). public class QuickSort<E> implements Sort<E> { public void sort(SortableCollection<E> sortable) { int n = sortable.size(); Qsort<E> qsort = new Qsort<>(comparator,swapper); qsort.qsort(sortable, 0, n-1); } // ... setter injectors were deleted from the print } Do not forget that we also need a test! But, in this case, that is not much different than that of BubbleSort. @Test public void canSortStrings() { final String[] actualNames = new String[]{ "Johnson", "Wilson", "Wilkinson", "Abraham", "Dagobert" }; final String[] expected = new String[]{"Abraham", "Dagobert", "Johnson", "Wilkinson", "Wilson"}; Sort<String> sort = new QuickSort<>(); sort.setComparator(String::compareTo); sort.setSwapper(new ArraySwapper<String>(actualNames)); sort.sort(new ArrayWrapper<>(actualNames)); Assert.assertArrayEquals(expected, actualNames); } This time, we used String array instead of ArrayList. This makes this test simpler and, this time, we already have the support classes. You may recognize that this is not a unit test. In the case of BubbleSort, the algorithm was implemented in a single class. Testing that single class is a unit test. In the case of QuickSort, we separated the functionality into separate classes, and even into separate packages. A real unit test of the QuickSort class will disclose the dependency of that class on other classes. When this test runs, it involves the execution of Partitioner and also Qsort; therefore, it is not really a unit test. Should we bother about that? Not really. We want to create unit tests that involve a single unit to know where the problem is when a unit test fails. If there were only integration tests, a failing test case would not help a lot in pointing out where the problem is. All it says is that there is some problem in the classes that are involved in the test. In this case, there are only a limited number of classes (three) that are involved in this test and they are tied together. They are actually tied together and related to each other so closely that in the real production code, I would have implemented them in a single class. I separated them here to demonstrate how to test a single unit and also to demonstrate Java 9 module support that needs a bit more than a single class in a JAR file. Creating modules Module handling, also known as project Jigsaw, is a feature that was made available only in Java 9. It was a long planned feature that the developers were waiting for. First it was planned for Java 7, but it was so complex that it got postponed to Java 8 and then to Java 9. A year ago, it seemed that it would get postponed again, but finally, the project code got into the early releases and now nothing can stop from being part of the release. Why modules are needed We have already seen that there are four levels of access in Java. A method or field can be private, protected, public, or default (also known as package private) when no modifier is supplied. When you develop a complex library to be used in several projects, the library itself will contain many classes in many packages. There will certainly be classes and methods, fields in those that are used inside the library by other classes from different packages, but classes that are not to be used by the code outside the library. Making them anything less visible than public will render them unusable inside the library. Making them public will make them visible from outside. In our code, the Maven module quick compiled to a JAR can only be used if the method sort can invoke qsort. But, we do not want qsort to be used directly from outside. In the next version, we may want to develop a version of the sort that uses qsort from the NonRecursiveQuickSort class and we do not want complaining customers whose code does not compile or work because of a minor library upgrade. We can document that the internal methods and classes are still public but not for use, but in vain. Developers using our library do not read documentation. This is also why we do not write excessive comments. Nobody will read it, not even the processor executing the code. The most well-known and infamous example of this problem is the sun.misc.Unsafe class in the JDK. There is some really unsafe code in it, as the name implies. You can access memory out of heap, create objects without initialization, and so on. You should not. Why bother? You are a well-behaving developer and you just stick to the rules and you do not use that package. Whenever it changes in a new version of the JDK, your program is safe using only public and well-documented JDK API. Right? Wrong! Without being aware of this, you may use some libraries that depend on other libraries that use the package. Mockito and Spring Framework are only two of the numerous in danger. In addition, Java 9 will definitely come with a new version of this package. However, it will also come with module handling. While Java 9 will provide some useful API for the libraries that were using the Unsafe package because there was no provided API for the functionality they needed, it will deliver modules not to recreate the same problem again. What is a Java module A Java module is a collection of classes in a JAR or in a directory that also contain a special class named module-info. If there is this file in a JAR or directory then it is a module, otherwise it is just a collection of classes that are on the classpath (or not). Java 8, and the earlier versions, will just ignore that class as it is never used as code. This way, using older Java, causes no harm and backward compatibility is maintained. The module information defines what the module exports and what it requires. It has a special format. For example, we can place module-info.java in our SortInterface Maven module. module packt.java9.by.example.ch03{ exports packt.java9.by.example.ch03; } This means that any class, which is public and inside the packt.java9.by.example.ch03 package, can be used from outside. This package is exported from the module, but other classes from other packages are not visible from outside of the module even if they are public. The name of the module is same as the package, but this is mere convention in case there is only one package exported. The requirement is the same as in the case of packages: there should be a name that is not likely to collide with other module names. The reversed domain name is a good choice but it is not a must as you can see in this book. There is no toplevel domain packt, yet. We should also configure the parent POM to ensure that the compiler we use is Java 9, <build> ... <plugins> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.9</source> <target>1.9</target> </configuration> </plugin> ... Older versions would be confused with the module-info.java file. (By the way, even the early access version of Java 9 I use for this book sometimes gives a hard time.) We also create a module-info.java file in the Maven module, quick, which is as follows: module packt.java9.by.example.ch03.quick{ exports packt.java9.by.example.ch03.quick; requires packt.java9.by.example.ch03; } This module exports another package and requires the packt.java9.by.example.ch03 module that we have just created. Now, we can compile the modules and the created JARs in the./quick/target and ./SortInterface/target directories are now Java 9 modules. As Maven does not fully support the modules yet, when I issue the mvn install command, I get the following error message: [ERROR] .../genericsort/quick/src/main/java/module-info.java:[3,40] module not found: packt.java9.by.example.ch03 Maven puts the compiled modules on classpath, but Java 9 seeks modulepath for modules. Maven does not handle modulepath yet. To hack modulepath to the compiler, we will have to add the following configuration lines to the parent POM to the configuration of the compiler plugin:<compilerArgs> <arg>-modulepath</arg> <arg>${project.parent.basedir}/SortInterface/target/SortInterface-1.0.0-SNAPSHOT.jar: ...</arg> </compilerArgs> The actual file should list all the colon separated JAR files that Maven generates, and on which some of the modules depend. These are the SortInterface, quick, and SortSupportClasses. To test the functionality of module support, we will create another Maven module called Main. It has only one class, called Main, with a public static void main method: package packt.java9.by.example.ch03.main; // ... imports deleted from the print public class Main { public static void main(String[] args) throws IOException { String fileName = args[0]; BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(fileName)))); List<String> lines = new LinkedList<>(); String line; while ((line = br.readLine()) != null) { lines.add(line); } br.close(); String[] lineArray = lines.toArray(new String[0]); Sort<String> sort = new QuickSort<>(); Qsort<String> qsort = new Qsort<>(String::compareTo,new ArraySwapper<>(lineArray)); sort.setComparator(String::compareTo); sort.setSwapper(new ArraySwapper<>(lineArray)); sort.sort(new ArrayWrapper<>(lineArray)); for (final String outLine : lineArray) { System.out.println(outLine); } } } It takes the first argument (without checking that there is one, which we should not use in a production code) and uses that as a file name. Then, it reads the lines of the file into a String array, sorts it, and prints it to the standard output. As the module support only works for modules, this Maven module also has to be a Java module and have a module-info.java file. module packt.java9.by.example.ch03.main{ requires packt.java9.by.example.ch03.quick; requires packt.java9.by.example.ch03; requires packt.java9.by.example.ch03.support; } Additionally, we will have to create a module-info.java file for the support module; otherwise, we will not be able to use it from our module. After compiling the modules using mvn , we can run it to print out the parent POM. install java -cp Main/target/Main-1.0.0-SNAPSHOT.jar:SortInterface/target/SortInterface-1.0.0-SNAPSHOT.jar:quick/target/quick Note that this is one line of command that print breaks into several lines. Now, if we try to access Qsort directly inserting the following line Qsort<String> qsort = new Qsort<> (String::compareTo,new ArraySwapper<>(lineArray)); into the main method, Maven will complain because the module system hides it from our Main class: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.5.1:compile (default-compile) on proj [ERROR] .../Main/src/main/java/packt/java9/by/example/ch03/main/Main.java:[4,41] package packt.java9.by.example.ch03. [ERROR] .../Main/src/main/java/packt/java9/by/example/ch03/main/Main.java:[25,9] cannot find symbol The module system also supports the java.util.ServiceLoader based class-loading mechanism, which we will not discuss in this book. This is an old technology that is rarely used in an enterprise environment when Spring, Guice, or some other dependency injection framework is used. If you see a module-info.java file that contains the uses and provides keywords, then first consult with the Java documentation about the ServiceLoader class at http://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html, and then the Java 9 language documentation on module support (http://openjdk.java.net/projects/jigsaw/quick-start). Summary In this chapter, we developed a general sorting algorithm implementing quick sort. We modified our project to be a multi-module Maven project and also to use Java module definitions. We were using JUnit to develop unit tests, and we developed the code using TDD. We converted the code from old style Java to new using generics, and we used exception handling. These are the basic tools that are needed for the coming chapters, where we will develop a guessing game. First we will develop a simpler version and in the subsequent chapter we will develop a version that uses parallel computing, and multiple proccessors. Mastermind - Creating a Game In this chapter, we will start to develop a simple game. The game is the Mastermind game for two players. Player one selects four differently colored pins out of six possible colors and arranges them on a board in a row hidden from the other player. The other player tries to guess the colors of the pins and its positions. After each try, player one tells the number of matching colors and the pins matching both color and position. The program will act as both player one and player two. Our code will play alone. However, what remains for us to play with is the most important: the code. This example is complex enough to deepen the OO principles and how we design classes and model the real world. We have already used classes provided in the Java runtime. This time, we will use collections and discuss this important area. These classes and interfaces are widely used and available in the JDK and as important for a professional Java developer as the language itself. The build tool this time is Gradle. In this chapter we will cover: Java collections Dependency injection How to comment our code and to create JavaDoc documentation How to create integration tests The Game Mastermind (https://en.wikipedia.org/wiki/Mastermind_(board_game)) is an old game. The plastic version that was ubiquitous in every house with children was invented in 1970. I got a board around 1980 as a Christmas gift and solving the game puzzle in BASIC language was one of the first programs that I created around 1984. The game board contains holes in several rows in four columns. There are plastic pins of six different colors that can be inserted into the holes. Each pin has one color. They are usually red, green, blue, yellow, black, and white. There is a special row that is hidden from one of the players (the guesser). To play the game, one of the players (hider) has to select four pins from a set of pins. The selected pins should have different colors. The pins are placed in the hidden row one by one, each into a position. The guesser tries to find out what colors are in which position guessing. Each guess takes place selecting four pins and placing them in a row. The hider tells the guesser how many pins are in correct position and how many have a color that is on the table, but are not in the position where that color is hidden. A sample play may go like this: The hider hides four pins with color blue, yellow, white, and black. Guesser guesses yellow, blue, green, and red. The hider tells the guesser that there are two colors matching, but none of them is in the position in the hidden row. The hider says this because yellow and blue are in the hidden row but not in the positions as the guesser guessed. They are actually swapped, but this information the hider keeps a secret. All she says is that there are two colors matching, none in the correct position. The next guess is ... The game finishes when the guesser finds the correct colors in the correct order. The same game, as on the figure, can also be described with textual notation, B for blue, Y for yellow, G for green, W for white, R for red, and b for black (lucky we have upper and lower case letters on the computer). RGBY 0/0 GRWb 0/2 YBbW BYGR RGYB RGBY 0/2 0/4 2/2 4/0 Guess what! This is the actual output of the program that we develop in this chapter. The model of the game When we develop a piece of code with an object-oriented mindset, we try to model the real world and map real-world objects to objects in the program. You certainly have heard of object orientation explained with the very typical examples of geometric objects, or the car and the motor thing to explain composition. Personally, I believe that these examples are too simple to get a good understanding. They may be good for starters, but we are already in the fourth chapter of the book. The Mastermind game is much better. It is a bit more complex than just rectangles and triangles, but not as complex as a telecom billing application or an atomic power plant control. What are the real-world objects that we have in that game? We have a table and we have pins of different colors. There are two Java classes that we certainly will need. What is in a table? There are rows each having four positions. Perhaps we will need a class for a row. A table will have rows. We will also need something that hides the secret. This also may be a row and each row may also hold the information about how many positions and how many colors are matching. In case of the secret row, this information is obvious: 4 and 0. What is a pin? Each pin has a color and generally, that is it. There are no other features of a pin, except that it can be inserted into a hole on the table, but this is a real life feature we will not model. Essentially, a pin is a color and nothing else. This way, we can eliminate the pin class from our model early on, even before we created it in Java. Instead, we have colors. What is a color? This is something that may be hard to immerse into the first time. We all know well what a color is. It is a mixture of different frequency of lights, as our eyes perceive it. We can have paints and prints in different colors, and so on. There are very many things that we do not model in this program. It is really hard to tell what we model about color in our code because these features are so obvious that we take it for granted in real life; we can tell about two colors that they are different. This is the only feature we need. To do this, the simplest class of Java can be used: package packt.java9.by.example.mastermind; public class Color {} If you have two variables of the type Color, you can tell if they are the same or not. You can use object identity comparing a and b using the expression a == b or you can use the equals method inherited from the Object class, a.equals(b). It is tempting to encode the colors with letters, or use String constants to denote them. It may be easier first, but there are serious drawbacks later. When the code becomes complex, it leads to bugs; it will be easy to pass something also encoded as String instead of a color and only unit tests may save the day. Better, the compiler already complains in the IDE when you type the wrong argument. When we play the game, the pins are in small boxes. We pull pins out of the boxes. How do we get the colors in the program? We need something from where we can fetch colors or looking at the other way something that can give us colors. We will call it ColorManager. ColorManager knows how many different colors we have and any time we need a color, we can ask for it. Again, there is a temptation to design the ColorManager that it can serve a color by its serial number. If we have four colors, we could ask for color number 0, 1, 2, or 3. But then again, it would just implicitly encode the colors as integer numbers, which we agreed we will not. We should find the minimum feature that we will need to model the game. To describe the structure of the classes, professional developers usually use UML class diagrams. UML is a diagram notation that is standardized and is almost exclusively used to visualize software architecture. There are many diagram types in UML to describe the static structure and the dynamic behavior of a program. This time, we will look at a very simplified class diagram. We have no room to get into the details of UML class diagrams. Rectangles denote the classes, normal arrows denote the relations when a class has field of the other class type, and triangle headed arrow means that a class extends another. The arrow points to the direction of the class being extended. A Game contains a secret Row and a Table. The Table has a ColorManager and a List<> of Row. The ColorManager has a first color and has a Map<> of Color. We have not discussed why that is the design, we will get there and the diagram helps us walking that road. A Row is essentially an array of Color. The one who plays the game has one function: it has to guess many times until it finds the hidden secret. To get to the model of the ColorManager, we will have to design the algorithm of the Guesser. When the player makes the first guess, any combination of colors is just as good as any other. Later, the guesses should consider the responses that were given for previous guesses. It is a reasonable approach to try only color variations that can be the actual secret. The player selects a variation and looks at all previous guesses assuming that the selected variation is the secret. If the responses to the rows he has already made are the same for this variation as for the unknown secret in the game, then it is reasonable to try this variation. If there is any difference in the responses, then this variation is certainly not the variation that was hidden. To follow this approach, the guesser has to generate all possible color variations one after the other and compare it against the table. The guesser code will not create and store all the possible variations ahead, but it has to know where it was and has to be able to calculate the next variation that comes. This assumes an order of the variations. For a short while, let's forget that no color may appear twice in a variation. A simple ordering can be made the same way as we sort decimal numbers. If we have a three-digit number, then the first one is 000, the next one is 001, and so on until 009, always fetching the next digit for the last position. After that, 010 comes. We increased a digit next to the last one and we set the last one to 0 again. Now, we have 011, 012, and so on. You know, how we count numbers. Now, replace the digits with colors and we have only six and not ten. Or, we have as many as we want when we instantiate a ColorManager object. This leads to the functionality of the ColorManager. It has to do the following two things: Give the first color to the caller Give the next color that follows a given color (we will name the method nextColor) The latter functionality should also signal some way when there is no next color. This will be implemented using another method, named thereIsNextColor. It is a convention to start the method names that return a Boolean value with is. That would lead to the name following this convention isThereNextColor, or isNextColor. Either of these names explains the functionality of the method. If I ask the question isThereNextColor, the method will answer me true or false. But, this is not how we will use the method. We will talk in simple sentences. We will use short sentences. We will avoid unnecessary, gibberish expressions. We will also program that way. Most probably, the caller will use this method in an if statement. They will write the following: If( thereIsNextColor(currentColor)){...} and not if( isThereNextColor(currentColor)){...} I think the first version is more readable and readability comes first. Last, but not least, nobody will blame you if you follow the old convention, and in case that is the company standard, you have to anyway. To do these, the ColorManager also has to create the color objects and should store them in a structure that helps the operations being performed. package packt.java9.by.example.mastermind; import java.util.HashMap; import java.util.Map; public class ColorManager { final protected int nrColors; final protected Map<Color, Color> successor = new HashMap<>(); final private Color first; public ColorManager(int nrColors) { this.nrColors = nrColors; first = new Color(); Color previousColor = first; for (int i = 1; i < nrColors; i++) { final Color thisColor = new Color(); successor.put(previousColor, thisColor); previousColor = thisColor; } successor.put(previousColor, Color.none); } public Color firstColor() { return first; } boolean thereIsNextColor(Color color) { return successor.get(color) != Color.none; } public Color nextColor(Color color) { return successor.get(color); } } The structure we use is a Map. Map is an interface defined in the Java runtime and is available since the very early releases of Java. A Map has keys and value, and for any key, you can easily retrieve the value assigned to the key. You can see on the line, where the variable successor is defined that we define the type of the variable as an interface, but the value is an instance of a class. Obviously, the value cannot be an instance of an interface because such beasts do not exist. But, why do we define the variable to be an interface? The reason is abstraction and coding practice. If we need to change the implementation we use for some reason, the variable type still may remain the same and there is no need to change the code elsewhere. It is also a good practice to declare the variable to be an interface so that we will not have the temptation to use some special API of the implementation that is not available in the interface just by convenience. When it is really needed, we can change the type of the variable and use the special API. After all, there is a reason that API is there, but the mere temptation to use some special thing just because it is there is hindered. This helps to write simpler and cleaner program. is only one of the interfaces defined in the Java runtime belonging to the Java collections. There are many other interfaces and classes. Although, the JDK and all the classes are a vast amount and almost nobody knows all the classes that are there, collections is a special area that a professional developer should be knowledgeable about. Before getting into details on why HashMap is used in this code, we will have an overview of the collection classes and interfaces. This will help us also understand the other collections used in this program. Map Java collections Collections are interfaces and classes that help us store more than one object. We have already seen arrays that can do that, and also ArrayList in the previous chapters, but we did not discuss in detail what other possibilities there are in the JDK. Here, we will go into more detail, but leave the streams and the functional methods for later chapters, and we will also refrain to go into details that is rather the task of a reference book. Using implementation of the collection classes and interfaces reduces the programming effort. First of all, you do not need to program something that is already there. Secondly, these classes are highly optimized, both in implementation and in their features. They have very well designed API as well as the code is fast and uses small memory footprint. Sorry to say that their code was written long time ago and many times it is not a good style, hard to read, and understand. When you use a collection from the JDK, it is more likely that you can interoperate with some library. If you cook your own version of linked lists, it is not likely that you will find a readymade solution that will sort your list. If you use the LinkedList class in the JDK's standard class library, you will get a readymade solution from the Collections class, right from the JDK. It is also worth mentioning that the Java language itself supports these classes, for example, you can easily iterate through the elements of a Collection with a shortened special syntax. The collections in JDK contain interfaces that define the behavior of the different collection types, implementation classes, and algorithms that perform certain actions such as sorting. Many times, these algorithms work on different implementation versions, getting the same result, but optimized for the implementation specific class. You can use the API given by the interface, and if you change the implementation in your code, you will get an optimized version fitting the implementation. The collection interfaces can be categorized in two bags. One bag contains the interfaces that extend the Collection interface, and the other one contains Map, and a SortedMap extending Map. This way, Map is not really a collection, as it does not simply contain other objects but also pair values to keys. Interface collection Collection is the top of the interface hierarchy. This interface defines the methods that all implementations should provide, no matter if they implement the Set, SortedSet, List, Queue, or Deque interface directly. As Collection simply says that an object that implements the Collection interface is only an object that collects other objects together, the methods it defines are like adding a new object to the collection, clearing all elements from there, checking that an object is already a member of the collection, and iterating through the elements. For an up-to-date definition of the interface, consult the Java pi documentation (http://down load.java.net/java/jdk9/docs/api/overview-summary.html). You can consult the online API any time, and it is recommended to do so. The Java language itself directly supports the interface. You can iterate through the elements of the Collection with the enhanced for loop syntax, the same way as you can iterate over the elements of an array where the collection should be an expression that results an object that implements the Collection interface: for( E element : collection ){...} In the preceding code, E is either Object or the generic type of the elements of the Collection. The interface Collection is not directly implemented in the JDK. Classes implement one of the sub interfaces of Collection. Set The Set is a special collection that cannot contain duplicate elements. When you want to add an object into a set that already has an object that is the same or equal to the actual one, then the add method will not add the actual object. The add method will return false indicating the failure. You can use Set in your program when you need a collection of unique elements where you simply want to check that an element is a member of a set or not, whether an object belongs to a certain group or not. As we will return to our program code, we will see that the UniqueGuesser class has to implement an algorithm that checks that a color in a guess is present only once. This algorithm is the ideal candidate for a Set to be used: private boolean isNotUniqueWithSet(Color[] guess) { final Set<Color> alreadyPresent = new HashSet<>(); for (Color color : guess) { if (alreadyPresent.contains(color)) { return true; } alreadyPresent.add(color); } return false; } The code creates a set, which is empty when the method starts. After that, it checks for each color (notice the enhanced for loop over the array elements) if it was already present before. To do that, the code checks if the color is already in the set. If it is there, the guess is not unique as we have found a color that is present at least twice. If the color was not in the set, then the guess can still be unique in colors. To be able to detect that later, the code puts the color into the set. The actual implementation of Set that we will use is HashSet. In the JDK, there are many classes implementing the Set interface. The most widely used is HashSet, and it is also worth mentioning EnumSet, LinkedHashSet, and TreeSet. The last one also implements the SortedSet interface, so we will detail it there. To understand what HashSet (and later HashMap) are and how they work, we will have to discuss what hashes are. They play very important and central role in many applications. They do their job under the hood in the JDK but there are some very important constraints that programmers have to follow or else really weird and extremely hard to find bugs will make their life miserable. I dare to say that violation of the hash contract in HashSet and HashMap are the cause of the second most difficult to find bugs next to multithread issues. Thus, before going on with the different collection implementations, we will visit this topic. We are already one level deep from our example in this detour discussing collections and now we will go one level deeper. I promise this is the last in-depth level of detours. Hash functions A hash is a mathematical function that assigns a number to an element. Say you work at a university administration and you have to tell if Wilkinson is a student at your class. You can store the names on small papers in envelopes one for each starting letter. Instead of searching through the 10 thousand students, you can look at the papers in the envelope titled W. This very simple hash function assigns the first letter of the name to the name (or the ordinal number of the letter, as we said that a hash function results a number). This is not really a good hash function because it puts only a few elements, if any, into the envelope denoted X and many to A for example. A good hash function results each possible ordinal number with similar probability. In hash tables, we usually have more buckets (envelopes in the previous example) than the number of elements to be stored. Therefore, when an element is searched for, it is likely that there is only one element there. At least that is what we would like to have. If there are multiple elements in a single bucket, it is called collision. A good hash function has as little collisions as possible. For backward compatibility, there is a Hashtable class in the JDK. This was one of the first hash table implementations in Java right in the very first version, and as Java is backward compatible, it was not thrown away. The Map interface was introduced in version 1.2 only. Hashtable has many drawbacks and its use is not recommended. (Even the name is violating the Java naming conventions.) We do not discuss this class in this book. Whenever we talk about hash tables, it is referring to the actual array that is inside the implementation of HashSet, HashMap, or any other collection that uses some hash indexed table. Hash tables are arrays that use the result of the hash function to index the array. Usually, linked lists manage collisions. Hash table implementations also implement a strategy to resize the array when the number of elements to be stored becomes too high and the likelihood of collisions increase. This operation may take considerable time and, during this, the individual elements are moved between the buckets. During this operation, the hash table cannot reliably be used and this may be some source of issues in a multithread environment. In single thread code, you do not meet this problem. When you call the add method, the hash table (set or map) decides that the table has to be resized. The add method calls the resizing method and does not return until it is finished. Single thread code has no possibility to use the hash table during this period: the one and single thread is executing the resizing itself. In a multithread environment, however... and HashMap use the hash function provided by the Object that is stored in the collection. The Object class implements the hashCode and equals methods. You can override them and if you do, you should override both in a consistent manner. First, we will see what they are and then how to override them consistently. HashSet Method equals The documentation of set says "sets contain no pair of elements e1 and e2 such that e1.equals(e2)". The equals method returns true if the e1 and e2 are in some way equal. It may be different from two objects being identical. There can be two distinct objects that are equal. For example, we could have a color implementation that has the name of the colors as an attribute and two color objects may return true calling the equals method on one of them and passing the argument as the other when the two strings are equal. The default implementation of the equals method is in the code of the Object class and this returns true if and only if e1 and e2 are exactly the same and single object. It seems to be obvious, but my experience shows that it cannot be stressed enough that the implementation of equals in an object has to be as follows: Reflexive: This means that an object that always equals itself Symmetric (commutative): This means if e1.equals(e2) is true, then e2.equals(e1) should also be true Transitive: This means if e1.equals(e2) and e2.equals(e3), then e1.equals(e3) Consistent: This means that the return value should not change if the objects were not changed between the invocations Method hashCode The hashCode method returns an int. The documentation says that any class redefining this method should provide the following implementation: Consistently return the same value if the object was not modified Result the same int value for two objects that are equal (the equals method returns true) The documentation also mentions that this is not a requirement to result different int values for objects that are not equal, but it is desirable to support the performance of the hash implementing collections. If you violate any of these rules in the implementation of equals and hashCode, then the JDK classes using them will fail. As you can be sure that HashSet, HashMap, and similar classes were fully debugged, seeing that you added an object to a set and then the set reporting that it is not there will be a bewildering experience. However, only until you find out that the two objects being equal and stored in the set have different hashCode values, HashSet and HashMap will look for the object only in the bucket that is indexed by the hashCode value. It is also a common mistake to store an object in a HashSet or HashMap and then modify it. The object is in the collection but you cannot find it because the hashCode returns a different value. Objects stored in a collection should not be modified unless you know what you are doing. Many times, objects contain fields that are not interesting from the equality point of view. The hashCode and equals methods should be idempotent to those fields and you can alter those fields even after storing the object in a HashSet or in HashMap. As an example, you may administer triangles in objects maintaining the coordinates of the vertices and the color of the triangle. However, you do not care about the color for equality, only that the two triangles are at the exact same location in the space. In that case, the equals and hashCode method should not take the field color into account. This way, we can paint our triangles; they will still be found in HashSet or HashMap no matter what the color field is. Implementing equals and hashCode Implementing these methods is fairly simple. As this is a very common task, the IDEs support the generation of these methods. These methods are tied together so much that the menu items in the IDEs are not separate; they offer you to generate these methods at once. Asking the IDE to generate the equals method will result in something like the following code: @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MyObjectJava7 that = (MyObjectJava7) o; return Objects.equals(field1, that.field1) && Objects.equals(field2, that.field2) && Objects.equals(field3, that.field3); } For this sample, we have three Object fields named field1, field2, and field3. The code with any other types and fields will look very similar. First, the method checks for object identity. One Object always equals itself. If the reference passed as argument is null and not an object, or they are of different class, then this generated method will return false. In other cases, the static method of the class Objects (note the plural) will be used to compare each of the fields. The utility class Objects was introduced in Java 7, hence the name of the sample class. The static methods, equals and hash, support the override of the Object equals and hashCode methods. The hashCode creation before Java 7 was fairly complex and required the implementation of modulo arithmetic with some magic numbers that is hard to explain just looking at the code without knowing the mathematics behind it. This complexity is now hidden behind the following Objects.hash method. @Override public int hashCode() { return Objects.hash(field1, field2, field3); } The generated method simply calls the Objects.hash method passing the important fields as arguments. HashSet Now, we know essentially a lot of things about hashes so we can bravely discuss the HashSet class. HashSet is an implementation of the Set interface that internally uses hash table. Generally, that is it. You store objects there and you can see if an object is already there or not. When there is a need for a Set implementation, almost always HashSet is the choice. Almost... EnumSet can contain elements from a certain enumeration. Recall that enumerations are classes that have fixed a number of instances declared inside the enum itself. As this limits the number of the different object instances, and this number is known during compilation time, the implementation of the EnumSet code is fairly optimized. Internally, EnumSet is implemented as a bit field and is a good choice where bit field manipulations can be used. EnumSet LinkedHashSet is a HashSet that also maintains a doubly linked list of the elements it holds. When we iterate though a HashSet, there is no guaranteed order of the element. When the HashSet is modified, the new elements are inserted into one of the buckets and, possibly, the hash table gets resized. This means that the elements get rearranged and get into totally different buckets. Iteration over the elements in HashSet just takes the buckets and the elements in it in some order that is arbitrary from the caller point of view. LinkedHashSet , however, iterates over the elements using the linked list it maintains and the iteration is guaranteed to happen in the order the elements were inserted. LinkedHashSet SortedSet The SortedSet is an interface that guarantees that the classes implementing it will iterate over the set in a sorted order. The order may be the natural ordering of the objects if the objects implement the Comparable interface or a Comparator object may drive it. This object should be available when the instance of the class implementing the SortedSet is created; in other words, it has to be a constructor parameter. NavigableSet extends the SortedSet interface with methods that let you do proximity search in the set. This essentially lets you search for an element that is in the search and is less than the searched object, less or equal to the searched element, greater or equal, or greater than the searched object. NavigableSet TreeSet is an implementation of NavigableSet and, this way this is also a SortedSet and, as a matter of fact, is also a Set. As a SortableSet documentation implies there are two types of the constructors, each having multiple versions though. One requires some Comparator, the other one relies on the natural ordering of the elements. TreeSet List is an interface that requires implementing class to keep track of the order of the elements. There are also methods that access an element by index and iteration defined by the Collection interface that guarantees the order of the elements. The interface also defines the listIterator method that returns an Iterator also implementing the ListIterator interface. This interface provides methods that let the caller insert elements to the list while iterating through it and also going back and forth in the iteration. It is also possible to search for a certain element in the List but most implementations of the interface provide poor performance while the searching is simply going through all elements until the element searched for is found. There are many classes implementing this interface in the JDK. Here, we will mention two. List LinkedList This is a doubly-linked list implementation of the List interface that has a reference to the previous, and also to the next element in the list for each element. The class also implements the Deque interface. It is fairly cheap to insert or delete an element from the list because it needs only the adjustment of few references. On the other hand, the access to an element by index will need iteration from the start of the list, or from the end of the list, whichever is closer to the specified indexed element. ArrayList This class is an implementation of the List interface that keeps the references to the elements in an array. That way, this is fairly fast to access an element by index. On the other hand, inserting an element to ArrayList can be costly. It needs moving all references above the inserted element one index higher, and it may also require resizing the backing array in case there is no room in the original one to store the new element. Essentially, this means allocating a new array and copying all references to it. The reallocation of the array may be optimized if we know how large the array will grow and call the ensureCapacity method. This will resize the array to the size provided as argument, even if the currently used slots are less numbered. My experience is that novice programmers use ArrayList when they need a list without considering the algorithmic performance of the different implementations. I do not actually know why there is this popularity of ArrayList. The actual implementation used in a program should be based on proper decision and not habit. Queue Queue is a collection that usually stores element for later use. You can put elements into a queue and you can pull them out. An implementation may specify the given order, that may be first in first out (FIFO) or last in first out (LIFO) or some priority based ordering. On a queue, you can invoke the add method to add an element, remove to remove the head element, and the element method to access the head element without removing it from the queue. The add method will throw an exception when there is a capacity problem and the element cannot be added to the queue. When the queue is empty, and there is no head element, the element and remove methods throw exception. As exceptions can only be used in exceptional cases, and the calling program may handle these situations in the normal course of the code, thus all these methods have a version that just return some special value signaling the situation. Instead of add, a caller may call offer to offer an element for storage. If the queue cannot store the element, it will return false. Similarly, peek will try to get access to the head element or return null if there is none, and poll will remove and return the head element or just return null if there is none. Note that these methods returning null just make the situation ambiguous when the implementation, such as LinkedList, allows null elements. Never store a null element in a queue. Deque is an interface which is a double-ended queue. It extends the Queue interface with the methods that allow access to both ends of the queue to add, look at, and remove elements from both ends. Deque For the Queue interface we needed six methods. Dequeue having two manageable ends needs 12 methods. Instead of add we have addFirst and addLast. Similarly we can offerFirst, offerLast as well as peekFirst, peekLast and pollFirst, pollLast. For some reason the methods that implement the functionality of the element method on Queue are named getFirst and getLast. Since this interface extends the Queue interface the methods defined there can also be used to access the head of the queue. In addition to these this interface also defines the methods removeFirstOccurrence and removeLastOccurrence that can be used to remove a specific element inside the queue. We cannot specify the index of the element to remove and we also cannot access an element based on index. The removeFirst/ LastOccurrence methods' argument is the object that is to be removed. If we need this functionality we can use Deque even if we add and remove elements from the same end of the queue. Why are there these methods in Deque and not in Queue? These methods have nothing to do with double headedness of Deque. The reason is that methods cannot be added to interfaces after they were released. If we add a method to an interface we break the backward compatibility because all classes that implement that interface have to implement the new method. Java 8 introduced default methods that eased this constraint, but the Queue interface was defined in Java 1.5 and the Deque interface was defined in Java 1.6. There was no way at that time to add the new methods to the already existing interfaces. Map A Map pairs keys and values. If we want to approach a Map from the Collection point of view then a Map is a set of key/value pairs. You can put key value pairs into a Map and you can get a value based on a key. Keys are unique the same way as elements in a Set. If you look at the source code of the different implementations of the Set interface, you may see that some of them are implemented as a wrapper around a Map implementation where the values are simply discarded. Using Maps is easy and alluring. Many languages, such as Python, Go, JavaScript, Perl, and so on, support this data structure on the language level. However, using a Map when an array would be sufficient is a bad practice that I have seen many times, especially in scripting languages. Java is not prone to that novice programmer error but you may still find yourself in a situation when you want to use a Map, and still there is a better solution. It is a general rule that the simplest data structure should be used that is sufficient for the implementation of the algorithm. HashMap is a hash table based implementation of the Map interface. As the map is based on a hash table, the basic put and get methods are performed in constant time. Additionally, as Map is very important, and because the most frequently used implementation in the JDK is HashMap, the implementation is fairly configurable. You can instantiate HashMap using the default constructor without argument, but there is also a constructor that defines the initial capacity and the load factor. HashMap IdentityHashMap is a special Map that implements the Map interface literally, but as a matter of fact, it violates the contract the Map interface documentation defines. It does it with good reason. The implementation uses a hash table just as HashMap, but to decide the equality of the key found in the bucket comparing with the key element provided as argument to the get method it uses Object reference (== operator) and not the method equals, which is required by documentation of Map interface. IdentityHashMap The use of this implementation is reasonable when we want to distinguish different Object instances as keys that otherwise equal to each other. Using this implementation for performance reasons is almost certainly a wrong decision. Also, note that there is no IdentityHashSet implementation in the JDK. Probably such collection is so rarely used that its existence in the JDK would cause more harm than good alluring novice programmers to misuse. Dependency injection In the previous chapter we briefly already discussed dependency injection (DI). Now we will dig into it a bit more detail. Objects usually do not work on their own. Most of the time the implementation depends on the services of other classes. When we want to write something to the console we use the System class. When we manage the table of guesses we need Color objects and ColorManager. In case of writing to the console we may not realize the dependency because the class being part of the JDK class library is available all the time and all we need to do is to write System.out.println. In this case this dependency is wired into the code. We cannot send the output somewhere else unless we change the code. This is not too flexible and in many cases we need a solution that can work with different output, different color manager or different whatever service our code depends on. The first step to do that is to have a field that has a reference of the object that gives our class the service. In case of output the type of the field can be of type OutputStream. The next, more interesting step is how this field gets value. One of the solution is to use DI. In this approach some external code prepares the dependencies and injects them into the object. When the first call to a method of the class is issued all the dependencies are already filled and ready to be used. In this structure, we have four different players: The client object is the one that gets the injected service objects during the process Service object or objects are injected into the client object Injector is the code that performs the injection Interfaces define the service that the client needs If we move the logic of the creation of the service objects from the client code the code becomes shorter and cleaner. The actual competency of the client class should hardly ever cover the creation of the service objects. For example a Game class contains a Table instance but a game is not responsible to create the Table. It is given to it to work with it, just as in real life that we model. The creation of service objects is sometimes as simple as issuing the new operator. Sometimes service objects also depend on other service objects and that way also act as clients in the process of dependency injection. In this case the creation of the service objects may be a lot of lines. The structure of the dependencies can be expressed in a declarative fashion that describes which service object needs which other service objects and also what implementation of the service interfaces are to be used. Dependency injection injectors work with such declarative descriptions. When there is a need for an object that needs service objects that themselves need again other service objects the injector creates the service instances in the appropriate order using the implementations that are matching the declarative descriptions. The injector discovers all the dependencies transitively and creates a transitive closure graph of the dependencies. The declarative description of the needed dependencies can be XML, or a special language developed especially for the dependency injection or it can even be Java itself using specially designed fluent API (h ttps://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/). XML was first used in DI injectors. Later Groovy based Domain Specific Language (https://martinfowler.com/books/dsl.html) came into picture and Java fluent API approach. We will use only the last one being the most modern and we will use Spring and GuiceDI containers since they are the most well-known injector implementations. Implementing the game Collections without examples are boring. Fortunately, we have our game where we use a few collection classes and also other aspects that we will examine in this chapter. ColorManager We jumped into the pool filled with collection classes from the implementation of the ColorManager class. Let's refresh the part of the class that is interesting for us now—the constructor: final protected int nrColors; final protected Map<Color, Color> successor = new HashMap<>(); final private Color first; public ColorManager(int nrColors) { this.nrColors = nrColors; first = new Color(); Color previousColor = first; for (int i = 1; i < nrColors; i++) { final Color thisColor = new Color(); successor.put(previousColor, thisColor); previousColor = thisColor; } successor.put(previousColor, Color.none); } We will use HashMap to keep the colors in an ordered list. At first, the choice of HashMap seems to be strange. Very true, that during the coding of ColorManager, I also considered a List, which seemed to be a more obvious choice. When we have a List<Color> colors variable, then the nextColor method is something like this: public Color nextColor(Color color) { if (color == Color.none) return null; else return colors.get(colors.indexOf(color) + 1); } The constructor will be much simpler, as shown in the following piece of code: final List<Color> colors = new ArrayList<>(); public ColorManager(int nrColors) { this.nrColors = nrColors; for (int i = 0; i < nrColors; i++) { colors.add(new Color()); } colors.add(Color.none); } public Color firstColor() { return colors.get(0); } Why did I choose the more complex solution and the unobvious data structure? The thing is performance. When the nextColor method is invoked, the list implementation first finds the element checking all the elements in the list and then fetches the next element. The time is proportional to the number of colors. When our number of colors increases, the time will also increase to just get the next color having one. At the same time, if we focus on not the data structure that comes from the verbal expression of the task we want to solve (get the colors in a sorted order) but rather focus on the actual method that we want to implement, nextColor(Color), then we will easily come to the conclusion that a Map is more reasonable. What we need is exactly a Map : having one element we want another related to the one we have. The key and the value is also Color. Getting the next element is constant time using HashMap. This implementation is probably faster than the one based on ArrayList. The problem is that it is only probably faster. When you consider refactoring a code to have better performance, your decision should always be based on measurements. If you implement a code that you only think is faster, practice shows, you will fail. In best case, you will optimize a code to be blazing fast and runs during the application server setup. At the same time, optimized code is usually less readable. Something for something. Optimization should never be done prematurely. Code for readability first. Then, assess the performance, and in case there is problem with the performance, then profile the execution and optimize the code where it hurts the most of the overall performance. Micro-optimizations will not help. Did I do premature optimization selecting the HashMap implementation instead of List? If I actually implemented the code using List and then refactored, then yes. If I was thinking about the List solution and then it came to me that Map solution is better without prior coding, then I did not. By years, such considerations will come easier, as you will also experience. The class color We have already looked at the code for the class code and it was the simplest class in the world. In reality, as it is in the GitHub repository (https://github.com/j9be/chapter04 or https://github.com/PacktPublishing/Java-9-Progra mming-By-Example/tree/master/Chapter04), the code is a bit more complex: package packt.java9.by.example.mastermind; /** * Represents a color in the MasterMind table. */ public class Color { /** * A special object that represents a * value that is not a valid color. */ public static final Color none = new Color(); } We have a special color constant named none that we use to signal a reference that is of type Color but is not a valid Color. In professional development, we used the null value for a long time to signal invalid reference, and because we are backward compatible, we still use it. However, it is recommended to avoid the null reference wherever possible. Tony Hoare (https://en.wikipedia.org/wiki/Tony_Hoare), who invented the null reference in 1965, admitted one time that this was a mistake that cost billions of dollars in the IT industry. The problem with the null value is that it takes the control away from the class, and thus, opens encapsulation. If a method returns null in some situation, the caller is strictly required to check the nullity and act according to that. For example, you cannot call a method on a null reference and you cannot access any field. If the method returns, a special instance of the object these problems are less serious. If the caller forgets to check the special return value and invokes methods on the special instance, the methods invoked still have the possibility to implement some exception or error handling. The class has the control encapsulated and can throw a special exception that may give more information about the error caused by the programmatic mistake by the caller not checking the special value. JavaDoc and code comments There is also another difference between what we presented here earlier and the listing. This is the commenting of the code. Code comments are part of the program, which are ignored, filtered out by the compiler. These comments are solely for those who maintain or use the code. In Java, there are two different comments. The code enclosed between /* and */ are comments. The start and the end of the comment do not need to be on the same line. The other type of comment starts with the // characters and ends at the end of the line. To document the code, the JavaDoc tool can be used. JavaDoc is a special tool that reads the source code and extracts HTML documentation about the classes, methods, fields, and other entities that have a comment starting with the /** characters. The documentation will contain the JavaDoc comments in a formatted way and also the information that is extracted from the program code. The documentation also appears as online help in the IDE when you move the mouse over a method call or class name, if there is any. The JavaDoc comment can contain HTML codes, but it generally should not. If really needed, you can use <p> to start a new paragraph or the <pre> tags to include some preformatted code sample into the documentation, but nothing more gives real benefit. Documentation should be as short as possible and contain as few formatting as possible. There are special tags that appear in the JavaDoc documentation. These are prefilled by the IDEs when you start to type a JavaDoc as /** and then press Enter. These are inside the comment and start with the @ character. There are a predefined set of tags: @author, @version, @param, @return, @exception, @see, @since, @serial, and @deprecated. The most important tags are @param and @return. They are used to describe the method arguments and the return value. Although we are not there yet, let's peek ahead to the guessMatch method from the Guesser class. /** * A guess matches if all rows in the table matches the guess. * * @param guess to match against the rows * @return true if all rows match */ protected boolean guessMatch(Color[] guess) { for (Row row : table.rows) { if (!row.guessMatches(guess)) { return false; } } return true; } The name of the parameter is automatically generated by the IDE. When you create the documentation, write something that is meaningful and not tautology. Many times, novice programmers feel the urge to write JavaDoc, and that something has to be written about the parameters. They create documentations like this: * @param guess is the guess Really? I would never have guessed. If you do not know what to write there to document the parameter, it may happen that you were choosing the name of the parameter excellent. The documentation of our preceding example will look as follows: Focus on what the method, class, and interface does and how it can be used. Do not explain how it works internally. JavaDoc is not the place for the explanation of the algorithm or the coding. It is used to help use the code. However, if somebody happens to explain how a method works, it is not a disaster. Comments can easily be deleted. There is, however, a comment that is worse than nothing: outdated documentation that is not valid anymore. When the contract of the element has changed, but the documentation does not follow the change and is misleading the user who wants to call the method, interface, or class whatever will face serious bugs and will be clueless. From now on, JavaDoc comments will not be listed in print to save trees, and electrons in the eBook version, but they are there in the repository and can be examined. Row Now, we have Colors and even instances if we need having a ColorManager. This is the time to store Colors in Rows. The Row class is a bit longer, but not too complex. package packt.java9.by.example.mastermind; import java.util.Arrays; public class Row { final Color[] positions; private int matchedPositions; private int matchedColors; A Row contains three fields. One is the positions array. Each element of the array is a Color. The matchedPositions is the number of positions that are matched and matchedColors is the number of colors that match a color in the hidden row but is not on the position as in the hidden row. public static final Row none = new Row(Guesser.none); The none is a constant that contains a special Row instance that we will use wherever we would use null. The constructor gets the colors in an array that should be in the row. public Row(Color[] positions) { this.positions = Arrays.copyOf(positions, positions.length); } The constructor makes a copy of the original array. This is an important code that we will examine a bit. Let's reiterate that Java passes arguments by value. It means that when you pass an array to a method, you will pass the value of the variable that holds the array. However, an array in Java is an Object just as well as anything else (except primitives like int). Therefore, what the variable contains is a reference to an object that happens to be an array. If you change the elements of the array, you actually change the elements of the original array. The array reference is copied when the argument passes, but the array itself, and the elements, are not. The java.util.Arrays utility class provides a lot of useful tools. We can easily code the array copying in Java but why to reinvent the wheel? In addition to that, arrays are continuous area of memory that can very effectively be copied from one place to another using low-level machine code. The copyOf method that we invoke calls the method System.arraycopy which is a native method and as such executes native code. Note that there is no guarantee that Arrays.copyOf invokes the native implementations and that this will be extremely fast in case of large arrays. The very version I was testing and debugging was doing it that way, and we can assume that a good JDK does something similar, effective and fast. After we copied the array, it is not a problem if the caller modifies the array that was passed to the constructor. The class will have a reference to a copy that will contain the same elements. However, note that if the caller changes any of the objects that are stored in the array (not the reference in the array, but the object itself that is referenced by an array element), then the same object is modified. Arrays.copyOf does not copy the objects that are referenced by the array, only the array elements. The row is created along with the colors and thus, we used a final field for the Color array. The matches, however, cannot be known when a Row is created. One of the players creates the Row and after that, the other player will tell the two int values. We do not create two setters for the two values, however, because they are always defined at the same time in the game together. public void setMatch(int matchedPositions, int matchedColors) { if (matchedColors + matchedPositions > positions.length) { throw new IllegalArgumentException( "Number of matches can not be more that the position."); } this.matchedColors = matchedColors; this.matchedPositions = matchedPositions; } The setMatch method does not only set the values, but also checks that the values are consistent. The sum of the two values cannot be more than the number of the columns. This check ensures that the caller, who uses the API of the Row class, does not use it inconsistently. If this API is used only from inside our code, this assertion should not be part of the code. A good coding style, in that case, will ensure that the method is never invoked inconsistently using unit tests. When we create API to use out of our control, we should check that the use is consistent. Failing to do so, our code may behave just weird when used inconsistently. When the caller sets matches to values that do not match any possible guess, the game may never finish and the caller may have a hard time figuring out what is going on. This figuring out probably will need the debug execution of our code. If we throw an exception in this case, the program stops where the bug is. There is no need to debug the library. public boolean guessMatches(Color[] guess) { return nrMatchingColors(guess) == matchedColors && nrMatchingPositions(guess) == matchedPositions; } The next method decides if a guess, given as an argument, matches the actual row. This method checks that the answers to the guess in the row can be valid if the current guess was in the hidden row. The implementation is fairly short and simple. A guess matches a row if the number of the colors matching and the number of positions matching are the same as the number given in the row. Do not be shy to write short methods. Do not think that a one-line method that essentially contains one statement is useless. Wherever we use this method, we could also write the expression, which is right after the return statement, but we do not for two reasons. The first and most important reason is that the algorithm, which decides that a row matches a guess belongs to the implementation of the class Row. If ever the implementation changes, the only location where the code is to be changed is here. The other reason is also important, and that is readability. In our codebase, we call this method from abstract class Guesser. It contains an if statement with the following expression: if (!row.guessMatches(guess)) { Would it be more readable in the following way: if( !(nrMatchingColors(guess) == matchedColors && nrMatchingPositions(guess) == matchedPositions)) { I am certain that the majority of the programmers understand the intention of the first version easier. I would even recommend implementing the doesNotMatchGuess method to improve the readability of the code even more. public int nrMatchingColors(Color[] guess) { int count = 0; for (int i = 0; i < guess.length; i++) { for (int j = 0; j < positions.length; j++) { if (i != j && guess[i] == positions[j]) { count++; } } } return count; } The number of matching colors is that which appears both in the row and the guess, but not in the same position. The definition, and how we calculate it, is fairly simple and unambiguous in case no color can appear twice in the hidden row. In case a color may appear multiple times in the hidden row, this implementation will count all occurrences of that color in the guess as many times as it appears in the hidden row. If we, for example, have a hidden RRGB row and the guess is bYRR, the calculation will say 4. It is a matter of agreement between the players how they count in this case. The important aspect is that they use the same algorithm, which should be true in our case, because we will ask the program to play both players. As we will program the code ourselves, we can trust that it will not cheat. public int nrMatchingPositions(Color[] guess) { int count = 0; for (int i = 0; i < guess.length; i++) { if (guess[i] == positions[i]) { count++; } } return count; } Counting the colors that are OK, and also on the position where they are supposed to be, is even simpler. public int nrOfColumns() { return positions.length; } This method tells the number of columns in the Row. This method is needed in the Game class that controls the flow of a whole game. As this class is in the same package as Row, it can access the field positions. I created the code to get the number of columns as row.positions.length. But then, I was reading the code next day and told myself: This is ugly and unreadable! What I am interested in here is not some mysterious positions' length; it is the number of columns. And the number of columns is the responsibility of the Row class and not the business of any other class. If I start to store the positions in a List, which does not have length (it has method size), it is the sole responsibility of Row and should not affect any other code. So, I created the nrOfColumns method to improve the code. The rest of the class contains some more very simple methods that are needed only to display the game and not for the algorithm to play: public int nrColumns() { return positions.length; } public Color position(int i) { return positions[i]; } public int matchedPositions() { return matchedPositions; } public int matchedColors() { return matchedColors; } } If you are a purist, you can encapsulate these methods into an inner class named Output or Print and call them through a final instance of it created as a field in the Row class. It is also possible to change the visibility of these fields from private to protected and implement these methods in a PrintableRow that can be instantiated from an already existing Row and implement these methods. The first version of PrintableRow will look like this: public class PrintableRow extends Row { public PrintableRow(Row row) { super(row.positions); super.setMatch(row.matchedPositions,row.matchedColors); } // the methods are deleted from the print ... } The methods are exactly the same as in the preceding print; they are cut and pasted, or rather moved, using the IDE refactoring support from one class to the other. When you write a code, please never use copy and paste. However you can use cut and paste to move code fragments around. The danger is in the copy paste use. Many developers claim that their use of actual copy and paste is not copy paste programming. Their reasoning is that they change the pasted code so much that it has practically nothing to do with the original code. Really? In that case why did you need the copied code when you started the modification of it? Why not start from scratch? That is because if you use the IDE's copy and paste functionality then, no matter what, you do copy paste programming. Class PrintableRow is pretty neat and separates the output concern from the core functionality. When you need an instance, it is not a problem that you have a Row instance already in hand. The constructor will essentially clone the original class and return a printable version. What bothers me is the implementation of the cloning. The code in the constructor calls the super constructor and then a method and all these work with the original functionality of the Row class. They have nothing to do with the printability that PrintableRow implements. This functionality actually belongs to the Row class. We should create a protected constructor that does the cloning: protected Row(Row cloneFrom) { this(cloneFrom.positions); setMatch(cloneFrom.matchedPositions, cloneFrom.matchedColors); } The constructor of PrintableRow should simply call super(row) and that is it. Code is never finished and never perfect. In a professional environment, programmers many times tend to finish polishing the code when it is good enough. There is no code that cannot be made better, but there is a deadline. The software has to be passed on to the testers and users and has to be used to help economy. After all, that is the final goal of a professional developer: have a code that supports the business. A code that never runs is worth nothing. I do not want you to think that the examples that I provided here were created perfect upfront. The reason for that is (did you read carefully?) because they are not perfect. As I said, code is never perfect. When I first created Row, it contained the printing methods in an inner class. I did not like it. The code was smelly. So, I decided to move the functionality to the Row class. However, I still did not like the solution. Then, I went to bed, slept, worked, and returned to it a few days later. What I could not create the day before now seemed obvious—these methods have to be moved to a subclass. Now comes another dilemma. Should I present this final solution or should I have here the different versions? In some cases, I will just present the final version. In other cases, like this, there are things to learn from the development step. In these cases, I present not only the code, but part of its evolution on how it was created. If you want to see those that I did not dare publishing, look at the Git history. I admit, sometimes, I create code that even makes me facepalm a day later. Table Table is a simple class that has only one very simple functionality. public class Table { final ColorManager manager; final int nrColumns; final List<Row> rows; public Table(int nrColumns, ColorManager manager) { this.nrColumns = nrColumns; this.rows = new LinkedList<>(); this.manager = manager; } public void addRow(Row row) { rows.add(row); } } There is one thing to mention, which is nothing new, but worth repeating. The rows variable is declared as final and it gets the value in the constructor. This is a List<Row> type variable. The fact that it is final means that it will hold the same list object during its lifetime. The length, members, and other features of the list may and will change. We will add new rows to this list. Final object variables reference an object, but it does not guarantee that the object itself is immutable. It is only the variable that does not change. When you do code review and explain to your colleagues what a class does, and you find yourself starting the explanation "this class is very simple" many times, it means the code is good. Well, it may be wrong in other aspects, but the class' granularity seems to be okay. Guesser Guesser and the UniqueGuesser and GeneralGuesser subclasses are the most interesting classes of the program. They actually perform the task that is the core of the game. Given a Table with a hidden row, the guesser has to create newer and newer guesses. To do this, a Guesser needs to get a Table when it is created. This is passed as a constructor argument. The only method it should implement is guess, which returns a new guess based on the table and on its actual state. As we want to implement a guesser that assumes that all colors in the hidden row are different, and also one that does not make this assumption, we will implement three classes. Guesser is an abstract class that implements only the logic that is independent from the assumptions. These methods will be inherited by both actual implementations: UniqueGuesser and GeneralGuesser. Let's go through the actual code of the class: package packt.java9.by.example.mastermind; public abstract class Guesser { protected final Table table; private final ColorManager manager; public Guesser(Table table) { this.table = table; this.lastGuess = new Color[table.nrColumns]; this.manager = table.manager; } The state of the guesser is the last guess it made. Although this is on the last row of the table, it is more of an internal matter of the guesser. The guesser has all the possible guesses, one after the other; lastGuess is the one where it left off last time and it should continue from there when it is invoked again. abstract protected void setFirstGuess(); Setting the first guess very much depends on the assumption of color uniqueness. The first guess should not contain duplicated colors in case the hidden row does not (at least in our implementation), while GeneralGuesser is free to guess any time, even as firstGuess all colors to be the same. protected final Color[] lastGuess; public static final Color[] none = new Color[]{Color.none}; Again, none in this class is just an object that we try to use instead of null, whenever we need to return something that is a reference to a Guess but is not really a guess. protected Color[] nextGuess() { if (lastGuess[0] == null) { setFirstGuess(); return lastGuess; } else { return nextNonFirstGuess(); } } The nextGuess method is an internal method that generates the next guess, which just comes as we order the possible guesses. It does not check anything against the Table; it only generates the next guess almost without thinking. The implementation on how we do the first guess and how we do the consecutive guesses are different. Thus, we will implement these algorithms in different methods and invoke them from here. The nextNonFirstGuess method represents the next guess in the special case when the guess is not the first one: private Color[] nextNonFirstGuess() { int i = 0; boolean guessFound = false; while (i < table.nrColumns && !guessFound) { if (manager.thereIsNextColor(lastGuess[i])) { lastGuess[i] = manager.nextColor(lastGuess[i]); guessFound = true; } else { lastGuess[i] = manager.firstColor(); i++; } } if (guessFound) { return lastGuess; } else { return none; } } Look back a few pages where we detailed how the algorithm works. We made the statement that this way of working is very much like the way we count with decimal numbers. By now, you have enough Java knowledge and programming skill to understand what the method does. It is more interesting to know why it is coded that way. Hint: as always, to be readable. There is the temptation to eliminate the guessFound variable. Would it not be simpler to return from the middle of the method when we find the blessed guesses? If we did, there would be no need to check the guessFound value before returning none value. The code would not get there if we returned from the middle of the loop. Yes, it would be simpler to write. But, we create code to be readable and not writable. Yes, but less code is more readable. Not in this case! Returning from a loop degrades the readability. Not to mention, the return statements are scattered around in the method at different stages of execution. private Color[] nextNonFirstGuess() { int i = 0; while (i < table.nrColumns) { if (manager.thereIsNextColor(lastGuess[i])) { lastGuess[i] = manager.nextColor(lastGuess[i]); return lastGuess; } else { lastGuess[i] = manager.firstColor(); i++; } } return none; } When somebody writes a code optimized in that way, it is similar to a toddler who makes his first steps and then looks proudly at the mother. Okay boy/girl, you are great. Now go on and start walking. When you are the postman, walking will be boring. That will be your profession. So, slide aside the pride and write boring code. Professionals write boring code. Won't it be slow? No! It will not be slow. First of all, it is not slow until the profiler proves that the code does not meet the business requirements. If it does, it is fast enough, no matter how slow it is. Slow is good as long as it is okay for the business. After all, JIT should have some task optimizing the code to run. The next method checks if the guess matches the previous guesses and their results on the Table: private boolean guessMatch(Color[] guess) { for (Row row : table.rows) { if (!row.guessMatches(guess)) { return false; } } return true; } private boolean guessDoesNotMatch(Color[] guess) { return !guessMatch(guess); } As we have the guess matching already implemented in the class Row, all we have to do is invoke that method for each row in the table. If all rows match, then the guess can be good for the table. If any of the former guesses do not match, then this guess goes down the drain. As we check the negated expression of matching, we created an English version of the method. In situations like this, it could be enough to create the guessDoesNotMatch version of the method. However, the logical execution of the code is more readable if the method is not negated. Therefore, it is more error prone to write the guessDoesNotMatch method alone. Instead, we will implement the original, readable version and the aux method to be nothing more than a negation. After all the aux methods, here we are implementing the public method of the Guesser. public Row guess() { Color[] guess = nextGuess(); while (guess != none && guessDoesNotMatch(guess)) { guess = nextGuess(); } if (guess == none) { return Row.none; } else { return new Row(guess); } } } It just takes the nextGuess and again and again until it finds one that matches the hidden row, or there is no more guess. If it finds a proper guess, it encapsulate it to a Row object and return it so that it can later be added to the Table by the Game objects. UniqueGuesser Class UniqueGuesser has to implement setFirstGuess (all concrete classes extending an abstract class should implement the abstract method of the parent) and it can and will override the protected nextGuess method: package packt.java9.by.example.mastermind; import java.util.HashSet; import java.util.Set; public class UniqueGuesser extends Guesser { public UniqueGuesser(Table table) { super(table); } @Override protected void setFirstGuess() { int i = lastGuess.length-1; for (Color color = table.manager.firstColor(); i >= 0; color = table.manager.nextColor(color)) { lastGuess[i--] = color; } } The setFirstGuess method selects the first guess in such a way that any possible color variations that come after the first one create the guesses one after the other if we follow the algorithm. The aux isNotUnique method returns true if the guess contains duplicate colors. It is not interesting to see how many. If all colors are the same, or only one color appears twice, it does not matter. The guess is not unique and does not fit our guesser. This method judges that. private boolean isNotUnique(Color[] guess) { final Set<Color> alreadyPresent = new HashSet<>(); for (Color color : guess) { if (alreadyPresent.contains(color)) { return true; } alreadyPresent.add(color); } return false; } To do this, it uses a Set, and any time a new color is found in the guess array, the color is stored in the set. If the set contains the color when we find it in the array, it means that the color was already used before; the guess is not unique. @Override protected Color[] nextGuess() { Color[] guess = super.nextGuess(); while (isNotUnique(guess)) { guess = super.nextGuess(); } return guess; } The overriding nextGuess method is simple. It asks the super nextGuess implementation to make guesses but throws away those that it does not like. package packt.java9.by.example.mastermind; <br/> <br/>public class GeneralGuesser extends Guesser { <br/> <br/> public GeneralGuesser(Table table) { super(table); } <br/> <br/> @Override <br/> protected void setFirstGuess() { <br/> int i = 0; <br/> for (Color color = table.manager.firstColor(); <br/> i < lastGuess.length; ) { <br/> lastGuess[i++] = color; <br/> } <br/> } <br/> <br/> } Setting the lastGuess it just puts the first color on all columns. Guess could not be simpler. Everything else is inherited from the abstract class Guesser. package packt.java9.by.example.mastermind; <br/> <br/> public class Game { <br/> <br/> final Table table; <br/> final private Row secretRow; <br/> boolean finished = false; <br/> <br/> public Game(Table table, Color[] secret ) { <br/> this.table = table; <br/> this.secretRow = new Row(secret); <br/> } <br/> <br/> public void addNewGuess(Row row) { <br/> if( isFinished()){ <br/> throw new IllegalArgumentException( <br/> "You can not guess on a finished game."); <br/> } <br/> final int positionMatch = secretRow. <br/> nrMatchingPositions(row.positions); <br/> final int colorMatch = secretRow. <br/> nrMatchingColors(row.positions); <br/> row.setMatch(positionMatch, colorMatch); <br/> table.addRow(row); <br/> if( positionMatch == row.nrOfColumns() ){ <br/> finished = true; <br/> } <br/> } <br/> <br/> public boolean isFinished() { <br/> return finished; <br/> } <br/> } Think about what I wrote earlier about short methods, and when you download the code from GitHub to play with it, try to make it look more readable. You can, perhaps, create and use a method named boolean itWasAWinningGuess(int positionMatch). Creating an integration test We have created unit tests in the previous chapter and there are unit tests for the functionalities implemented in the classes of this chapter as well. We will just not print these unit tests here. Instead of listing the unit tests, we will look at an integration test. Integration tests need the invocation of many classes working together. They check that the functionality can be delivered by the whole application, or at least a larger part of the application, and do not focus on a single unit. They are called integration tests because they test the integration between classes. The classes alone are all OK. They should not have any problem as it was already verified by the unit tests. Integration focuses on how they work together. If we want to test the Game class, we will either have to create mocks that mimic the behavior of the other Game classes, or we will just write an integration test. Technically, an integration test is very similar to a unit test. Many times, the very same JUnit framework is used to execute the integration tests. This is the case for the integration test of this game. The build tool, however, needs to be configured to execute the integration tests only when it is required. Usually, integration test executions need more time, and sometimes resources, such as external database that may not be available at each and every developer desktop. Unit tests run every time the application is compiled so they have to be fast. To separate the unit and integration tests, there are different techniques and configuration options, but there is no such more or less de-facto standard like the directory structure introduced by Maven (later adapted by Gradle). In our case, the integration test does not need any extra resource and does not take enormous time to run. It plays a game from the start to the end and plays the role of both the players. It is very much like somebody playing chess with themselves, making a step and then turning the table. The aim of this code is twofold. On one hand, we want to see that the code runs and plays a whole game. If the game finishes, then it is just OK. This is a very weak assertion and real integration tests perform lots of assertions (one test tests only one assertion though). We will focus on the other aim—deliver some joy and visualize the game on the console in text format so that the reader does not get bored. To do that, we will create a utility class that prints out a color and assigns letters to the Color instances on the fly. This is the PrettyPrintRow class. There are several limitations in this class that we have to talk about after we look at the code. I'd say that this code is here only to demonstrate what not to do, to establish some reasoning for the next chapter, and why we need to refactor the code we created in this one. package packt.java9.by.example.mastermind; import java.util.HashMap; import java.util.Map; public class PrettyPrintRow { private static final Map<Color, Character> letterMapping = new HashMap<>(); private static final String letters = "RGBYWb"; private static int counter = 0; private static char colorToChar(Color color) { if (!letterMapping.containsKey(color)) { letterMapping.put(color, letters.charAt(counter)); counter++; } return letterMapping.get(color); } This is the heart of this class. When a color is to be printed, it gets a letter assigned unless it already has one. As the Map containing the assignments in each and every game that is running in the JVM will use the same mapping, a new Game is started. It allocates new Colors and will soon run out of the six characters that we allocated here in the String constant. If the Game instances are run parallel, then we are in even more trouble. The class is not thread safe at all. If two threads concurrently call the colorToChar method for the same Color instance, (which is not likely because each Game uses its own color, but note that not likely in programming is very much like a famous last words quote on a tombstone) then both threads may see at the same time that there is no letter assigned to the color and both will assign the letter (the same letter or two different letters, based on luck) and increase the counter once or twice. At least, what we can say is that the execution is nondeterministic. You may recall that I said violating the hash contract is the second most difficult to find bug after multithread issues. Such a nondeterministic code is exactly that: a multithread issue. There is no prize to find the most difficult bug. When the application does not run, and a bug affects the production system for hours or days, no businessperson will be happy, and they will not be amazed after you find the bug. It may be an intellectual challenge, but the real value is not creating the bugs in the first place. As a summary, this code can only be used once in a JVM by a single thread. For this chapter, it is good, though a smelly and shameful code, but it will be a good example for the next chapter, in which we will see, how to refactor the application so that it will not need such a hacking to print out the colors. Code smell is a term minted by Kent Back, according to Martin Fowler (http://martinfowler.co m/bliki/CodeSmell.html). It means that some code looks not good, nor apparently bad, but some constructs make the feeling in the developer that it may not be good. As it is defined on the web page, "A code smell is a surface indication that usually corresponds to a deeper problem in the system." The term is widely accepted and used in software development for the last 10 years. The rest of the code is plain and simple: public static String pprint(Row row) { String string = ""; PrintableRow pRow = new PrintableRow(row); for (int i = 0; i < pRow.nrOfColumns(); i++) { string += colorToChar(pRow.position(i)); } string += " "; string += pRow.matchedPositions(); string += "/"; string += pRow.matchedColors(); return string; } The integration test, or rather the demonstration code (as it does not contain any assertions other than it runs without exception), defines six colors and four columns. This is the size of the original game. It creates a color manager, and then it creates a table and a secret. The secret could be just any random color selection from the six colors that is available (there are 360 different possibilities tested in the UniqueGuesserTest unit test available from GitHub). As we know that the Guesser implementation starts from one end of the color set and creates the new guesses systematically, we want to set a secret that it will guess the last. This is not because we are evil, but rather because we want to see that our code really works. The directory structure of the code is very similar to the one we used in case of the Maven build tool, as can be seen on the following screenshot created on a Windows machine: The source code is under the directory src and the main and test source code files are separated into two subdirectory structures. The compiled files will be generated in the directory build when we use Gradle. The code of the integration test class is the following: package packt.java9.by.example.mastermind.integration; import org.junit.Assert; import org.junit.Test; import packt.java9.by.example.mastermind.*; public class IntegrationTest { final int nrColors = 6; final int nrColumns = 4; final ColorManager manager = new ColorManager(nrColors); private Color[] createSecret() { Color[] secret = new Color[nrColumns]; int count = 0; Color color = manager.firstColor(); while (count < nrColors - nrColumns) { color = manager.nextColor(color); count++; } for (int i = 0; i < nrColumns; i++) { secret[i] = color; color = manager.nextColor(color); } return secret; } @Test public void testSimpleGame() { Table table = new Table(nrColumns, manager); Color[] secret = createSecret(); System.out.println( PrettyPrintRow.pprint(new Row(secret))); System.out.println(); Game game = new Game(table, secret); Guesser guesser = new UniqueGuesser(table); while (!game.isFinished()) { Row guess = guesser.guess(); if (guess == Row.none) { Assert.fail(); } game.addNewGuess(guess); System.out.println(PrettyPrintRow.pprint(guess)); } } } The easiest way to run the test is start it from inside the IDE. When the IDE imports the project based on the build file, be it a Maven pom.xml or Gradle build.gradle. IDE usually provides a run button or menu to start the code. Running the game will print out the following piece of code that we worked so hard on in this chapter: RGBY GRWb YBbW BYGR RGYB RGBY 0/0 0/2 0/2 0/4 2/2 4/0 Summary In this chapter, we programmed a table game: Mastermind. We not only programmed the model of the game, but also created an algorithm that can guess. We revisited some OO principles and discussed why the model was created the way it was. While we created the model of the game, which we will refine in the next chapter, you have learned about Java collections, what an integration test is, and how to create JavaDoc. Extending the Game - Run Parallel, Run Faster In this chapter, we will extend the Mastermind game. As it is now, it can guess the secret that was hidden and also hide the pegs. The test code can even do both at the same time. It can play against itself leaving us only with the fun of programming. What it cannot do is make use of all the processors that we have in today's notebooks and servers. The code runs synchronous and utilizes only a single processor core. We will alter the code extending the guessing algorithm to slice up the guessing into subtasks and execute the code in parallel. During this, we will get acquainted with Java concurrent programming. This will be a huge topic with many subtle corners and caveats lurking in the dark. We will get into those details that are the most important and will form a firm base for further studies whenever you need concurrent programs. As the outcome of the game is the same as it was, only faster, we have to assess what faster is. To do that, we will utilize a new feature introduced in Java 9: microbenchmarking harness. In this chapter, we will cover the following topics: The meaning of processes, threads and fibers Multithreading in Java Issues with multithread programming and how to avoid them Locking, synchronization, and blocking queues Microbenchmarking How to make Mastermind parallel The old algorithm was to go through all the variations and try to find a guess that matches the current state of the table. Assuming that the currently examined guess is the secret, will we get the same answers for the guesses that are already on the table as the answers are actually on the table? If yes, then the current guess can be the secret, and it is just as good a guess as any other guesses. A more complex approach can implement the min-max algorithm (https://en.wikipedia.org/wiki/Minimax). This algorithm does not simply get the next possible guess but also looks at all the possible guesses and selects the one that shortens the outcome of the game the most. If there is a guess that can be followed by three more guesses in the worst case, and there is another for which this number is only two, then min-max will choose the latter. It is a good exercise for the interested readers. In the case of the six colors and four columns for the pegs, the min-max algorithm solves the game in no more than 5 steps. The simple algorithm we implemented also solves the game in 5 steps. However, we do not go in that direction. Instead, we want to have a version of the game that utilizes more than one processor. How can you transform the algorithm into a parallel one? There is no simple answer to this. When you have an algorithm, you can analyze the calculations and parts of the algorithm, and you can try to find dependencies. If there is some calculation B that needs the data, which is the result of another calculation A, then it is obvious that A can only be performed when B is ready. If there are parts of the algorithm that do not depend on the outcome of the others, then they can be executed in parallel. For example, the quick-sort has two major tasks: partitioning and then sorting of the two parts. It is fairly obvious that the partitioning has to finish before we start sorting the two partitioned parts. However, the sorting tasks of the two parts do not depend on each other, they can be done independently. You can give them to two different processors. One will be happy sorting the part containing the smaller elements; the other one will carry the heavier, larger ones. If you turn the pages back to Chapter 3, Optimizing the Sort - Making Code Professional where we implemented quick-sort in a non-recursive way, you can see that we scheduled sorting tasks into a stack and then performed the sorting by fetching the elements from the stack in a while loop. Instead of executing the sort right there in the core of the loop, we could pass the task to an asynchronous thread to perform it and go back for the next waiting task. We just do not know how. Yet. That is why we are here in this chapter. Processors, threads, and processes are complex and abstract things and they are hard to imagine. Different programmers have different techniques to imagine parallel processing and algorithms. I can tell you how I do it but it is not a guarantee that this will work for you. Others may have different techniques in their mind. As a matter of fact, I just realized that as I write this, I have actually never told this to anyone before. It may seem childish, but anyway, here it goes. When I imagine algorithms, I imagine people. One processor is one person. This helps me overcome the freaking fact that a processor can make billions of calculations in a second. I actually imagine a bureaucrat wearing a brown suit and doing the calculations. When I create a code for a parallel algorithm, I imagine many of them working behind their desks. They work alone and they do not talk. It is important that they do not talk to each other. They are very formal. When there is a need for information exchange, they stand up with a piece of paper they have written something on, and they bring it to each other. Sometimes, they need a piece of paper for their work. Then they stand up, go to the place where the paper is, take it, bring it back to their desk, and go on working. When they are ready, they go back and bring the paper back. If the paper is not there when they need it, they queue up and wait until someone who has the paper brings it there. How does it help with Mastermind? I imagine a boss who is responsible for the guesses. There is a table on the wall in the office with the previous guesses and the results for each row. The boss is too lazy to come up with new guesses so he gives this task to subordinates. When a subordinate comes up with a guess, the boss checks whether the guess is valid or not. He does not trust the subordinates, and if the guess is good, he makes it as an official guess, putting it on the table along with the result. The subordinates deliver the guesses written on small post-it notes, and they put them in a box on the table of the boss. The boss looks at the box from time to time, and if there is a note, the boss takes it. If the box is full and a subordinate wants to put a paper there, the subordinate stops and waits until the boss takes at least one note so that there is some room in the box for a new note. If the subordinates queue up to deposit guesses in the box, they all wait for their time. The subordinates should be coordinated; otherwise, they will just come up with the same guesses. Each of them should have an interval of guesses. For example, the first one should check the guesses from 1234 up until 2134, the second should check from 2134 up until 3124, and so on, if we denote the colors with numbers. Will this structure work? Common sense says that it will. However, bureaucrats, in this case, are metaphors and metaphors are not exact. Bureaucrats are human, even when they do not seem like it much more than threads or processors. They sometimes behave extremely strangely, doing things that normal humans don't really do often. However, we can still use this metaphor if it helps us imagine how parallel algorithms work. We can imagine that the boss goes on holiday and does not touch the heap of paper piling up on the table. We can imagine that some of the workers are producing results much faster than the others. As this is only imagination, the speedup can be 1000 times (think of a time-lapse video). Imagining these situations may help us discover special behavior that rarely happens, but may cause problems. As the threads work in parallel, many times subtle differences may influence the general behavior greatly. In some early version, as I coded the parallel Mastermind algorithm, the bureaucrats started working and filled the box of the boss with guesses before the boss could put any of them on the table. As there were no guesses on the table, the bureaucrats simply found all possible variations in their interval being a possibly good guess. The boss gained nothing by the help of the parallel helpers; they had to select the correct ones from all possible guesses, while the guessers were just idle. Another time, the bureaucrats were checking guesses against the table while the boss was putting a guess on one of them created beforehand. And some of the bureaucrats freaked out saying that it is not possible to check a guess against a table if someone is changing it. More precisely, the code executing in one thread, threw ConcurrentModificationException when the List of the table was modified. Another time, I tried to avoid the too fast work of bureaucrats, and I limited the size of the box where they could put their papers containing the guesses. When the boss finally found the secret, and the game finished, the boss told the bureaucrats that they could go home. The boss did that by creating a small paper with the instruction: you can go home, and put it on the tables of the bureaucrats. What did the bureaucrats do? Kept waiting for the box to have space for the paper! (Until the process was killed. This is kind of equivalent on Mac OS and on Linux as ending the process from the task manager on Windows.) Such coding errors happen and, to avoid as many as possible, we have to do at least two things. Firstly, we have to understand how Java multithreading works and secondly, have a code as clean as possible. For the second, we will clean up the code even more and then we will look at how the parallel algorithm described earlier can be implemented in Java, running on the JVM instead of utilizing bureaucrats. Refactoring When we finished the previous chapter, we had the classes of the Mastermind game designed and coded in a nice and perfectly object oriented way that did not break any of the OO principles. Did we? Absurd. There is no code, except some trivial examples, that cannot be made to look nicer or better. Usually, when we develop code and finish the coding, it looks great. It works, the tests all run, and documentation is ready. From the professional point of view, it really is perfect. Well, it is good enough. The big question that we have not tested yet is maintainability. What is the cost to alter the code? That is not an easy question, especially because it is not a definite one. Alter to what? What is the modification that is to be made to the code? We do not know that when we create the code in the first place. If the modification is to fix a bug, then it is obvious that we did not know that beforehand. If we knew, we would not have introduced the bug in the first place. If this is a new feature, then there is a possibility that the function was foreseen. However, usually it is not the case. When a developer tries to predict the future, and what features the program will need in the future, they usually fail. It is the task of the customer to know the business. Features needed are driven by the business in case of professional software development. After all, that is what it means to be professional. Even though we do not exactly know what needs to be altered later in the code, there are certain things that may give hints to experienced software developers. Usually, the OO code is easier to maintain than the ad-hoc code, and there are code smells that one can spot. For example, take a look at the following code lines: while (guesser.guess() != Row.none) { while (guesser.nextGuess() != Guesser.none) { public void addNewGuess(Row row) { Color[] guess = super.nextGuess(); We may sense the odor of something strange. (Each of these lines is in the code of the application as we finished it in Chapter 4, Mastermind - Creating a Game.) The return value of the guess method is compared to Row.none, which is a Row. Then, we compare the return value of nextGuess to Guesser.none, which should be a Guesser. When we add a new guess to something, we actually add a Row. Finally, we can realize that nextGuess returns a guess that is not an object with its own declared class. A guess is just an array of colors. Should we introduce another layer of abstraction creating a Guess class? Will it make the code more maintainable? Or will it only make the code more complex? It is usually true that the less code lines we have, the less possibility we have for bugs. However, sometimes, the lack of abstraction will make the code complex and tangled. What is the case in this situation? How can we decide that generally? The more experience you have, the easier you will tell by looking at the code and acutely knowing what modifications you want to make. Many times, you will not bother making the code more abstract, and many other times, you will create new classes without hesitation. When in doubt, do create the new classes and see what comes out. The important thing is not to ruin the already existing functionality. You can do that only if you have sufficient unit tests. When you want to introduce some new functionality or fix a bug, but the code is not appropriate, you will have to modify it first. When you modify the code so that the functionality does not change, the process is named refactoring. You change a small part of the code in a limited time, and then you build it. If it compiles and all unit tests run, then you can go on. The hint is to run the build frequently. It is like building a new road near an existing one. Once in every few miles, you should meet the old line. Failing to do so, you will end up somewhere in the middle of the desert in a totally wrong direction, and all you can do is return to the starting point—your old to-be-refactored code. Effort wasted. It is not only the safety that advises us to run the build frequently, it is also time limitation. Refactoring does not directly deliver revenue. The functionality of the program is tied directly to income. Nobody will pay us for infinite refactoring work. Refactoring has to stop some time and it is usually not the time when there is nothing to be refactored any more. The code will never be perfect, but you may stop when it is good enough. And, many times, programmers are never satisfied with the quality of the code, and when they are stopped by some external factor (usually called project manager), the code should compile and tests should run so that the new feature and bug fixing can be performed on the actual code base. Refactoring is a huge topic and there are many techniques that can be followed during such an activity. It is so complex that there is a whole book about it by Martin Fowler (http://martinfowler.com/books/refactoring.html). In our case, the modification we want to apply to our code is to implement a parallel algorithm. The first thing we will modify is the ColorManager. When we wanted to print guesses and rows on the terminal, we had to implement some bad tricks. Why not have color implementations that can be printed? We can have a class that extends the original Color class and has a method that returns something that represents that color. Do you have any candidate name for that method? It is the toString method. It is implemented in the Object class and any class can freely override it. When you concatenate an object to a string, automatic type conversion will call this method to convert the object to String. By the way, it is an old trick to use ""+object instead of object.toString() to avoid null pointer exception. Needless to say, we do not use tricks. The toString method is also invoked by the IDEs when the debugger wants to display the value of some object, so it is generally recommended to implement toString if for nothing else, then to ease development. If we have a Color class that implements toString, then the PrettyPrintRow class becomes fairly straightforward and tricks less: package packt.java9.by.example.mastermind; public class PrettyPrintRow { public static String pprint(Row row) { String string = ""; PrintableRow pRow = new PrintableRow(row); for (int i = 0; i < pRow.nrOfColumns(); i++) { string += pRow.pos(i); } string += " "; string += pRow.full(); string += "/"; string += pRow.partial(); return string; } } We removed the problem from the printing class, but you may argue that the issue is still there, and you are right. Many times, when there is a problem in a class design, the way to the solution to move the problem from the class to another. If it is still a problem there, then you may split the design more and more and, at the last stage, you will realize that what you have is an issue and not a problem. To implement a LetteredColor class is also straightforward: package packt.java9.by.example.mastermind.lettered; import packt.java9.by.example.mastermind.Color; public class LetteredColor extends Color { private final String letter; public LetteredColor(String letter){ this.letter = letter; } @Override public String toString(){ return letter; } } Again, the problem was pushed forward. But, in reality, this is not a problem. It is an OO design. Printing is not responsible for assigning String to colors for their representation. And the color implementation itself is also not responsible for that. The assignment has to be performed where the color is made, and then the String has to be passed to the constructor of the LetteredColor class. The color instances are created in ColorManager so we have to implement this in the ColorManager class. Or not? What does ColorManager do? It creates the colors and... When you come to an explanation or description of a class that lists the functionalities, you may immediately see that the single responsibility principle was ignored. ColorManager should manage the colors. Managing is providing a way to get the colors in a definite order and getting the first and the next when we know one color. We should implement the other responsibility—the creation of a color in a separate class. A class that has the sole functionality to create an instance of another class is called factory. That is almost the same as using the new operator but unlike new, the factories can be used more flexibly. We will see that immediately. The ColorFactory interface contains a single method, as follows: package packt.java9.by.example.mastermind; public interface ColorFactory { Color newColor(); } Interfaces that define only one method are named functional interfaces because their implementation can be provided as a lambda expression at the place where you would use an object that is an instance of a class which implements the functional interface. The SimpleColorFactory implementation creates the following Color objects: package packt.java9.by.example.mastermind; public class SimpleColorFactory implements ColorFactory { @Override public Color newColor() { return new Color(); } } It is very much like how we create an interface, and then an implementation, instead of just writing new Color() in the code in ColorManager. LetteredColorFactory is a bit more interesting: package packt.java9.by.example.mastermind.lettered; import packt.java9.by.example.mastermind.Color; import packt.java9.by.example.mastermind.ColorFactory; public class LetteredColorFactory implements ColorFactory { private final String letters = "0123456789ABCDEFGHIJKLMNOPQRSTVWXYZabcdefghijklmnopqrstvwxzy"; private int counter = 0; @Override public Color newColor() { Color color = new LetteredColor(letters.substring(counter, counter + 1)); counter++; return color; } } Now, here we have the functionality that assigns Strings to the Color objects when they are created. It is very important that the counter variable that keeps track of the already created colors is not static. The similar variable in the previous chapter was static and it meant that it could run out of characters as evernewer ColorManagers created too many colors. It actually did happen to me during the unit test execution when the tests each created ColorManagers and new Color instances, and the printing code tried to assign new letters to the new colors. The tests were running in the same JVM under the same classloader and the unfortunate static variable had no clue when it could just start counting from zero for the new tests. The drawback is that somebody, somewhere, has to instantiate the factory and it is not the ColorManager. ColorManager already has a responsibility and it is not to create a color factory. The ColorManager has to get the ColorFactory in its constructor: package packt.java9.by.example.mastermind; import java.util.HashMap; import java.util.List; import java.util.Map; public class ColorManager { final protected int nrColors; final protected Map<Color, Color> successor = new HashMap<>(); private Color first; private final ColorFactory factory; public ColorManager(int nrColors, ColorFactory factory) { this.nrColors = nrColors; this.factory = factory; createOrdering(); } private Color[] createColors() { Color[] colors = new Color[nrColors]; for (int i = 0; i < colors.length; i++) { colors[i] = factory.newColor(); } return colors; } private void createOrdering() { Color[] colors = createColors(); first = colors[0]; for (int i = 0; i < nrColors - 1; i++) { successor.put(colors[i], colors[i + 1]); } } public Color firstColor() { return first; } public boolean thereIsNextColor(Color color) { return successor.containsKey(color); } public Color nextColor(Color color) { return successor.get(color); } public int getNrColors() { return nrColors; } } You may also notice that I could not resist refactoring the createColors method into two methods to follow the single responsibility principle. Now, the code that creates ColorManager has to create a factory and pass it to the constructor. For example, the unit test's ColorManagerTest class will contain the following method: @Test public void thereIsAFirstColor() { ColorManager manager = new ColorManager(NR_COLORS, Color::new); Assert.assertNotNull(manager.firstColor()); } This is the simplest way ever to implement a factory defined by a functional interface. Just name the class and reference the new operator like it was a method by creating a method reference. The next thing we will refactor is the Guess class, which, actually, we did not have so far. A Guess class contains the pegs of the guess and can calculate the number of full (color as well as position) and partial (color present but in wrong position) matches, and can also calculate the next Guess that comes after this guess. This functionality was implemented in the Guesser class so far, but this is not really the functionality for how we select the guesses when checking the already made guesses on the table. If we follow the pattern we set up for the colors, we may implement this functionality in a separate class named GuessManager, but as for now, it is not needed. Again, this is not black and white. It is important to note that a Guess object can only be made at once. If it is on the table, the player is not allowed to change it. If we have a Guess that is not yet on the table, it is still just a Guess identified by the colors and orders of the pegs. A Guess object never changes after it was created. Such objects are easy to use in multithread programs and are called immutable objects: package packt.java9.by.example.mastermind; import java.util.Arrays; import java.util.HashSet; import java.util.Set; public class Guess { final static public Guess none = new Guess(new Color[0]); final private Color[] colors; private boolean uniquenessWasNotCalculated = true; private boolean unique; public Guess(Color[] colors) { this.colors = Arrays.copyOf(colors, colors.length); } The constructor is creating a copy of the array of colors that were passed. As a Guess is immutable, this is extremely important. If we just keep the original array, any code outside of the Guess class could alter the elements of the array, essentially changing the content of Guess that is not supposed to be changing: public Color getColor(int i) { return colors[i]; } public int nrOfColumns() { return colors.length; } /** * Calculate the next guess and return a new Guess object. * The guesses are ordered in the order of the colors as * specified by the color manager. * * @param manager that specifies the order of the colors * can return the next color after one color. * @return the guess that comes after this guess. */ public Guess nextGuess(ColorManager manager) { final Color[] colors = Arrays.copyOf( this.colors, nrOfColumns()); int i = 0; boolean guessFound = false; while (i < colors.length && !guessFound) { if (manager.thereIsNextColor(getColor(i))) { colors[i] = manager.nextColor(colors[i]); guessFound = true; } else { colors[i] = manager.firstColor(); i++; } } if (guessFound) { return new Guess(colors); } else { return Guess.none; } } In this method, we start to calculate the next Guess starting with the color array that is contained in the actual object. We need a work array that is modified, so we will copy the original. The final new object can, this time, use the array we use during the calculation, so that will need a separate constructor that does not create a copy. It is possible extra code, but we should consider making that only if we see that that is the bottleneck in the code and we are not satisfied with the actual performance. The next method just checks if the passed Guess has the same number of colors as the actual one. This is just a safety check used by the next two methods that calculate the matches: private void assertCompatibility(Guess guess) { if (nrOfColumns() != guess.nrOfColumns()) { throw new IllegalArgumentException("Cannot compare different length guesses"); } } /** * Count the number of colors that are present on the guess * but not on the pos where they are in the other guess. * If the same color is on multiple pos it is counted * for each pos once. For example the secret is * <pre> * RGRB * </pre> * and the guess is * <pre> * YRPR * </pre> * then this method will return 2. * * @param guess is the actual guess that we evaluate * @return the number of good colors not in pos */ public int nrOfPartialMatches(Guess guess) { assertCompatibility(guess); int count = 0; for (int i = 0; i < nrOfColumns(); i++) { for (int j = 0; j < nrOfColumns(); j++) { if (i != j && guess.getColor(i) == this.getColor(j)) { count++; } } } return count; } /** * Count the number of colors that are correct and are in pos. * * @param guess is the actual guess that we evaluate * @return the number of colors that match in pos */ public int nrOfFullMatches(Guess guess) { assertCompatibility(guess); int count = 0; for (int i = 0; i < nrOfColumns(); i++) { if (guess.getColor(i) == this.getColor(i)) { count++; } } return count; } The isUnique method checks if there is any color more than once in the Guess. As the Guess is immutable, it may not happen that a Guess is unique one time and not unique at another time. This method should return the same result whenever it is called on a specific object. Because of that, it is possible to cache the result. This method does this, saving the return value to an instance variable. You may say that this is premature optimization. Yes, it is. I decided to do it for one reason. It is demonstration, and based on that, you can try to modify the nextGuess method to do the same: /** * @return true if the guess does not * contain any color more than once */ public boolean isUnique() { if (uniquenessWasNotCalculated) { final Set<Color> alreadyPresent = new HashSet<>(); unique = true; for (Color color : colors) { if (alreadyPresent.contains(color)) { unique = false; break; } alreadyPresent.add(color); } uniquenessWasNotCalculated = false; } return unique; } Methods that return the same result for the same arguments are called idempotent. Caching the return value for such a method can be very important if the method is called many times and the calculation is using a lot of resources. When the method has arguments, the result caching is not simple. The object method has to remember the result for all arguments that were already calculated, and this storage has to be effective. If it takes more resources to find the stored result than the calculation of it, then the use of cache not only uses more memory but also slows down the program. If the method is called for several arguments during the lifetime of the object, then the storage memory may just grow too large. Some of the elements have to be purged—those that will not be needed anymore in the future. However, we cannot know which elements of the cache are not needed, so we will have to guess. As you can see, caching can get complex very fast and, to do that professionally, it is almost always better to use some readily available cache implementation. The caching we use here is only the tip of the iceberg. Or, it is even only the sunshine glimpsing on it. The rest of the class is fairly standard and something we have talked about in detail—a good check of your knowledge is to understand how the equals, hashCode, and toString methods are implemented this way. I implemented the toString method to help me during debugging, but it is also used in the following example output: @Override public boolean equals(Object other) { if (this == other) return true; if (other == null || !(other instanceof Guess)) return false; Guess guess = (Guess) other; return Arrays.equals(colors, guess.colors); } @Override public int hashCode() { return Arrays.hashCode(colors); } @Override public String toString() { if (this == none) { return "none"; } else { String s = ""; for (int i = colors.length - 1; i >= 0; i--) { s += colors[i]; } return s; } } } This is mainly the modification that I needed while I developed the parallel algorithm. Now, the code is fairly up-to-date and described to focus on the main topic of this chapter: how to execute code in Java in parallel. The parallel execution of the code in Java is done in threads. You may know that there is a Thread object in Java runtime, but without understanding what a thread in the computer is, it makes no sense. In the following subsections, we will learn what these threads are, how to start a new thread, how to synchronize data exchange between threads, and finally put all this together and implement the Mastermind parallel guessing algorithm. Processes When you start your computer, the program that starts is the operating system (OS). The OS controls the machine hardware and the programs that you can run on the machine. When you start a program, the OS creates a new process. It means that the OS allocates a new entry in a table (array) where it administers the processes and fills in the parameters that it knows, and needs to know, about the process. For example, it registers what memory segment the process is allowed to use, what the ID of the process is, and which user started from which other process. You cannot start a process just out of thin air. When you double-click on an EXE file, you actually tell the file explorer, which is a program running as a process, to start the EXE file as a separate process. The explorer calls the system via some API and kindly asks the OS to do that. The OS will register the explorer process as the parent of the new process. The OS does not actually start the process, but creates all the data that it needs to start it and, when there is some free CPU resource, then the process gets started, and then it gets paused very soon. You will not notice it because the OS will start it again and again and is always pausing the process repeatedly. It needs to do it to provide run possibilities to all processes. That way, we experience all processes running at the same time. In reality, processes do not run at the same time on a single processor, but they get time slots to run often. If you have more than one CPU in the machine, then processes can actually run at the same time, as many CPUs as there are. As the integration gets more advanced today, desktop computers have CPUs that contain multiple cores that function almost like separate CPUs. On my machine, I have four cores, each capable of executing two threads simultaneously; so, my Mac is almost like an 8 CPU machine. Processes have separate memories. They are allowed to use one part of the memory and if a process tries to use another part that does not belong to it, the processor will stop doing so. The OS will kill the process. Just imagine how frustrated the developers of the original UNIX could have been that they named the program to stop a process to kill, and stopping a process is called killing it. It is like medieval ages when they cut off the hand of a felon. You touch the wrong part of the memory and get killed. I would not like to be a process. The memory handling by the operating system is very complex in addition to separating the processes from each other. When there is not enough memory, the OS writes part of the memory to disk freeing up the memory and reloading that part when it is needed again. This is a very complex, low-level implemented and highly optimized algorithm that is the responsibility of the OS. Threads When I said that the OS executes the processes in time slots, I was not absolutely precise. Every process has one or more threads, and threads are executed. A thread is the smallest execution managed by an external scheduler. Older operating systems did not have the notion of a thread and were executing processes. As a matter of fact, the first thread implementations were simply duplications of processes that were sharing the memory. You may hear the terminology, lightweight process—it means a thread. The important thing is that the threads do not have their own memory. They use the memory of the process. In other words, the threads that run in the same process have undistinguished access to the same memory segment. It is an extremely powerful possibility to implement parallel algorithms that make use of the multiple cores in the machine, but at the same time, it may lead to bugs. Imagine that two threads increment the same long variable. The increment first calculates the incremented value of the lower 32 bits and then the upper, if there were any overflow bits. These are two or more steps that may be interrupted by the OS. It may happen that one thread increments the lower 32 bits, remembers that there is something to do to the upper 32 bits, starts the calculation, but has no time to store the result before it gets interrupted. Then, another thread increments the lower 32 bits, the upper 32 bits, and then the first thread just saves the upper 32 bits that it calculated. The result gets garbled. On an older 32-bit Java implementation, it was extremely easy to demonstrate this effect. On a 64-bit Java implementation, all the 64 bits are loaded into registers and saved back to the memory in one step so it is not that easy to demonstrate multithread issues, but it does not mean that there are none. When a thread is paused and another thread is started, the operating system has to perform a context switch. It means that, among other things, the CPU registers have to be saved and then set to the value that they should have for the other thread. A context switch is always saving the state of the thread and loading the previously saved state of the thread to be started. This is on a CPU register level. This context switch is time consuming; therefore, the more context switches that are done, the more CPU resource is used for the thread administration instead of letting them run. On the other hand, if there are not enough switches, some threads may not get enough time slots to execute, and the program hangs. Fibers Java does not have fibers, but as there are some libraries that support fiber handlings, it is worth mentioning. A fiber is a finer unit than a thread. A program code executing in a thread may decide to give up the execution and tell the fiber manager to just execute some other fiber. What is the point and why is it better than using another thread? The reason is that this way, fibers can avoid part of the context switch. A context switch cannot be avoided totally because a different part of the code that starts to execute it may use the CPU registers in a totally different way. As it is the same thread, the context switching is not the task of the OS, but the application. The OS does not know if the value of a register is used or not. There are bits in the registers, and no one can tell seeing only the processor state whether those bits are relevant for the current code execution or just happen to be there in that way. The program generated by a compiler does know which registers are important and which are those that can just be ignored. This information changes from place to place in the code, but when there is a need for a switch, the fiber passes the information of what is needed to be switched at that point to the code that does the switching. The compiler calculates this information, but Java does not support fibers in the current version. The tools that implement fibers in Java analyze and modify the byte code of the classes to do this after the compilation phase. Golang's goroutines are fibers and that is why you can easily start many thousand goroutines in Go, but you better limit the number of threads in Java to a lower number. They are not the same things. As the terminology lightweight process is fading out and used by less and less fibers, many times are referred to as lightweight threads. java.lang.Thread As everything in Java (well, almost) is object, if we want to start a new thread, we will need a class that represents the thread. This class is java.lang.Thread built into the JDK. When you start a Java code, the JVM automatically creates a few Thread objects and uses them to run different tasks that are needed by it. If you start up VisualVM, you can select the Threads tab of any JVM process and see the actual threads that are in the JVM. For example, the VisualVM as I started it has 29 live threads. One of them is the thread named main. This is the one that starts to execute the main method (surprise!). The main thread started most of the other threads. When we want to write a multithread application, we will have to create new Thread objects and start them. The simplest way to do that is new Thread(), and then calling the start method on the thread. It will start a new Thread that will just finish immediately as we did not give it anything to do. The Thread class, as it is in the JDK, does not do our business logic. The following are the two ways to specify the business logic: Creating a class that implements the Runnable interface Creating a class that extends the Thread class and overrides the run method The following block of code is a very simple demonstration program: public class ThreadIntermingling { static class MyThread extends Thread { private final String name; MyThread(String name){ this.name = name; } @Override public void run(){ for(int i = 1 ; i < 1000 ; i ++ ){ System.out.print(name + " " + i+ ", "); } } } public static void main(String[] args){ Thread t1 = new MyThread("t1"); Thread t2 = new MyThread("t2"); t1.start(); t2.start(); System.out.print("started "); } } The preceding code creates two threads and starts them one after the other. When the start method is called, it schedules the thread object to be executed and then returns. As a result, the new thread will soon start executing asynchronously while the calling thread continues its execution. The two threads, and the main thread, run parallel in the following example and create an output that looks something like this: started t2 1, t2 2, t2 3, t2 4, t2 5, t2 6, t2 7, t2 8, t1 1, t2 9, t2 10, t2 11, t2 12,... The actual output changes from run to run. There is no definite order of the execution or how the threads get access to the single screen output. There is not even guarantee that in each and every execution, the message started is printed before any of the thread messages. To get a better understanding of this, we will have to look at the state diagram of threads. A Java Thread can be in one of the following states: NEW RUNNABLE BLOCKED WAITING TIMED_WAITING TERMINATED These states are defined in the enumThread.State. When you create a new thread object, it is in the NEW state. At this moment, the thread is nothing special, it is just an object but the operating system executionscheduling does not know about it. In some sense, it is only a piece of memory allocated by the JVM. When the start method is invoked, the information about the thread is passed to the operating system and the OS schedules the thread so it can be executed by it when there is an appropriate time slot. Doing this is a resourceful action and that is the reason why we do not create and, especially, do not start new Thread objects only when it is needed. Instead of creating new Threads, we will keep the existing threads for a while, even if they are not needed at the moment, and reuse an existing one if there is one suitable. A thread in the OS can also be in a running state as well as runnable when the OS schedules and executes it at the moment. Java JDK API does not distinguish between the two for good reason. It would be useless. When a thread is in the RUNNABLE state asking if it is actually running from the thread itself, it will result in an obvious answer: if the code just returned from the getState method implemented in the Thread class, then it runs. If it were not running, it would not have returned from the call in the first place. If the getState method was called from another thread, then the result about the other thread by the time the method returns would be meaningless. The OS may have stopped, or started, the queried thread several times until then. A thread is in a BLOCKED state when the code executing in the thread tries to access some resource that is not currently available. To avoid constant polling of resources, the operating system provides effective notification mechanism so the threads get back to the RUNNABLE state when the resource they need becomes available. A thread is in the WAIT or TIMED_WAITING state when it waits for some other thread or lock. TIMED_WAITING is the state when the waiting started calling a version of a method that has timeout. Finally, the TERMINATED state is reached when the thread finishes its execution. If you append the following lines to the end of our previous example, then you will get a TERMINATED printout and also an exception thrown up to the screen complaining about illegal thread state, which is because you cannot start an already terminated thread: System.out.println(); System.out.println(t1.getState()); System.out.println(); t1.start(); Instead of extending the Thread class to define what to execute asynchronously, we can create a class that implements Runnable. Doing that is more in line with the OO programming approach. The something that we implement in the class is not a functionality of a thread. It is more of a something that can be executed. It is something that can just run. If this execution is asynchronous in a different thread, or it is executed in the same thread that was calling the run method, is a different concern that has to be separated. If we do it that way, we can pass the class to a Thread object as a constructor argument. Calling start on the Thread object will start the run method of the object we passed. This is not the gain. The gain is that we can also pass the Runnable object to an Executor (dreadful name, huhh!). Executor is an interface, and implementations execute Runnable (and also Callable, see later) objects in Threads in an efficient way. Executors usually have a pool of Thread objects that are prepared, and in the BLOCKED state. When the Executor has a new task to execute, it gives it to one of the Thread objects and releases the lock that is blocking the thread. The Thread gets into the RUNNABLE state, executes the Runnable, and gets blocked again. It does not terminate and thus can be reused to execute another Runnable later. That way, Executors avoid the resource consuming process of thread registration into the operating system. Professional application code never creates a new Thread. Application code uses some framework to handle the parallel execution of the code or uses Executors provided by some ExecutorService to start Runnable or Callable objects. Pitfalls We have already discussed many of the problems that we may face when developing parallel program. In this section, we will summarize them with the usual terminology used for the problems. Terminology is not only interesting, but it is also important when you talk with colleagues to easily understand each other. Deadlocks Deadlock is the most infamous parallel programming pitfall, and for this reason, we will start with this one. To describe the situation, we will follow the metaphor of bureaucrats. The bureaucrat has to stamp a paper he has in his hand. To do that, he needs the stamp, and he also needs the inkpad. First, he goes to the drawer where the stamp is and takes it. Then, he walks to the drawer where the inkpad is and takes the inkpad. He inks the stamp, pushes on the paper. Then, he puts the stamp back to its place and then the inkpad back in its place. Everything is nice, we are on cloud 9. What happens if another bureaucrat takes the inkpad first and then the stamp second? They may soon end up as one bureaucrat with the stamp in hand waiting for the inkpad and another one with the inkpad in hand waiting for the stamps. And, they may just stay there, frozen forever, and then more and more start to wait for these locks, the papers never get stamped, and the whole system sinks into anarchy. To avoid such situations, the locks have to be ordered and the locks should always be acquired in the order. In the preceding example, the simple agreement that the inkpad is acquired first and the stamp second solves the problem. Whoever acquired the stamp can be sure that the inkpad is free or will soon be free. Race conditions We talk about race conditions when the result of a calculation may be different based on the speed and CPU access of the different parallel running threads. Let's take a look at the following two code lines: void method1(){ 1 a = b; 2 b = a+1; } void method2(){ 3 c = b; 4 b = c+2; } If the value of b at the start of the execution is 0, and two different threads execute the two methods, then the order of the lines can be 1234, 1324, 1342, 3412, 3142, or 3142. Any execution order of the four lines may happen which assures that 1 runs before 2 and 3 runs before 4, but no other restrictions. The outcome, the value of b, is either 1 or 2 at the end of the execution of the segments, which may not be good and what we wanted when coding. Note that the implementation of the parallel Mastermind game also has something like this. The actual guesses very much depend on the speed of the different threads, but this is irrelevant from the final result point of view. We may have different guesses in different runs and that way the algorithm is not deterministic, but we are guaranteed to find the final solution. Overused locks In many situations, it may happen that the threads are waiting on a lock, which protects a resource from concurrent access. If the resource cannot be used by multiple threads simultaneously, and there are more threads than can be served, then the threads are starving. However, in many cases, the resource can be organized in a way so that the threads can get access to some of the services that the resource provides, and the locking structure can be less restrictive. In that case, the lock is overused and the situation can be mended without allocating more resource for the threads. It may be possible to use several locks that control the access to the different functionality of the resource. Starving Starving is the situation when several threads are waiting for a resource trying to acquire a lock and some threads get access to the lock only after extremely long time or never. When the lock is released and there are threads waiting for it, then one of the threads can get the lock. There is usually no guarantee that a thread gets the lock if it waits long enough. Such a mechanism would require intensive administration of the threads, sorting them in the waiting queue. As locking should be a low latency and high performance action, even a few CPU clock cycles are significant; therefore, the locks do not provide this type of fair access by default. Not wasting time with fairness in thread scheduling is a good approach, in case the locks have one thread waiting. The main goal of locks is not scheduling the waiting threads, but rather preventing parallel access to resources. It is like in a shop. If there is somebody at the cashier, you wait. It is a lock built in implicitly. It is not a problem if people do not queue up for the cashier, so long as long there is almost always one free. However, when there are several queues built up in front of the cashiers, then having no queue and waiting order will certainly lead to some very long waiting order for someone who is slow to get access to the cashier. Generally, the solution of fairness and creating queue of waiting threads (customers) is not a good solution. The good solution is to eliminate the situation that leads to waiting queues. You can employ more cashiers, or you can do something totally different that makes the peak load smaller. In a shop, you can give discount to drive customers who come in at off-peak hours. In programming, several techniques can be applied, usually, depending on the actual business we code and fair scheduling of locks is usually a workaround. ExecutorService is an interface in the JDK. An implementation of the interface can execute a Runnable or Callable class in an asynchronous way. The interface only defines the API for the implementation and does not require that the invocation is asynchronous but, in reality, that is the main point implementing such a service. Invoking the run method of a Runnable interface in a synchronous way is simply calling a method. We do not need a special class for that. ExecutorService The Runnable interface defines one run method. It has no arguments returns no value and does not throw any exception. The Callable interface is parameterized and the only method it defines, call, has no argument but returns a generic value and may also throw Exception. In our code, we will implement Runnable if we just want to run something, and Callable when we want to return something. Both of these interfaces are functional interfaces, therefore, they are good candidates to be implemented using lambda. To have an instance of an implementation of an ExecutorService, we can use the utility class Executors. Many times when there is an XYZ interface in the JDK, there can be an XYZs (plural) utility class that provides factory for the implementations of the interface. If we want to start the t1 task many times, we can do so without creating a new Thread. We should use the following executor service: public class ThreadIntermingling { static class MyThread implements Runnable { private final String name; MyThread(String name) { this.name = name; } @Override public void run() { for (int i = 1; i < 1000; i++) { System.out.print(name + " " + i + ", "); } } } public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newFixedThreadPool(2); Runnable t1 = new MyThread("t1"); Runnable t2 = new MyThread("t2"); Future<?> f1 = es.submit(t1); Future<?> f2 = es.submit(t2); System.out.print("started "); f1.get(); f2.get(); System.out.println(); f1 = es.submit(t1); es.shutdown(); } } This time, we do not get any exception. Instead, the t1 task runs second time. In this example, we are using a fixed size thread pool that has two Threads. As we want to start only two threads simultaneously, it is enough. There are implementations that grow and shrink the size of the pool dynamically. Fixed size pool should be used when we want to limit the number of the threads or we know from some other information source the number of the a-priory threads. In this case, it is a good experiment to change the size of the pool to one and see that the second task will not start in this case until the first one finishes. The service will not have another thread for t2 and will have to wait until the one and only Thread in the pool is freed. When we submit the task to the service, it returns even if the task cannot currently be executed. The tasks are put in a queue and will start execution as soon as there is enough resource to start them. The submit method returns a Future object, as we can see in the preceding sample. It is like a service ticket. You bring your car to the repair mechanic, and you get a ticket. You are not required to stay there until the car is fixed, but at any time, you can ask if the car is ready. All you need is the ticket. You can also decide to wait until the car is ready. A Future object is also something like that. You do not get the value that you need. It will be calculated asynchronously. However, there is a Future promise that it will be there and your ticket to access the object you need is the Future object. When you have a Future object, you can call the isDone method to see if it is ready. You can start waiting for it to call get with, or without, some timeout. You can also cancel the task executing it, but in that case, the outcome may be questionable. Just like, in case of your car, if you decide to cancel the task, you may get back your car with the motor disassembled. Similarly, cancelling a task that is not prepared for it may lead to resource loss, opened and inaccessible database connection (this is a painful memory for me, even after 10 years), or just a garbled unusable object. Prepare your tasks to be cancelled or do not cancel them. In the preceding example, there is no return value for Future because we submitted a Runnable object and not a Callable one. In that case the value passed to the Future is not to be used. It is usually null, but that is nothing to lean on. The final and most important thing that many developers miss, even me, after not writing multithread Java API using code for years, is shutting down the ExecutorService. The ExecutorService is created and it has Thread elements. The JVM stops when all non-daemon threads are stopped. It ain't over till the fat lady sings. A thread is a daemon thread if it was set to be daemon (invoking setDaemon(true)) before it was started. A thread is automatically daemon of the starting thread is a daemon thread. Daemon threads are stopped by the JVM when all other threads are finished and the JVM wants to finish. Some of the threads the JVM executes itself are daemon threads, but it is likely that there is no practical use of creating daemon threads in an application program. Not shutting down the service simply prevents the JVM from stopping. The code will hang after the main method finishes. To tell the ExecutorService that there is no need for the threads it has, we will have to shutdown the service. The call will only start the shutdown and return immediately. In this case, we do not want to wait. The JVM does anyway. If we need to wait, we will have to call awaitTermination. ForkJoinPool The ForkJoinPool is a special ExecutorService that has methods to execute ForkJoinTask objects. These classes are very handy when the task that we want to perform can be split into many small tasks and then the results, when they are available, aggregated. Using this executor, we need not care about the size of the thread pool and shutting down the executor. The size of the thread pool is adjusted to the number of processors on the given machine to have optimal performance. As the ForkJoinPool is a special ExecutorService that is designed for short running tasks, it does not expect any task to be there longer or being needed when there are no more tasks to run. Therefore, it is executed as a daemon thread; when the JVM shuts down, the ForkJoinPool automatically stops and the lady does not sing any more. To create a task, the programmer should extend either RecursiveTask or RecursiveAction. The first one is to be used when there is some return value from the task, the second when there is no computed value returned. They are called recursive because many times, these tasks split the problem they have to solve smaller problems and invoke these tasks asynchronously through the fork-join API. A typical problem to be solved using this API is the quick-sort. In the Chapter 3, Optimizing the Sort Making Code Professional we created two versions of the quick-sort algorithm. One using recursive calls and one without using it. We can also create a new one, which, instead of calling itself recursively, schedule the task to be executed, perhaps by another processor. The scheduling is the task of the ForkJoinPool implementation of ExecutorService. You may revisit the code of Qsort.java in Chapter 3, Optimizing the Sort - Making Code Professional. Here is the version that is using ForkJoinPool: public class FJQuickSort<E> { final private Comparator<E> comparator; final private Swapper swapper; public FJQuickSort(Comparator<E> comparator, Swapper swapper){ this.comparator = comparator; this.swapper = swapper; } public void qsort(SortableCollection<E> sortable, int start, int end) { ForkJoinPool pool = new ForkJoinPool(); pool.invoke(new RASort(sortable,start,end)); } private class RASort extends RecursiveAction { final SortableCollection<E> sortable; final int start, end; public RASort(SortableCollection<E> sortable, int start, int end) { this.sortable = sortable; this.start = start; this.end = end; } public void compute() { if (start < end) { final E pivot = sortable.get(start); final Partitioner<E> partitioner = new Partitioner<>(comparator, swapper); int cutIndex = partitioner.partition( sortable, start, end, pivot); if (cutIndex == start) { cutIndex++; } RecursiveAction left = new RASort(sortable, start, cutIndex - 1); RecursiveAction right = new RASort(sortable, cutIndex, end); invokeAll(left,right); left.join(); right.join(); } } } Whenever you can split your tasks into subtasks similar to the way it was done in the preceding quick-sort example, I recommend that you use ForkJoinPool as an ExecutorService. You can find good documentation on the API and the use on the JavaDoc documentation of Oracle. Variable access Now that we can start threads and create code that runs parallel, it is time to talk a little bit about how these threads can exchange data between each other. At first glimpse, it seems fairly simple. The threads use the same shared memory; therefore, they all can read and write all the variables that the Java access protection allows them. This is true, except that some threads may just decide not to read the memory. After all, if they have just recently read the value of some variable, why read it again from the memory to the registers if it was not modified? Who would have modified them? Let's see the following short example: package packt.java9.by.example.thread; public class VolatileDemonstration implements Runnable { private Object o = null; private static final Object NON_NULL = new Object(); @Override public void run() { while( o == null ); System.out.println("o is not null"); } public static void main(String[] args) throws InterruptedException { VolatileDemonstration me = new VolatileDemonstration(); new Thread(me).start(); Thread.sleep(1000); me.o = NON_NULL; } } What will happen? You may expect that the code starts up, starts the new thread, and one minute, when the main thread sets the object to something not null, will it stop? It will not. It may stop on some Java implementations, but in most of them, it will just keep spinning. The reason for that is that the JIT compiler optimizes the code. It sees that the loop does nothing and also that the variable will just never be non-null. It is allowed to assume that because the variables not declared volatile are not supposed to be modified by any other thread, the JIT is eligible to optimize. If we declare the Object o variable to be volatile (with the volatile keyword), then the code will stop. In case you try to remove the call to sleep, the code will also stop. This, however, does not fix the issue. The reason is that JIT optimization kicks in only after about 5000 loops of the code execution. Before that, the code runs naive and stops before the optimization will eliminate the extra and regularly not needed access to the non-volatile variable. If this is so gruesome, then why don't we declare all variables to be volatile? Why does Java not do that for us? The answer is speed, and to understand it deeper, we will use our metaphor, the office, and the bureaucrat. The CPU heartbeat These days CPUs run on 2 to 4 GHz frequency processors. It means that a processor gets 2 to 4 times 109 clock signals to do something every second. A processor cannot do any atomic operation faster than this, and also there is no reason to create a clock that is faster than what a processor can follow. It means that a CPU performs a simple operation, such as incrementing a register in half or quarter of a nanosecond. This is the heartbeat of the processor, and if we think of the bureaucrat as humans, who they are, then it is equivalent to one second, approximately, if and as their heartbeat. Processors have registers and caches on the chip on different levels, L1, L2, and sometimes L3; there is memory, SSD, disk, network, and tapes that may be needed to retrieve data. Accessing data that is in the L1 cache is approximately 0.5ns. You can grab a paper that is on your desk— half of a second. L2 cache is 7ns. This is a paper in the drawer. You have to push the chair a bit back, bend it in a sitting position, pull out the drawer, take the paper, push the drawer back, and raise and put the paper on the desk; it takes 10 seconds, give or take. Main memory read is 100ns. The bureaucrat stands up, goes to the shared file at the wall, he waits while other bureaucrats are pulling their papers or putting theirs back, selects the drawer, pulls it out, takes the paper, and walks back to the desk. This is two minutes. This is volatile variable access every time you write a single word on a document and it has to be done twice. Once to read, and once to write, even if you happen to know that the next thing you will do is just fill another field of the form on the same paper. Modern architectures, where there are no multiple CPUs but rather single CPUs with multiple cores, are a bit faster. One core may check the other core's caches to see if there was any modification on the same variable, but this speeds the volatile access to 20ns or so, which is still a magnitude slower than nonvolatile. Although the rest is less focused on multithread programming, it is worth mentioning here, because it gives good understanding on the different time magnitudes. Reading a block from an SSD (4K block usually) is 150,000ns. In human speed, that is a little bit more than 5 days. Reading or sending something to a server over the network on the Gb local Ethernet is 0.5ms, which is like waiting for almost a month for the metaphoric bureaucrat. If the data over the network is on a spinning magnetic disk, then seek time adds up (the time until the disk rotates so that the part of the magnetic surface gets under the reading head) to 20ms. It is, approximately, a year in human terms. If we send a network packet over the Atlantic on the Internet, it is approximately is 150ms. It is like 14 years, and this was only one single package; if we want to send data over the ocean, it may be seconds that count up to historic times, thousands of years. If we count one minute for a machine to boot, it is equivalent to the time span of our whole civilization. We should consider these numbers when we want to understand what the CPU is doing most of the time: it waits. Additionally, it also helps cool your nerves when you think about the speed of a real-life bureaucrat. They are not that slow after all, if we consider their heartbeat, which implies the assumption that they have a heart. However, let's go back to real life, CPUs, and L1, L2 caches and volatile variables. Volatile variables Let's modify the declaration of the o variable in our sample code as follows: private volatile Object o = null; The preceding code runs fine and stops after a second or so. Any Java implementation has to guarantee that multiple threads can access volatile fields and the value of the field is consistently updated. This does not mean that volatile declaration will solve all synchronization issues, but guarantees that the different variables and their value change relations are consistent. For example, let's consider we have the following two fields incremented in a method: private volatile int i=0,j=0; public void method(){ i++; j++; } In the preceding code, reading i and j from another thread will never result an i>j. Without the volatile declaration, the compiler is free to reorganize the execution of the increment operations if it needs and thus, it will not guarantee that an asynchronous thread reads consistent values. Synchronized block Declaring variables are not the only tool to ensure the consistency between threads. There are other tools in the Java language and one of them is the synchronized block. The synchronized keyword is part of the language and it can be used in front of a method or a program block inside a method. Every object in the Java program has a monitor that can be locked and unlocked by any running thread. When a thread locks a monitor, it is said that that thread holds the lock, and no two threads can hold the lock of a monitor at a time. If a thread tries to lock a monitor that is already locked, it gets BLOCKED until the monitor is released. A synchronized block starts with the synchronized keyword, and then an object instance specified between parentheses and the block comes. The following small program demonstrates the synchronized block: public class SynchronizedDemo implements Runnable { public static final int N = 1000; public static final int MAX_TRY = 1_000_000; private final char threadChar; private final StringBuffer sb; public SynchronizedDemo(char threadChar, StringBuffer sb) { this.threadChar = threadChar; this.sb = sb; } @Override public void run() { for (int i = 0; i < N; i++) { synchronized (sb) { sb.append(threadChar); sleep(); sb.append(threadChar); } } } private void sleep() { try { Thread.sleep(1); } catch (InterruptedException ignored) {} } public static void main(String[] args) { boolean failed = false; int tries = 0; while (!failed && tries < MAX_TRY) { tries++; StringBuffer sb = new StringBuffer(4 * N); new Thread(new SynchronizedDemo('a', sb)).start(); new Thread(new SynchronizedDemo('b', sb)).start(); failed = sb.indexOf("aba") != -1 || sb.indexOf("bab") != -1; } System.out.println(failed ? "failed after " + tries + " tries" : "not failed"); } } The code starts two different threads. One of the threads appends aa to the StringBuffer. The other one appends bb. This appending is done in two separate steps with a sleep in between. The sleep is needed to avoid JIT that optimizes the two separate steps into one. Each thread executes the append 1000 times each time appending a or b two times. As the two appends one after the other are inside a synchronized block it cannot happen that an aba or bab sequence gets into the StringBuffer. While one thread executes the synchronized block, the other thread cannot execute it. If I remove the synchronized block, then the JVM I used to test Java HotSpot (TM) 64-Bit Server VM (build 9-ea+121, mixed mode) prints out the failure with a try-count around a few hundreds. It clearly demonstrates what the synchronization means, but it draws our attention to another important phenomena. The error occurs only around every few hundred thousand executions only. It is extremely rare, even though this example was furnished to demonstrate such a mishap. If a bug appears so rare, it is extremely hard to reproduce and, even more, to debug and fix. Most of the synchronization errors manifest in mysterious ways and their fixing usually is the result of meticulous code review rather than debugging. Therefore, it is extremely important to clearly understand the true nature of Java multithread behavior before starting commercial multithread application. The synchronized keyword can also be used in front of a method. In this case, the object to acquire the lock of is the object. In case of a static method, the synchronization is done on the whole class. Wait and notify There are five methods implemented in the class Object that can be used to get further synchronization functionality: wait with three different timeout argument signature, notify, and notifyAll. To call wait, the calling thread should have the lock of the Object on which wait is invoked. It means that you can only invoke wait from inside a synchronized block, and when it is called, the thread gets BLOCKED and releases the lock. When another thread calls notify all on the same Object, the thread gets into the RUNNABLE state. It cannot continue execution immediately as it cannot get the lock on the object. The lock is held at that moment by the thread that just called notifyAll. However, sometime after the other thread releases, the lock gets out of the synchronized block, and the waiting thread continues the execution. If there are more threads waiting on an object, all of them get out of the BLOCKED state. The notify method wakes only one of the waiting threads. There is no guarantee which thread is awakened. The typical use of wait, notify, and notifyAll is when one or more threads are creating Objects that are consumed by other thread, or threads. The storage where the objects travel between the threads is some kind of queue. The consumer waits until there is something to read from the queue, and the producer puts the objects into the queue one after the other. The producer notifies the consumers when it stores something into the queue. If there is no room left in the queue, the producer has to stop and wait until the queue has some space. In this case, the producer calls the wait method. To wake the producer up, the consumer calls notifyAll when it reads something. The consumer consumes the objects from the queue in a loop and calls wait only if there is nothing to be read from the queue. When the producer calls notifyAll, and there is no consumer waiting, the notification is just ignored. It flies away, but this is not a problem; consumers are not waiting. When the consumer consumes an object and calls notifyAll and there is no producer waiting, the situation is the same. It is not a problem. It cannot happen that the consumer consumes, calls notifyAll, and after the notification was flying in the air not finding any waiting producer, a producer starts to wait. This cannot happen because the whole code is in a synchronized block and it ensures that no producer is in the critical section. This is the reason why wait, notify, and notifyAll can only be invoked when the lock of the Object class is acquired. If there are many consumers, which are executing the same code and are equivalently good in consuming the objects, then it is an optimization to call notify instead of notifyAll. In that case, notifyAll will just awake all consumer threads and all, but the lucky one will recognize that they were woken up but somebody else already got away with the bait. I recommend that you practice at least once to implement a blocking queue that can be used to pass Objects between threads. However, never use that code in production: starting with Java 1.5, there are implementations of the BlockingQueue interface. Use one that fits your needs. We will too, in our example code. Feel lucky that you can code in Java 9. I started using Java professionally when it was 1.4 and once I had to implement a blocking queue. Life gets just better and easier all the time with Java. In professional code, we usually avoid using synchronized methods or blocks and volatile fields as well as the wait and notify methods, notifyAll too, if possible. We can use asynchronous communication between threads, or pass the whole multithreading to the framework for handling. Synchronized and volatile cannot be avoided in some special cases when the performance of the code is important, or we cannot find a better construct. Sometimes, the direct synchronization on specific code and data structures is more efficient than the approach delivered by JDK classes. It is to note, however, that those classes also use these lowlevel synchronization constructs, so it is not magic how they work; and to develop yourself, you can look into the code of the JDK classes before you want to implement your own version. You will realize that it is not that simple to implement these queues; the code of the classes is not complex and compound without reason. If you find the code simple, it means that you are senior enough to know what not to reimplement. Or, perhaps, you do not even realize what code you read. Lock s are built in Java; every Object has a lock that a thread may acquire when it enters a synchronized block. We discussed that already. In some programming code, there are situations when this kind of structure is not optimal. Lock In some situations, the structure of locks may be lined up to avoid deadlock. It may be needed to acquire lock A before B and to acquire B before C. However, A should be released as soon as possible, not to prevent access to resource protected by lock D, but also needing lock A before it. In complex and highly parallel structures, the locks are structured many times into trees where accessing a resource a thread should climb down along the tree to a leaf representing the resource. In this climbing, the thread gets hold of a lock on a node, then a lock on a node below it, and then releases the lock above, just like a real climber descending (or climbing up if you imagine the tree with the leafs at the top, which is more realistic, nevertheless graphs usually show trees upside down). You cannot leave a synchronized block remaining in another that is inside the first one. Synchronized blocks are nested. The java.util.concurrent.Lock interface defines methods to handle that situation and the implementations are also there in the JDK to be used in our code. When you have a lock, you can call the methods lock and unlock. The actual order is in your hand and you can write the following line of code to get the locking sequence: a.lock(); b.lock(); a.unlock(); c.lock() The freedom, however, comes with responsibility as well. The locks and unlocks are not tied to the execution sequence of the code, like in case of synchronized block, and it may be very easy to create code that in some case just loses a lock not unlocking it rendering some resource unusable. The situation is similar to a memory leak: you will allocate (lock) something and forget to release (unlock) it. After a while, the program will run out of resource. My personal recommendation is to avoid using locks if possible and use higher-level constructs and asynchronous communications between threads, such as blocking queues. Condition The java.util.concurrent.Condition interface in functionality is similar to the built-in wait, notify, and notifyAll. Any implementation of Lock should create new Condition objects and return as a result to the invocation of the newCondition method. When the thread has a Condition, it can call await, signal, and signalAll when the thread has the lock that created the condition object. The functionality is very similar to the methods of Object mentioned. However, the big difference is that you can create many Condition for a single Lock and they will work independent of each other, but not independent of the Lock. ReentrantLock is the simplest implementation of the interface lock in the JDK. There are two ways to create this type of lock: with and without fairness policy. If the ReentrantLock(Boolean fair) constructor is called with the true argument, then the lock will be assigned to the thread that is waiting for the lock the longest time in case there are many threads waiting. This will avoid a thread made to wait for infinite time and starving. ReentrantLock ReentrantReadWriteLock This class is an implementation of ReadWriteLock. ReadWriteLock is a lock that can be used for parallel read access and exclusive write access. It means that several threads can read the resource protected by the lock, but when a thread writes the resource, no other thread can get access to it, not even read during that period. A ReadWriteLock is simply two Lock objects returned by the readLock and writeLock methods. To get read access on ReadWriteLock, the code has to invoke myLock.readLock().lock(), and to get access to write lock, myLock.writeLock().lock(). Acquiring one of the locks and releasing it in the implementation is coupled with the other lock. To acquire a write lock, no thread should have an active read lock, for example. There are several intricacies in the use of the different lock. For example, you can acquire a read lock, but you cannot get a write lock so long as you have the read lock. You have to release the read lock first to acquire a write lock. This is just one of the simple details, but this is the one that novice programmers have trouble with many times. Why is it implemented this way? Why should the program get a write lock, which is more expensive—in sense of higher probability locking other threads—when it still is not sure that it wants to write the resource? The code wants to read it and. based on the content. it may later decide that it wants to write it. The issue is not with the implementation. The developers of the library decided this rule, not because they just liked it that way or because they were aware of parallel algorithms and deadlock possibilities. When two threads have read lock and each decides to upgrade the lock to write lock, then they would intrinsically create a deadlock. Each would hold the read lock waiting for the write and none of them would get it ever. On the other end, you can downgrade a write lock to a read lock without risking that in the meantime somebody acquires a write lock and modifies the resource. Atomic classes Atomic classes enclose primitive values into objects and provide atomic operations on them. We discussed race conditions and volatile variables. For example, if we have an int variable to be used as a counter and we want to assign a unique value to objects that we work with, we can increment the value and use the result as a unique ID. However, when multiple threads use the same code, we cannot be sure about the value we read after the increment. It may happen that another thread also incremented the value in the meantime. To avoid that, we will have to enclose the increment and the assignment of the incremented value to an object into a synchronized block. This can also be done using AtomicInteger. If we have a variable of AtomicInteger, then calling incrementAndGet increments the value of int enclosed in the class and returns the incremented value. Why do it instead of using synchronized block? The first answer is that if the functionality is there in the JDK, then using it is less line than implementing it again. Developers maintaining the code you create are expected to know the JDK libraries but have to study your code, and this takes time and time is money. The other reason is that these classes are highly optimized and, many times, they implement the features using platform specific native code that greatly over performs the version we can implement using synchronized blocks. Worrying about performance too early is not good, but parallel algorithms and synchronization between threads are usually used when performance is crucial; thus, there is a good chance that the performance of the code using the atomic classes is important. In the java.util.concurrent.atomic package, there are several classes, AtomicInteger, AtomicBoolean, AtomicLong, and AtomicReference among them. They all provide methods that are specific to the encapsulated value. The method, which is implemented by every atomic class, is compareAndSet. This is a conditional valuesetting operation that has the following format: boolean compareAndSet(expectedValue, updateValue); When it is applied on an atomic class, it compares the actual value with the one expectedValue, and if they are the same, then it sets the value to updateValue. If the value was updated, the method returns true and it does all this in an atomic action. You may ask the question that if this method is in all of these classes, why is there no Interface defining this method? The reason for this is that the argument types are different based on the encapsulated type, and these types are primitives. As primitives cannot be used as generic types, not even a generic interface can be defined. In case of AtomicXXXArray, the method has an extra first argument, which is the index of the array element handled in the call. The variables encapsulated are handled the same way as volatile, as far as the reordering is concerned, but there are special methods that loosen the conditions a bit to be used when possible, and performance is key. The general advice is to consider using atomic classes, if there is one usable, and you will find yourself creating a synchronized block for check-and-set, atomic increment, or addition operations. BlockingQueue is an interface that extends the standard Queue interface with methods that are suitable to be used by multithread applications. Any implementation of this interface provides methods that allow different threads to put element into the queue, pull elements off the queue, and wait for elements that are in the queue. BlockingQueue When there is a new element that is to be stored in the queue, you can add it, offer it, or put it. These are the name of the methods that store elements and they do the same thing, but a bit differently. The add element throws an exception if the queue is full and there is no room for the element. The offer element does not throw exception but returns either true or false, based on the success. If it can store the element in the queue, it returns true. There is also a version of offer that specifies a timeout. That version of the method waits, and returns only false if it cannot store the value into the queue during the period. The put element is the dumbest version; it waits until it can do its job. When talking about available room in a queue, do not get puzzled and mix it with general Java memory management. If there is no more memory, and the garbage collector can also not release any, you will certainly get OutOfMemoryError. Exception is thrown by add, and false is returned by offer, when the queue limits are reached. Some of the BlockingQueue implementations can limit the number of elements that can be stored at a time in a queue. If that limit is reached, then the queue is full and cannot accept more elements. Fetching elements from a BlockingQueue implementation also has four different ways. In this direction, the special case is when the queue is empty. In that case, remove throws an exception instead of returning the element, poll returns null if there is no element, and take just waits until it can return an element. Finally, there are two methods inherited from the interface Queues that do not consume the element from the queue only look at. The element return the head of the queue and throws an exception if the queue is empty, and peek returns null if there is no element in the queue. The following table summarizes the operations borrowed from the documentation of the interface: Throws exception Special value Blocks Times out Insert add(e) offer(e) put(e) offer(e, time, unit) Remove remove() poll() take() poll(time, unit) Examine element() peek() not applicable not applicable LinkedBlockingQueue This is an implementation of the BlockingQueue interface, which is backed up by a linked list. The size of the queue is not limited by default (to be precise, it is Integer.MAX_VALUE) but it can optionally be limited in a constructor argument. The reason to limit the size in this implementation is to aid the use when the parallel algorithm performs better with limited size queue, but the implementation does not have any restriction on the size. LinkedBlockingDeque This is the simplest implementation of the BlockingQueue and also its subinterface BlockingDeque. As we discussed in the previous chapter, a Deque is a double-ended queue that has add, remove, offer, and so on, type of methods in the form of xxxFirst and xxxLast to do the act with one or the other end of the queue. The Deque interface defines getFirst and getLast instead of consistently naming elementFirst and elementLast, so this is something you should get used to. After all, the IDEs help with automatic code completion so this should not be a really big problem. ArrayBlockingQueue implements the BlockingQueue interface, hence the Queue interface. This implementation manages a queue with fixed size elements. The storage in the implementation is an array and the elements are handled in a FIFO manner: first-in first-out. This is the class that we will also use in the parallel implementation of Mastermind for the communication between the boss and the subordinated bureaucrats. ArrayBlockingQueue LinkedTransferQueue The TransferQueue interface is extending BlockingQueue and the only implementation of it in the JDK is LinkedTransferQueue. A TransferQueue comes handy when a thread wants to hand over some data to another thread and needs to be sure that some other thread takes the element. This TransferQueue has a method transfer that puts an element on the queue but does not return until some other thread removes (or polls) it. That way the producing thread can be sure that the object put on the queue is in the hands of another processing thread and does not wait in the queue. The method transfer also has a format tryTransfer in which you can specify some timeout value. If the method times out the element is not put into the queue. IntervalGuesser We discussed the different Java language elements and JDK classes that are all available to implement parallel algorithms. Now, we will see how to use these approaches to implement the parallel guesser for the Masterrmind game. The class that performs the creation of the guesses is named IntervalGuesser. It creates the guesses between a start and an end guess and sends them to a BlockingQueue. The class implements Runnable so it can run in a separate Thread. The purist implementation will separate the Runnable functionality from the interval guessing, but as the whole class is hardly more than 50 lines, it is forgivable sin implementing the two functionalities in a single class. public class private private private private IntervalGuesser extends UniqueGuesser implements Runnable { final Guess start; final Guess end; Guess lastGuess; final BlockingQueue<Guess> guessQueue; public IntervalGuesser(Table table, Guess start, Guess end, BlockingQueue<Guess> guessQueue) { super(table); this.start = start; this.end = end; this.lastGuess = start; this.guessQueue = guessQueue; nextGuess = start; } @Override public void run() { Guess guess = guess(); try { while (guess != Guess.none) { guessQueue.put(guess); guess = guess(); } } catch (InterruptedException ignored) { } } @Override protected Guess nextGuess() { Guess guess; guess = super.nextGuess(); if (guess.equals(end)) { guess = Guess.none; } lastGuess = guess; return guess; } public String toString() { return "[" + start + "," + end + "]"; } } The implementation is very simple as most of the functionality is already implemented in the abstract Guesser class. The more interesting code is the one that invoked the IntervalGuesser. ParallelGamePlayer The ParallelGamePlayer class implements the Player interface that defines the play method: @Override public void play() { Table table = new Table(NR_COLUMNS, manager); Secret secret = new RandomSecret(manager); Guess secretGuess = secret.createSecret(NR_COLUMNS); Game game = new Game(table, secretGuess); final IntervalGuesser[] guessers = createGuessers(table); startAsynchronousGuessers(guessers); final Guesser finalCheckGuesser = new UniqueGuesser(table); try { while (!game.isFinished()) { final Guess guess = guessQueue.take(); if (finalCheckGuesser.guessMatch(guess)) { game.addNewGuess(guess); } } } catch (InterruptedException ie) { } finally { stopAsynchronousGuessers(guessers); } } This method creates a Table, a RandomSecret that creates the guess used as a secret in a random way, a Game object, IntervalGuessers, and a UniqueGuesser. The IntervalGuessers are the bureaucrats; the UniqueGuesser is the boss who crosschecks the guesses that the IntervalGuessers create. The method starts off the asynchronous guessers and then reads the guesses in a loop from them and puts them on the table if they are OK until the game finishes. At the end of the method, in the finally block, the asynchronous guessers are stopped. The start and the stop method for the asynchronous guessers use ExecutorService. private ExecutorService executorService; private void startAsynchronousGuessers( IntervalGuesser[] guessers) { executorService = Executors.newFixedThreadPool(nrThreads); for (IntervalGuesser guesser : guessers) { executorService.execute(guesser); } } private void stopAsynchronousGuessers( IntervalGuesser[] guessers) { executorService.shutdown(); guessQueue.drainTo(new LinkedList<>()); } The code is quite straightforward. The only thing that may need mention is that the queue of the guesses is drained into a collection that we do not use afterward. This is needed to help any IntervalGuesser that is waiting with a suggested guess in hand, trying to put it into the queue. When we drain the queue, the guesser thread returns from the method put in the guessQueue.put(guess); line in IntervalGuesser and can catch the interrupt. The rest of the code does not contain anything that would be radically different from what we have already seen and you can find it on GitHub. The last question that we still want to discuss in this chapter is how much speed did we gain making the code parallel? Microbenchmarking Microbenchmarking is measuring the performance of a small code fragment. When we want to optimize our code, we will have to measure it. Without measurement, code optimization is like shooting blindfolded. You will not hit the target, but you likely will shoot somebody else. Shooting is a good metaphor because you should usually not do it, but when you really have to then you have no choice. If there is no performance issue and the software meets the requirements, then any optimization, including speed measurement, is a waste of money. This does not mean that you are encouraged to write slow and sloppy code. When we measure performance, we will compare it against a requirement, and the requirement is usually on the user level. Something like, the response time of the application should be less than 2 seconds. To do such a measurement, we usually create load tests in a test environment and use different profiling tools that tell us what is consuming the most time and where we should optimize. Many times, it is not only Java code, but configuration optimization, using larger database connection pool, more memory, and similar things. Microbenchmarking is a different story. It is about the performance of a small Java code fragment and, as such, closer to the Java programming. It is rarely used, and before starting to do a microbenchmark for real commercial environment, we will have to think twice. Microbenchmark is a luring tool to optimize something small without knowing if it is worth optimizing that code. When we have a huge application that has several modules run on several servers, how can we be sure that improving some special part of the application drastically improves the performance? Will it pay back in increased revenue that generates so much profit that will cover the cost we burned into the performance testing and development? Statistically, almost sure that such an optimization including microbenchmarking will not pay off. Once I was maintaining the code of a senior's colleague. He created a highly optimized code to recognize configuration keywords that were present in a file. He created a program structure that represented a decision tree based on the characters in the key string. If there was a keyword in the configuration file that was misspelled, the code threw an exception at the very first character where it could decide that the keyword could not be correct. To insert a new keyword, it needed to get through the code structure to find the occasion in the code where the new keyword was first different from already existing ones and extend the deeply nested if/else structures. To read the list of the handled keywords was possible from the comments that listed all the keywords that he did not forget to document. The code was working blazingly fast, probably saving a few milliseconds of the servlet application startup time. The application was started up only after system maintenance every few month. You feel the irony, don't you? Seniority is not always the number of years. Lucky ones can save their inner child. So when to use microbenchmarking? I can see two areas: You identified the code segment that eats most of the resources in your application and the improvement can be tested by microbenchmarks You cannot identify the code segment that will eat most of the resources in an application but you suspect it The first is the usual case. The second is when you develop a library, and you just do not know all the applications that will use it. In this case, you will try to optimize the part that you think is the most crucial for most of the imagined, suspected applications. Even in that case, it is better to take some sample applications that are created by users of your library and collect some statistics about the use. Why should we talk about microbenchmarking in details? What are the pitfalls? Benchmarking is an experiment. The first programs I wrote was a TI calculator code and I can just count the number of steps the program made to factor two large (10 digits those days) prime numbers. Even at that time, I was using an old Russian stopwatch to measure the time, being lazy to calculate the number of steps. Experiment and measurement was easier. Today, you cannot calculate the number of steps the CPU makes even if you wanted. There are so many small factors that may change the performance of the applications that are out of control of the programmer, which makes it impossible to calculate the steps. We have the measurement left for us, and we will gain all the problems of measurements. What is the biggest problem? We are interested in something, say X, and we usually cannot measure that. So, we will measure Y instead and hope that the values of Y and X are coupled together. We want to measure the length of the room, but instead we measure the time it takes for the laser beam to travel from one end to the other. In this case, the length X and the time Y are strongly coupled. Many times, X and Y only correlate more or less. Most of the times, when people do measurement, the X and Y values have no relation to each other at all. Still, people put their money and more on decisions backed by such measurements. Microbenchmarking is no different. The first question is how to measure the execution time? Small code runs short times and System.currentTimeMillis() may just return the same value when the measurement starts and when it ends, because we are still in the same millisecond. Even if the execution is 10ms, the error of the measurement is still at least 10% purely because of the quantization of the time as we measure. Luckily, there is System.nanoTime(). But is there? Just because the name says it returns the number of nanoseconds from a specific start time, it does not necessarily mean it really can. It very much depends on the hardware and the implementation of the method in the JDK. It is called nano because this is the precision that we cannot certainly reach. If it was microseconds, then some implementation may be limited by the definition, even if on the specific hardware, there is a more precise clock. However, this is not only the precision of an available hardware clock; it is about the precision of the hardware. Let's remember the heartbeat of the bureaucrats, and the time needed to read something from memory. Calling a method, such as System.nanoTime(), is like asking the bellboy in a hotel to run down from the second floor to the lobby and peek out to look at the clock on the tower on the other side of the road, come back, and tell seconds precision what the time was it when we asked. Nonsense. We should know the precision of the clock on the tower and the speed of the bellboy running from the floor to the lobby and back. This is a bit more than just calling nanoTime. This is what a microbenchmarking harness does for us. The Java Microbenchmarking Harness (JMH) is available for some time as a library. It is developed by Oracle and used to tune the performance of some core JDK classes, and with Java 9, these performance measurements and results become part of the distributed JDK. This is good news for those who develop Java platform for new hardware, but also for developers, because it means that the JMH is and will be supported by Oracle. "JMH is a Java harness to build, run, and analyze nano/micro/milli/macro benchmarks written in Java and other languages targeting the JVM." (quote from the official site of JMH, http://openjdk.java.net/projects/cod e-tools/jmh/). You can run jmh as a separate project independent from the actual project you measure, or you can just store the measurement code in a separate directory. The harness will compile against the production class files and will execute the benchmark. The easiest way, as I see, is to use the Gradle plugin to execute JMH. You can store the benchmark code in a directory called jmh (the same level as main and test) and create a main that can start the benchmark. The Gradle build script is extended with the following lines: buildscript { repositories { jcenter() } dependencies { classpath "me.champeau.gradle:jmh-gradle-plugin:0.2.0" } } apply plugin: "me.champeau.gradle.jmh" jmh { jmhVersion = '1.13' includeTests = true } And the microbenchmark class is as follows: public class MicroBenchmark { public static void main(String... args) throws IOException, RunnerException { Options opt = new OptionsBuilder() .include(MicroBenchmark.class.getSimpleName()) .forks(1) .build(); new Runner(opt).run(); } @State(Scope.Benchmark) public static class ThreadsAndQueueSizes { @Param(value = {"1", "4", "8"}) String nrThreads; @Param(value = { "-1","1", "10", "100", "1000000"}) String queueSize; } @Benchmark @Fork(1) public void playParallel(ThreadsAndQueueSizes t3qs) throws InterruptedException { int nrThreads = Integer.valueOf(t3qs.nrThreads); int queueSize = Integer.valueOf(t3qs.queueSize); new ParallelGamePlayer(nrThreads, queueSize).play(); } @Benchmark @Fork(1) public void playSimple(){ new SimpleGamePlayer().play(); } } is created to play the game with -1, 1, 4, and 8 IntervalGuesser threads, and in each case, there is a test running with a queue of length 1, 10, 100, and 1 million. These are 16 test executions. When the number of threads is negative, then the constructor uses LinkedBlockingDeque. There is another separate measurement that measures the nonparallel player. The test was executed with unique guesses and secrets (no color used more than once) and ten colors and six columns. ParallelGamePlayer When the harness starts, it does all the calibrations automatically and runs the tests for many iterations to let the JVM start up. You may recall the code that just never stopped unless we used the volatile modifier in for the variable that was used to signal the code to stop. That happened because the JIT compiler optimized the code. This is done only when the code was already run a few thousand times. The harness makes these executions to warm up the code and ensure that the measurement is done when JVM is at full speed. Running this benchmark takes approximately 15 minutes on my machine. During the execution, it is recommended to stop all other processes and let the benchmark use all available resources. If there is anything using resources during the measurement, then it will be reflected in the result. Benchmark playParallel playParallel playParallel playParallel playParallel playParallel playParallel playParallel playParallel playParallel playParallel playParallel playParallel playParallel playParallel playSimple (nrThreads) 1 1 1 1 1 4 4 4 4 4 8 8 8 8 8 N/A (queueSize) -1 1 10 100 1000000 -1 1 10 100 1000000 -1 1 10 100 1000000 N/A Score 15,636 15,316 15,425 16,580 15,035 25,945 25,559 25,034 24,971 20,584 24,713 24,265 24,475 24,514 16,595 18,613 Error &pm; 1,905 &pm; 1,237 &pm; 1,673 &pm; 1,133 &pm; 1,148 &pm; 0,939 &pm; 1,250 &pm; 1,414 &pm; 1,010 &pm; 0,655 &pm; 0,687 &pm; 1,022 &pm; 1,137 &pm; 0,836 &pm; 0,739 &pm; 2,040 The actual output of the program is a bit more verbose; it was edited for printing purposes. The Score column shows how many times the benchmark can run in a second. The Error shows that the measurement shows less than 10% scattering. The fastest performance we have is when the algorithm runs on eight threads, which is the number of threads the processor can independently handle on my machine. It is interesting that limiting the size of the queue did not help the performance. I actually expected it to be different. Using a one million length array as a blocking queue has a huge overhead and this is not a surprise that, in this case, the execution is slower than when we have only 100 elements in the queue. The unlimited linked list-based queue handling, on the other hand, fairly fast and clearly shows that the extra speed at the limited queue for 100 elements does not come from the fact that the limit does not allow the IntervalThreads to run too far. When we start one thread, then we expect similar results, as when we run the serial algorithm. The fact that the serial algorithm beats the parallel algorithm running on one thread is not a surprise. The thread creation and the communication between the main thread and the extra one thread have overhead. The overhead is significant, especially when the queue is unnecessarily large. Summary In this chapter, you learned a lot of things. First of all, we refactored the code to be ready for further development that uses parallel guessing. We got acquainted with processes and threads, and we even mentioned fibers. After that, we looked at how Java implements threads and how to create code that runs on multiple threads. Additionally, we saw the different means that Java provides to programmers needing parallel programs, starting threads, or just starting some tasks in already existing threads. Perhaps the most important part of this chapter that you should remember is the metaphor of bureaucrats and the different speeds. This is extremely important when you want to understand the performance of concurrent applications. And I hope that this is a catchy picture, which is easy to remember. There was a huge topic about the different synchronization means that Java provides, and you have also learned about the pitfalls that programmers can fall into when programming concurrent applications. Last but not least, we created the concurrent version of the Mastermind guesser and also measured that it is indeed faster than the version that uses only one processor (at least on my machine). We used the Java Microbenchmark Harness with the Gradle build tool and discussed, a bit, how to perform microbenchmarking. This was a long chapter and not an easy one. I may tend to think that this is the most complex and most theoretical one. If you understood half of it at first read, you can be proud. On the other hand, be aware that this is only a good base to start experimenting with concurrent programming and there is a long way to being senior and professional in this area. And, it is not an easy one. But first of all, be proud of yourself at the end of this chapter. In the following chapters we will learn more about web and web programming. In the very next chapter we will develop our little game so that it can run in a server and the player can play with it using a web browser. This will establish the basic knowledge for web programming. Later we will build on this developing web based service applications, reactive programming and all the tools and areas that will make a professional Java developer. Making Our Game Professional - Do it as a Webapp In this chapter, we will program a web application. We will build on what we have achieved already and create a web version of the Mastermind game. This time, it will not only run alone, guessing and answering the number of positions and matched colors, but also communicate with the user asking for the answers to the guesses. This will be a real game. Web programming is extremely important for Java programmers. Most of the programs are web applications. The universal client available on the Internet is the web browser. The thin-client, web browser-based architecture is widely accepted in enterprises as well. There are only some exceptions when the architecture has something else but the web client. If you want to become a professional Java developer, you must be familiar with web programming. And it is also fun! There are a lot of technical topics that we will visit during the development. First of all, we will discuss networking and web architecture. This is the concrete base of the whole building. It is not too sexy, just like when you construct the building. You spend a lot of money and effort digging trenches, and then you bury the concrete and end up at the end of the phase with what you seemingly had before: flat ground. Except that there is the base. Building without this base, the house would either collapse soon after or during the process of building. Networking is just as important for web programming. There are a lot of topics that seemingly have nothing to do with programming. Still, it is the base of the building and when you program web applications, you will also find the fun part in it. We will also talk a bit about HTML, CSS, and JavaScript, but not too much. We cannot avoid them because they are also important for web programming, but they are topics that you can learn from somewhere else as well. In case you are not an expert in some of these areas, there are usually other experts in enterprise project teams who can extend your knowledge. (In the case of networking, there is no mercy.) In addition to that, JavaScript is a topic so complex and huge that it deserves a whole book to start with it. There are only very few experts who deeply understand both Java and JavaScript. I understand the general structure of the language and the environment it runs in, but I cannot keep up with the new frameworks that are released every week these days, having my focus on other areas. You will learn how to create Java applications that run in an application server, this time in Jetty, and we will see what a servlet is. We will create a web hello world application to start up fast, and then we will create the servlet version of Mastermind. Note that we hardly ever program servlets directly without the aid of some framework that implements the code to handle parameters, authentication, and many other things that are not application-specific. We will still stick to a naked servlet in this chapter because it is not possible to effectively use frameworks, such as Spring, without first understanding what a servlet is. Spring will come in the next chapter. We will mention Java Server Pages (JSP) only because you may meet some legacy application, which was developed using that technology, but modern web applications do not use JSP. Still, JSP is a part of the servlet standard and is available for use. There are other technologies that were developed in the recent past but do not seem to be future-proof these days. They are still usable but appear only in legacy applications, and choosing them for a new project is fairly questionable. We will talk about these technologies shortly in a separate section. By the end of this chapter, you will understand how the basic web technology works and what the major architectural elements are, and you will be able to create simple web applications. This is not enough to be a professional Java web developer but will be a good grounding for the next chapter, where we will have a look at the professional frameworks used in today's enterprises for real application developments. Web and network Programs run on computers, and computers are connected to the Internet. This network was developed in the last 60 years, first to provide military data communication that is resilient to rocket attack, then it was extended to be an academic network, and later it became a commercial network used by anyone and available almost ubiquitously all over the Earth. The design of the network, and the research, started as a response to the flight of Gagarin over the Earth in the fifties. Sending Gagarin to space and travelling over the Earth was a demonstration that Russia could send a rocket anywhere on the globe, possibly with atomic explosives. It meant that any data network that needed some central control was not resilient to such an attack. It was not feasible to have a network with a central location as a single point of failure. Therefore, research was started to create a network that goes on working even if any part of it is brought down. IP The network delivers data packets between any two computers connected to it. The protocol used on the network is IP, which is simply an abbreviation of Internet Protocol. Using IP, a computer can send a data packet to another. The package contains a header and the data content. The header contains the Internet addresses of the sender and the target machine, other flags, and information about the package. Since the machines are not connected to each other directly, routers forward the packets. It is like post offices sending mails to each other till it gets into the hands of the postman you know, who can directly deliver it to your mailbox. To do that, the routers use the information in the header. The algorithm and organization of how the routers interact are complex and something we need not know to be Java professionals. If you ever need to program in order to send IP packets directly, you should look at java.net.DatagramPacket, and the rest is implemented in the JDK, the operating system, and on the firmware of the network card. You can create a data packet; sending it and changing the modulated voltage on the network card or emitting photons to the fiber is not your headache. However, you will all know whether you really need to program datagrams directly. IP has two versions. The old version still in use is IPv4. The new version that coexists with the old one is IPv6 or IPng (ng stands for new generation). The major difference that may concern a Java developer is that version 4 uses 32-bit addresses and version 6 uses 128-bit addresses. When you see a version-4 address, you will see something like 192.168.1.110, which contains the four bytes in a decimal format separated by dots. IPv6 addresses are expressed as 2001:db8:0:0:0:0:2:1, as eight 16-bit numbers expressed in hexadecimal separated by colons. The Web is a bit more complex than sending data packets. If sending a data packet is like sending a onepage letter, then a web page download is like discussing a contract in paper mail. There should be an agreement in the initial paper mail as to what to send, what to answer, and so on, until the contract is signed. On the Internet, that protocol is called Transmission Control Protocol (TCP). While it is highly unlikely (but possible) that you will meet IP routing issues, being a Java developer, you certainly may meet TCP programming. Therefore, we will cover shortly how the TCP works. Be aware that this is very brief. Really. You will not become a TCP expert reading the next section, but you will get a glimpse of the most important issues that affect web programming. TCP/IP The TCP protocol is implemented in the operating system and provides a higher level of interface than IP. When you program TCP, you do not deal with datagrams. Instead, you have a channel of byte streams where you can put bytes to be delivered to the other computer, and you can read bytes from the channel that were sent by the other computer, exactly in the order as they were sent. This is a kind of connection between two computers and, what's more, between two programs. There are other protocols that are implemented over IP and which are not connectionoriented. One of them is User Datagram Protocol (UDP), used for services when there is no need for connections, when the data may be lost and it is more important that the data gets to the destination in a timely manner than losing some of the packets (video streaming, telephony). When the data amount is small and in case it is not delivered, it can be requested again; the cost of losing it is cheap (DNS request, see the next section). When a packet is lost on the network, or when it is sent twice, or when it is delivered sooner than a later package, it is handled by the TCP software layer implemented by the operating system. This layer is also popularly called the TCP stack. Since the TCP is a connected protocol, there is a need for something that tells the TCP stack which stream a datagram belongs to when it arrives. The stream is identified by two ports. A port is a 16-bit integer. One identifies the program that initiates the connection, called the source port. The other one identifies the target program: the destination port. These are contained in each and every TCP packet delivered. When a machine runs a Secure Shell (SSH) server and a web server, they use different ports, usually port 22 and 80. When a package comes that contains the destination port number 22 in the TCP header, the TCP stack knows that the data in the packet belongs to the stream handled by the SSH server. Likewise, if the destination port is 80, then the data goes to the web server. When we program a server, we usually have to define the port number; otherwise, there is no way the clients will find the server program. Web servers are usually listen on port 80, and clients try to connect to that port. The client port is usually not important and not specified; it is allocated by the TCP stack automatically. To connect from a client code to a server is easy: only a few lines of code. Sometimes, it is only one line of code. However, under the hood, there is a lot of work that the TCP stack does that we should care about—it takes time to build up a TCP connection. To have a connection, the TCP stack has to send a datagram to the destination to know that it exists. If there is no server listening on the port, sending the data over the network has no result, except for wasting the network bandwidth. For this reason, the client first sends an empty data packet called SYN. When the other side receives it, it sends back a similar package called SYN-ACK. Finally, the client sends a package called ACK. If the packets go through the Atlantic, this is approximately 45ms for each package, which is equivalent to 45 million seconds in bureaucrat time. This is almost one and a half years. We need three of those to set up the connection, and there is more. When a TCP connection starts, the client does not start to send the data without control. It sends some data packets and then it waits for the server to acknowledge their receipt. It would not only be useless, but also network wasting, to send data that the server is not prepared to accept and has to throw away. The TCP is designed to optimize the network usage. Therefore, the client sends some data, and then it waits for the acknowledgement. The TCP stack automatically manages this. If the acknowledgement arrives, it sends more packets, and if a carefully designed optimization algorithm, implemented in the TCP stack, believes that it is good to send more, it will send a bit more data than in the first step. If there are negative acknowledgements telling the client that the server could not accept some of the data and had to throw it away, then the client will lower the number of packets it sends without acknowledgement. But first it starts slow and cautious. This is called TCP slow start and we have to be aware of it. Although it is a low level networking feature it has consequences that we have to consider in our Java code: we use database connection pools instead of creating a new connection to the database each time there is a need for some data; we try to manage to have as few connections to web servers as possible using techniques such as keep-alive, SPDY protocol, or http/2.0 (also replacing SPDY). For a start, it is enough that TCP is connection-oriented where you build up a connection to a server, send and receive bytes, and finally close the connection. When you have a network performance problem, you have to look at the issues I listed. DNS The TCP protocol creates a channel using the IP addresses of machines. When you type a URL in the browser, it usually does not contain IP numbers. It contains machine names. The name is converted to IP numbers using a distributed database called Domain Name System (DNS). This database is distributed, and when a program needs to convert a name to an address, it sends DNS request to one of the DNS servers it knows. These servers query each other or tell the client whom to ask, until the client knows the IP address assigned to the name. The servers and the client also cache the recently requested names, so answering is fast. On the other hand, when the IP address of a server changes this name, not all clients will immediately see the address assignment over the globe. The DNS lookup can be easily programmed, and there are classes and methods in JDK that support this, but usually we need not care about that; when we program, it is done automatically in web programming. The HTTP protocol The Hypertext Transport Protocol (HTTP) is built on top of the TCP. When you type a URL in a browser, the browser opens a TCP channel to the server (after DNS lookup, of course) and sends a HTTP request to the web server. The server, after receiving the request, produces a response and sends it to the client. After that, the TCP channel may be closed or kept alive for further HTTP request-response pairs. Both the request and the response contain a header and an optional (possibly zero-length) body. The header is in the text format, and it is separated from the body by an empty line. More precisely the header and the body are separated by four bytes: 0x0D, 0x0A, 0x0D, and 0x0A, which are two CR, LF line separators. The HTTP protocol uses carriage return and line feed to terminate lines in the header, and thus, an empty line is two CRLF following each other. The start of the header is a status line plus header fields. The following is a sample HTTP request: GET /html/rfc7230 HTTP/1.1 Host: tools.ietf.org Connection: keep-alive Pragma: no-cache Cache-Control: no-cache Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 DNT: 1 Referer: https://en.wikipedia.org/ Accept-Encoding: gzip, deflate, sdch, br Accept-Language: en,hu;q=0.8,en-US;q=0.6,de;q=0.4,en-GB;q=0.2 The following is the response: HTTP/1.1 200 OK Date: Tue, 04 Oct 2016 13:06:51 GMT Server: Apache/2.2.22 (Debian) Content-Location: rfc7230.html Vary: negotiate,Accept-Encoding TCN: choice Last-Modified: Sun, 02 Oct 2016 07:11:54 GMT ETag: "225d69b-418c0-53ddc8ad0a7b4;53e09bba89b1f" Accept-Ranges: bytes Cache-Control: max-age=604800 Expires: Tue, 11 Oct 2016 13:06:51 GMT Content-Encoding: gzip Strict-Transport-Security: max-age=3600 X-Frame-Options: SAMEORIGIN X-Xss-Protection: 1; mode=block X-Content-Type-Options: nosniff Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html; charset=UTF-8 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head profile="http://dublincore.org/documents/2008/08/04/dc-html/"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="robots" content="index,follow" /> The request does not contain a body. The status line is as follows: GET /html/rfc7230 HTTP/1.1 It contains the so-called method of the request, the object that is requested, and the protocol version used by the request. The rest of the request of the header contains header fields that have the format, label : value. Some of the lines are wrapped in the printed version, but there is no line break in a header line. The response specifies the protocol it uses (usually the same as the request), the status code, and the message format of the status: HTTP/1.1 200 OK After this, the response fields come with the same syntax as in the request. One important header is the content type: Content-Type: text/html; charset=UTF-8 It specifies that the response body (truncated in the printout) is HTML text. The actual request was sent to the URL, https://tools.ietf.org/html/rfc7230, which is the standard that defines the 1.1 version of HTTP. You can easily look into the communication yourself, starting up the browser and opening the developer tools. Such a tool is built into every browser these days. You can use it to debug the program behavior on the network application level looking at the actual HTTP requests and responses on the byte level. The following screenshot shows how the developer tool shows this communication: HTTP methods The method that is the first word in the status line of the request tells the server what to do with the request. The standard defines different methods, such as GET, HEAD, POST, PUT, DELETE, and some others. The client uses the GET method when it wants to get the content of a resource. In the case of a GET request, the body of the request is empty. This is the method used by the browser when we download a web page. It is also, many times, the method used when some program implemented in JavaScript and running in the browser asks for some information from a web application, but it does not want to send much information to the server. When the client uses POST, the intention is usually to send some data to the server. The server does reply and, many times, there is also a body in the reply, but the main purpose of the request/reply communication is to send some information from the client to the server. This is the opposite of the GET method in some sense. The GET and POST methods are the most frequently used methods. Although there is a general guideline to use GET to retrieve data and POST to send data to the server, it is only a recommendation, and there is no clean separation of the two cases. Many times, GET is used to send some data to the server. After all, it is an HTTP request with a status line and header fields, and although there is no body in the request, the object (part of the URL) that follows the method in the status line is still able to deliver parameters. Many times, it is also easy to test a service that responds to a GET request because you only need a browser and to type in the URL with the parameters, and look at the response in the browser developer tools. You should not be surprised if you see an application that uses GET requests to execute operations that modify the state on a web server. However, not being surprised does not mean approval. You should be aware that in most cases, these are not good practices. When we send sensitive information using the GET request, the parameters in the URL are available to the client in the address line of the browser. When we send using POST, the parameters are still reachable by the client (after all, the information the client sends is generated by the client and, as such, cannot be unavailable), but not that easy for a simple securityunaware user to copy-paste the information and send, perhaps, to a malevolent third party. The decision between using GET and POST should always consider practicalities and security issues. The HEAD method is identical to a GET request, but the response will not contain a body. This is used when the client is not interested in the actual response. It may happen that the client already has the object and wants to see if it was changed. The Last-Modified header will contain the time when the resource was last changed, and the client can decide if it has a newer one or needs to ask for the resource in a new request. The PUT method is used when the client wants to store something on the server and DELETE when the client wants to erase some resource. These methods are used only by applications usually written in JavaScript and not directly by the browser. There are other methods defined in the standard, but these are the most important and frequently used ones. Status codes The response starts with the status code. These codes are also defined and there are a limited number of codes usable in a response. The most important is 200, which says all is OK; the response contains what the request wanted. The codes are always in the range of 100 to 599, contain three digits, and are grouped by the first digit. : These codes are information codes. They are rarely used but can be very important in some cases. For example, 100 means continue. A server can send this code when it gets a POST request and the server wants to signal the client to send the body of the request because it can process it. Using this code, and the client waiting for this code, may save a lot of bandwidth if properly implemented on the server and also on the client. 2xx: These codes mean success. The request is answered properly, or the requested service was done. There are codes, such as 200, 201, 202, and so on, defined in the standard and there is a description about when to use one or the other. 3xx: These codes mean redirection. One of these codes is sent when the server cannot directly service the request but knows the URL that can. The actual codes can distinguish between a permanent redirect (when it is known that all future requests should be sent to the new URL) and temporary redirect (when any later request should be sent here and possibly served or redirected), but the decision is kept on the server side. 4xx: These are error codes. The most famous code is 404, which means Not Found, that is, the server is not able to respond to the request because the resource is not found. 401 means that the resource to serve the request may be available but it requires authentication. 403 is a code that signals that the request was valid but is still refused to be served by the server. 5xx: These codes are server error codes. When a response holds one of these error codes, the meaning is that there is some error on the server. This error can be temporary, for example, when the server is processing too many requests and cannot respond to a new request with a calculationintensive response (this is usually signaled by error code 503) or when the feature is not implemented (code 501). The general error code 500 is interpreted as Internal Error, which means that no information, whatsoever, is available about what was going wrong on the server, but it was not going well and hence, no meaningful response. 1xx HTTP/2.0 After almost 20 years since the last release of HTTP, the new version of HTTP was released in 2015. This new version of the protocol has several enhancements over the previous versions. Some of these enhancements will also affect the way server applications will be developed. The first and most important enhancement is that the new protocol will make it possible to send several resources parallelly in a single TCP connection. The keep-alive flag is available to avoid the recreation of the TCP channel, but it does not help when a response is created slowly. In the new protocol, other resources can also be delivered in the same TCP channel even before one request is fully served. This requires complex package handling in the protocol, but this is hidden from the server application programmer as well as the browser programmer. The application server, servlet container, and browser implement this transparently. HTTP/2.0 will always be encrypted, therefore it will not be possible to use http as a protocol in the browser URL. It will always be https. The feature that will need changes in servlet programming to leverage the advantages of the new version of the protocol is server push. Version 4.0 of the servlet specification includes support for HTTP/2.0, and this version is still in draft. Server push is an HTTP response to a request that will come in the future. How can a server answer a request that is not even issued? Well, the server anticipates. For example, the application sends an HTML page that has references to many small pictures and icons. The client downloads the HTML page, builds the DOM structure, analyzes it, and realizes that the pictures are needed, and sends the request for the pictures. The application programmer knows what pictures are there and may code the server to send the pictures even before the browser requests for it. Every such response includes a URL that this response is for. When the browser wants the resource, it realizes that it is already there and does not issue a new request. In HttpServlet, the program should access PushBuilder via the request's new getPushBuilder method and use that to push down resources to the client. Cookies Cookies are maintained by the browser and are sent in the HTTP request header using the Cookie header field. Each cookie has a name, value, domain, path, expiration time, and some other parameters. When a request is sent to a URL that matches the domain, the path of a non-expired cookie, the client sends the cookie to the server. Cookies are usually stored in small files on the client by the browser or in a local database. The actual implementation is the business of the browser, and we need not worry about it. It is just the text information that is not executed by the client. It is only sent back to the server when some rules (mainly domain and path) match. Cookies are created by servers and are sent to the client in HTTP responses using the Set-Cookie header field. Thus, essentially the server tells the client, Hey, here is this cookie, whenever you come to me next time, show me this piece of information, so I will know it is you. Cookies are usually to remember clients. Advertisers and online shops that need to remember who they are talking to heavily use it. But this is not the only use. These days, any application that maintains user sessions uses cookies to chain up the HTTP requests that come from the same user. When you log in to an application, the username and password you use to identify yourself are sent to the server only once, and in subsequent requests, only a special cookie is sent to the server used to identify the already logged in user. This use of cookies emphasizes why it is important to use cookie values that cannot be easily guessed. If the cookie used to identify a user is easily guessable, then an attacker could just create a cookie and send it to the server mimicking the other user. Cookie values, for the purpose, are usually long random strings. Cookies are not always sent back to the server where they originate. When the cookie is set, the server specifies the domain of the URL where the cookie should be sent back. This is used when a different server from the one providing the services needing authentication does the user authentication. Applications sometimes encode values into cookies. This is not necessarily bad, though in most actual cases, it is. When encoding something into a cookie, we should always consider the fact that the cookie travels through the network and can go huge as more and more data is encoded in it and can create unnecessary burden on the network. Usually, it is better to send only some unique, otherwise meaningless, random key, and store the values in some database, be it on disk or in the memory. Client server and web architecture The applications we developed so far were running on a single JVM. We already have some experience with concurrent programming and this is something that will come handy now. When we program a web application, a part of the code will run on the server and a part of the application logic will execute in the browser. The server part will be written in Java, the browser part will be implemented in HTML, CSS, and JavaScript. Since this is a Java book we will focus mainly on the server part, but we should still be aware of the fact that many of the functionalities can be and should be implemented to run in the browser. The two programs communicate with each other over the IP network, that is, the Internet, or in the case of an enterprise internal application, the network of the company. Today, a browser is capable of running very powerful applications, all implemented in JavaScript. A few years ago, such applications needed client application implemented in Delphi, C++, or Java, using the windowing capabilities of the client operating system. Originally, the client-server architecture meant that the functionality of the application was implemented on the client, and the program was using general services only from the server. The server provided database access and file storage but nothing more. Later, the three-tier architecture put the business functionality on the servers that used other servers for database and other general services, and the client application implemented the user interface and limited business functionality. When the web technology started to penetrate enterprise computing, the web browser started to replace the client applications in many use cases. Previously, the browser could not run complex JavaScript applications. The application was executed on the web server and the client displayed the HTML that the server created as a part of the application logic. Every time something was changed on the user interface, the browser started a communication with the server, and in a HTTP request-response pair, the browser content was replaced. A web application was essentially a series of form filling and form data sending to the server, and the server responded with HTML-formatted pages, presumably containing new forms. JavaScript interpreters were developed and became more and more effective and standardized. Today, modern web applications contain HTML (which is a part of the client code and is not generated by the server on the fly), CSS, and JavaScript. When the code is downloaded from the web server, the JavaScript starts to execute and communicate with the server. It is still HTTP requests and responses, but the responses do not contain HTML code. It contains pure data, usually in the JSON format. This data is used by the JavaScript code and some of the data, if needed, is displayed on the web browser display also controlled by JavaScript. This is functionally equivalent to a three-tier architecture with some slight but very important differences. The first difference is that the code is not installed on the client. The client downloads the application from a web server, and the only thing that is installed is the modern browser. This removes a lot of enterprise maintenance burden and cost. The second difference is that the client is not able, or is limited, to access the resources of the client machine. Thick client applications could save anything in a local file or access a local database. This is very limited, for security reasons, compared to a program running on the browser. At the same time this is a handy limitation because clients aren't and shouldn't be a trusted part of the architecture. The disk in the client computer is hard and expensive to back up. It can be stolen with a notebook, and encrypting it is costly. There are tools to protect client storage, but most of the time, storing the data on the server only is a more viable solution. It is also a common program design error to trust the client application. The client physically controls the client computer and although it can be made technically very difficult, the client can still overcome the security limitations of the client device and client code. If it is only the client application that checks the validity of some functionality or data, then the physical security provided by the physical control of the server is not used. Whenever data is sent from the client to the server, the data has to be checked in regards of validity, no matter what the client application is. Actually, since the client application can be changed, we just don't really know what the client application really is. In this chapter and, as a matter of fact, in the entire book, we focus on Java technologies; therefore the sample application will not contain almost any client technology. I could not help but create some CSS. On the other hand, I definitely avoided JavaScript. Therefore, I have to emphasize again that the example is to demonstrate the programming of the server side and still providing something that really works. A modern application would use REST and JSON communications and would not play around creating HTML on the fly on the server side. Originally, I wanted to create a JavaScript client and REST server application, but the focus was moved so much from server-side Java programming that I dropped this idea. On the other hand, you can extend the application to be one like that. Writing servlets Servlets are Java classes that are executed in a web server that implements the servlet container environment. The first web servers could only deliver static HTML files to the browsers. For each URL, there was an HTML page on the web server and the server delivered the content of this file, in response to a request sent by the browser. Very soon, there was a need to extend the web servers to be able to start some program that calculates the content of the response, on the fly, when the request is processed. The first standard to do that defined CGI. It started a new process to respond to a request. The new process got the request on its standard input, and the standard output was sent back to the client. This approach wastes a lot of resources. Starting a new process, as you learned in the previous chapter, is way too costly just to respond to an HTTP request. Even starting a new thread seems to be unnecessary, but with that, we ran a bit ahead. The next approach was FastCGI, executing the external process continually and reusing it, and then came different other approaches. The approaches after FastCGIall use in-process extensions. In these cases, the code calculating the response runs inside the same process as the web server. Such standards or extension interfaces were ISAPI for the Microsoft IIS server, NSASPI for the Netscape server, and the Apache module interface. Each of these made it possible to create a dynamically loaded library (DLL on Windows or SO files on Unix systems) to be loaded by the web server during startupand to map certain requests to be handled by the code implemented in these libraries. When somebody programs PHP, for example, the Apache module extension is the PHP interpreter that reads the PHP code and acts upon it. When somebody programs ASP pages for the Microsoft IIS, the ISAPI extension implementing the ASP page interpreter is executed (well, this is a bit sloppy and oversimplified to say but works as an example). To Java, the interface definition is a servlet defined in JSR340 as of version 3.1. JSR stands for Java Specification Request. These are requests for modification of the Java language, library interfaces, and other components. The requests go through an evaluation process, and when they are accepted, they become a standard. The process is defined by the Java Community Process (JCP). JCP is also documented and has versions. The current version is 2.10 and can be found at https://jcp.org/en/procedures/overview. The JSR340 standard can be found at https://jcp.org/en/jsr/detail?id=340. A servlet program implements the servlet interface. Usually this is done via extending HttpServlet, the abstract implementation of the Servlet interface. This abstract class implements methods, such as doGet, doPost, doPut, doDelete, doHead, doOption, and doTrace, free to be overridden by the actual class extending it. If a servlet class does not override one of the these methods, sending the corresponding HTTP method, GET, POST, and so on, will return the 405Not Allowed status code. Hello world servlet Before getting into the technical details, let's create an extremely simple hello world servlet. To do it, we setup a Gradle project with the build file, build.gradle, the servlet class in the file, src/main/java/packt/java9/by/example/mastermind/servlet/HelloWorld.java, and last but not least, we have to create the file src/main/webapp/WEB-INF/web.xml. The gradle.build file will look the following: apply plugin: 'java' apply plugin: 'jetty' repositories { jcenter() } dependencies { providedCompile "javax.servlet:javax.servlet-api:3.1.0" } jettyRun { contextPath '/hello' } The Gradle build file uses two plugins, java and jetty. We have already used the java plugin in the previous chapter. The jetty plugin adds tasks such as jettyRun that load the Jetty servlet container and start up the application. The jetty plugin is also an extension of the war plugin that compiles web applications into a Web Archive (WAR) packaging format. The WAR packaging format is practically the same as JAR; it is a zip file and it contains a lib directory that contains all the JAR files that the web application depends on. The classes of the application are in the directory, WEB-INF/classes, and there is a WEB-INF/web.xml file that describes servlet URL mapping, which we will explore in detail soon. Since we want to develop an extremely simple servlet, we add the servlet API as a dependency to the project. This is, however, not a compile dependency. The API is available when the servlet runs in the container. Still, it has to be available when the compiler compiles our code; therefore, a dummy implementation is provided by the artifact specified as providedCompile. Because it is specified that way, the build process will not package the library into the generated WAR file. The generated file will contain nothing that is specific to Jetty or any other servlet container. The servlet container will provide the actual implementation of the servlet library. When the application is deployed and started in a Jetty, the Jetty-specific implementation of the servlet library will be available on the classpath. When the application is deployed to a Tomcat, the Tomcat specific implementation will be available. We create a class in our project, as follows: package packt.java9.by.example.mastermind.servlet; import import import import import import javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; java.io.IOException; java.io.PrintWriter; public class HelloWorld extends HttpServlet { private String message; @Override public void init() throws ServletException { message = "Hello, World"; } @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<h1>" + message + "</h1>"); } @Override public void destroy() { } } When the servlet is started, the init method is invoked. When it is put out of service, the destroy method is called. These methods can be overridden and provide a more fine-grained control than the constructor and other finalization possibilities. A servlet object may be put into service more than once, and after calling destroy, the servlet container may invoke init again; thus, this cycle is not strictly tied to the life cycle of the object. Usually, there is not much that we do in these methods, but sometimes, you may need some code in them. Also, note that a single servlet object may be used to serve many requests, even at the same time; thus, the servlet classes and methods in it should be fairly thread-safe. The specification demands that a servlet container uses only one servlet instance in case the container runs in a non-distributed environment. In case the container runs on the same machine in several processes, each executing a JVM, or even on different machines, there can be many servlet instances that handle the requests. Generally, the servlet classes should be designed such that they do not assume that only one thread is executing them, but at the same time, they should also not assume that the instance is the same for different requests. We just cannot know. What does it mean in practice? You should not use instance fields that are specific to a certain request. In the example, the field initialized to hold the message holds the same value for each and every request; essentially, the variable is almost a final constant. It is used only to demonstrate some functionality for the init method. The doGet method is invoked when the servlet container gets an HTTP request with the GET method. The method has two arguments. The first one represents the request, and the second one represents the response. The request can be used to collect all information that comes in the request. In the preceding example, there is nothing like that. We do not use any of the inputs. If a request comes to our servlet, then we answer the Hello, World string, no matter what. Later, we will see examples when we read the parameters from the request. The response gives methods that can be used to handle the output. In the example, we fetch PrintWriter, which is to be used to send characters to the body of the HTTP response. This is the content that appears in the browser. The mime type we send is text/html, and this is set by calling the setContentType method. This will get into the HTTP header field, Content-Type. The standard and the JavaDoc documentation of the classes define all the methods that can be used, and also how these should be used. Finally, we have a web.xml file that declares the servlets that are implemented in our code. This is, just as the name of the file indicates, an XML file. It declaratively defines all the servlets that are included in the archive and also other parameters. In the example, the parameters are not defined, only the servlet and the mapping to the URL. Since we have only one single servlet in this example, the WAR file, it is mapped to the root context. All and every GET request that arrives to the servlet container and to this archive will be served by this servlet: <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <display-name>HelloWorldServlet</display-name> <servlet-name>HelloWorldServlet</servlet-name> <servlet-class>packt.java9.by.example.mastermind.servlet.HelloWorld</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloWorldServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> Java Server Pages I promised you that I would not bore you with Java Server Pages because that is a technology of the past. Even though it is the past, it is still not history as there are many programs running that still use JSP and contain JSP code. JSP pages are web pages that contain HTML and Java code mixed. When an HTTP request is served by a JSP page, the servlet container reads the JSP page, executes the Java parts, takes the HTML parts as they are, and in this way, mixing the two together, creates an HTML page that is sent to the browser. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <body> <% for( int i = 0 ; i < 5 ; i ++ ){ %> hallo<br/> <% } %> </body> </html> The preceding page will create an HTML page that contains the text hallo five times, each in a new line separated by the tag br. Behind the scenes, the servlet container converts the JSP page to a Java servlet, then compiles the servlet using the Java compiler, and then runs the servlet. It does it every time there is some change in the source JSP file; therefore, it is very easy to incrementally craft some simple code using JSP. The code that is generated from the preceding JSP file is 138 lines long (on the Tomcat 8.5.5 version), which is simply long and boring to list here, but the part that may help to understand how the Java file generation works is only a few lines. If you want to see all the lines of the generated servlet class, you can deploy the application into a Tomcat server and look at the directory work/Catalina/localhost/hello/org/apache/jsp/. It is a rarely known fact among developers that this code is actually saved to disk and is available. Sometimes it helps when you need to debug some JSP pages. Here are the few interesting lines generated from the preceding code: out.write("\n"); out.write("<html>\n"); out.write("<body>\n"); for( int i = 0 ; i < 5 ; i ++ ){ out.write("\n"); out.write(" hallo<br/>\n"); } out.write("\n"); out.write("</body>\n"); out.write("</html>\n"); The JSP compiler moves the inside of the JSP code out and the outside in. In the JSP code, Java is surrounded by HTML, and in the generated servlet Java source, the HTML is surrounded by Java. It is like when you want to mend clothes: the first thing is to turn the dress inside out. It is not only the Java code that you can mix into HTML in the JSP pages but also the so-called tags. Tags are collected into tag libraries, implemented in Java, and packaged into JAR files, and they should be available on the classpath to be used. The JSP page using the tags from some library should declare the use: <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> The tags look like HTML tags, but they are processed by the JSP compiler and executed by the code implemented in the taglib library. JSP may also refer to the value of the Java objects that are available in the scope of the JSP. To do this inside the HTML page, the JSP expression language could be used. JSP was originally created to ease the development of a web application. The main advantage is the fast startup of development. There is no lengthy time for configuration, setup, and so on in the development, and when there is any change in the JSP page, there is no need to compile the whole application again: the servlet container generates the Java code, compiles it to class file, loads the code into memory, and executes. JSP was a competitor of Microsoft ASP pages, which mixed HTML with VisualBasic code. When the application starts to grow big, using the JSP technology causes more problems than are good. The code that mixes the business logic and the view of the application, how it is rendered in the browser, becomes messy. Developing JSP requires frontend technology knowledge. A Java developer is expected to know some frontend technology but is rarely a design expert and CSS guru. Modern code also contains JavaScript, many times embedded in the HTML page. After all, the big advantage of JSP is that it contains code that runs on the server as well as on the client-side code. The developers follow the paradigm many times, so do not be surprised to see some legacy code that contains Java, HTML, CSS, and JavaScript all mixed in a JSP file. Since Java and JavaScript are syntactically similar sometimes, it is not obvious to see what is executed on the server and what is executed on the client. I have even seen code that created JavaScript code from Java code in a JSP file. That is a total mix of different responsibilities and a mess that is nearly impossible to maintain. This led to the total deprecation of JSP as of today. The deprecation of JSP is not official. It is my expert opinion. You may meet some experienced developers who are still in love with JSP, and you may find yourself in projects where you are required to develop programs in JSP. It is not shameful doing that. Some people do worse for money. To mend the messy situation, there were technologies that advocated the separation of the server code and the client functionality more and more. These technologies include Wicket, Vaadin, JSF, and different Java templating engines, such as Freemarker, Apache Velocity, and Thymeleaf. These latter technologies can also be interesting when you generate textual output from Java even when the code is not web-related at all. These technologies, with discipline, helped control the development and maintenance costs of moderate and large web projects, but the basic problem of the architecture was still there: no clear separation of concerns. Today, modern applications implement the code of a web application in separate projects: one for the client, using HTML, CSS and JavaScript, and a separate one to implement server functionality in Java (or in something else, but we focus here on Java). The communication between the two is the REST protocol, which we will cover in the subsequent chapters. HTML, CSS, and JavaScript HTML, CSS, and JavaScript are client-side technologies. These are extremely important for web applications, and a professional Java developer should have some knowledge about them. Nobody expects you to be an expert in Java and in web-client technologies at the same time, though this is not impossible. A certain understanding is desirable. HTML is the textual representation of a structured text. The text is given as characters, as in any text file. Tags represent the structure. A start tag starts with a < character, then the name of the tag, then, optionally, name="value" attributes, and finally a closing > character. An end tag starts with </, then the name of the tag, and then >. Tags are enclosed into hierarchies; thus, you should not close a tag sooner than the one that was opened later. First, the tag that was opened last has to be closed, then the next, and so on. This way, any actual tag in the HTML has a level, and all tags that are between the start and end tags are below this tag. Some tags that cannot enclose other tags or text do not have end tags and stand on their own. Consider the following sample: <html> <head> <title>this is the title</title> </head> </html> The tag head is under html, and title is under head. This can be structured into a tree, as follows: html + head + title + "this is the title" The browser stores the HTML text in a tree structure, and this tree is the object model of the web page document, thus the name, Document Object Model (DOM) tree. The original HTML concept mixed formatting and structure, and even with the current version of HTML5, we still have tags such as b, i, tt that suggest the browser to display the text between the start and end tags in bold, italics, and teletype, respectively. As the name HTML, standing for Hypertext Markup Language, suggests, the text can contain references to other web pages in the form of hyperlinks. These links are assigned to texts using the a tag (standing for anchor) or to some form that may consist of different fields, and when the submit button of the form is pressed, the content of the fields is sent to the server in a POST request. When the form is sent, the content of the fields is encoded in the so-called application/x-www-form-urlencoded form. The HTML structure always tried to promote the separation of structure and formatting. To do so, formatting was moved to styles. Styles defined in Cascading Style Sheets (CSS) provide much more flexibility for formatting than HTML; the format of a CSS is more effective for formatting. The aim to create CSS was that the design can be decoupled from the structure of the text. If I had to choose one of the three, I would opt for CSS as the one that is least important for Java server-side web developers and, at the same time, the most important for the users (things should look nice). JavaScript is the third pillar of client-side technologies. JavaScript is a fully functional, interpreted programming language executed by the browser. It can access the DOM tree, and read and modify it. When the DOM tree is modified, the browser automatically displays the modified page. JavaScript functions can be scheduled and registered to be invoked when some event occurs. For example, you can register a function to be invoked when the document is fully loaded, when the user presses a button, clicks on a link, or just hovers the mouse over some section. Although JavaScript was first only used to create funny animations on the browser, today it is possible, and is a usual practice, to program fully functional clients using the capabilities of the browser. There are really powerful programs written in JavaScript, even such power-hungry applications as PC emulators. In this book, we focus on Java and use the client-side technologies as much as is needed for demonstration technologies. However, being a Java web developer professional, you have to learn these technologies as well, to some extent at least, to understand what a client can do and to be able to cooperate with the professionals responsible for frontend technologies. Mastermind servlet Playing the Mastermind game via the Web is a bit different from what it used to be. Till now, we did not have any user interaction and our classes were designed accordingly. For example, we could add a new guess to the table, along with the partial and full matches calculated by the program. Now we have to separate the creation of a new guess, add it to the game, and set the full and partial matches. This time, we have to display the table first, and the user has to calculate and provide the number of matches. We have to modify some of the classes to be able to do that. We need to add a new method to Game.java: public Row addGuess(Guess guess, int full, int partial) { assertNotFinished(); final Row row = new Row(guess, full, partial); table.addRow(row); if (itWasAWinningGuess(full)) { finished = true; } return row; } Till now, we had only one method that was adding a new guess, and since the program knew the secret, it was immediately calculating the value of full and partial. The name of the method could be addNewGuess, overloading the original method, but this time, the method is used not only to add a new guess but also to add old guesses to rebuild the table. When the program starts, there are no guesses. The program creates one, the first one. Later on, when the user tells the program the full and partial matches, the program needs the Game structure with Table and Row objects containing Guess objects and the full and partial match values. These were already available, but when the new HTTP hit comes in, we have to pull it from somewhere. Programming a servlet, we have to store the state of the game somewhere and restore it when a new HTTP request hits the server. Storing state Storing the state can be done in two places. One place, which we will first do in our code, is the client. When the program creates a new guess, it adds it to the table and sends an HTML page that contains not only the new guess but also all the previous guesses and the full and partial match values that the user gave for each of the rows. To send the data to the server, the values are stored in the fields of a form. When the form is submitted, the browser gathers the information in the fields, creates an encoded string from the content of the fields, and puts the content into the body of a POST request. The other possibility for storing the actual state is in the server. The server can store the state of the game, and it can reconstruct the structure when it creates a new guess. The problem in this case is knowing which game to use. The server can and should store many games, one for each user, and users may use the application concurrently. It does not necessarily mean strong concurrency in the same meaning as we examined in the previous chapter. Even if the users are not served at the same time in multiple threads, there can be games that are active. Imagine cnn.com telling you that you cannot read the news at the moment because somebody else is reading it. There can be multiple users playing multiple games, and while serving an HTTP request, we should know which user we are serving. Servlets maintain sessions that can be used for this purpose as we will see in the next section. HTTP session When a client sends requests from the same browser to the same servlet, the series of requests belong to one session. To know that the requests belong to the same session, the servlet container automatically sends a cookie named JSESSIONID to the client, and this cookie has a long, random, hard-to-guess value (tkojxpz9qk9xo7124pvanc1z as I run the application in Jetty). The servlet maintains a session store that contains the HttpSession instances. The key string that travels in the value of the JSESSIONID cookie identifies the instances. When an HTTP request arrives at the servlet, the container attaches the session to the request object from the store. If there is no session for the key, then one is created, and the code can access the session object by calling the request.getSession() method. A HttpSession object can store attributes. The program can call the setAttribute(String,Object), getAttribute(String), and removeAttribute(String) methods to store, retrieve, or delete an attribute object. Each attribute is assigned to a String and can be any Object. Although the session attribute store essentially looks as simple as a Map<String,?> object, it is not. The values stored in the session can be moved from one node to another when the servlet container runs in a clustered or other distributed environment. To do that, the values are serialized; therefore, the values stored in the session should be Serializable. Failing to do so is a very common novice error. During development, executing the code in a simple development Tomcat or Jetty container practically never serializes the session to disk and never loads it from the serialized form. This means that the values set using setAttribute will be available by calling getAttribute. We run into trouble the first time the application gets installed in a clustered environment. As soon as a HTTP request arrives on different nodes getAttribute may return null. The method setAttribute is called on one node and during the processing of the next request getAttribute on a different node cannot deserialize the attribute value from the disk shared among the nodes. This is usually, and sadly, the production environment. You, as a developer, should also be aware that serializing and de-serializing an object is a heavy operation that costs several CPU cycles. If the structure of the application uses only a part of the client state serving most of the HTTP requests, then this is a waste of CPU to create the whole state in memory from a serialized form and then serializing it again. In such cases, it is more advisable to store only a key in the session and use some database (SQL or NoSQL) or some other service to store the actual data referenced by the key. Enterprise applications almost exclusively use this structure. package packt.java9.by.example.mastermind.servlet; <br/><br/>import packt.java9.by.example.mastermind.Color; <br/>import packt.java9.by.example.mastermind.Table; <br/><br/>import javax.inject.Inject; <br/>import javax.inject.Named; <br/><br/>public class HtmlTools { <br/> @Inject <br/> Table table; <br/><br/> @Inject <br/> @Named("nrColumns") <br/> private int NR_COLUMNS; <br/><br/> public String tag(String tagName, String... attributes) { <br/> StringBuilder sb = new StringBuilder(); <br/> sb.append("<").append((tagName)); <br/> for (int i = 0; i < attributes.length; i += 2) { <br/> sb.append(" "). <br/> append(attributes[i]). <br/> append("=\""). <br/> append(attributes[i + 1]). <br/> append("\""); <br/> } <br/> sb.append(">"); <br/> return sb.toString(); <br/> } <br/> <br/> public String inputBox(String name, String value) { <br/> return tag("input", "type", "text", "name", name, "value", value, "size", "1"); <br/> } <br/><br/> public String colorToHtml(Color color, int row, int column) { <br/> return tag("input", "type", "hidden", "name", paramNameGuess(row, column), <br/> "value", color.toString()) + <br/> tag("div", "class", "color" + color) + <br/> tag("/div") + <br/> tag("div", "class", "spacer") + <br/> tag("/div"); <br/> } <br/><br/><br/> public String paramNameFull(int row) { <br/> return "full" + row; <br/> } <br/><br/> public String paramNamePartial(int row) { <br/> return "partial" + row; <br/> } <br/><br/> public String paramNameGuess(int row, int column) { <br/> return "guess" + row + column; <br/> } <br/><br/> public String tableToHtml() { <br/> StringBuilder sb = new StringBuilder(); <br/> sb.append("<html><head>"); <br/> sb.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"colors.css\">"); <br/> sb.append("<title>Mastermind guessing</title>"); <br/> sb.append("<body>"); <br/> sb.append(tag("form", "method", "POST", "action", "master")); <br/><br/> for (int row = 0; row < table.nrOfRows(); row++) { <br/> for (int column = 0; column < NR_COLUMNS; column++) { <br/> sb.append(colorToHtml(table.getColor(row, column), row, column)); <br/> } <br/><br/> sb.append(inputBox(paramNameFull(row), "" + table.getFull(row))); <br/> sb.append(inputBox(paramNamePartial(row), "" + table.getPartial(row))); <br/> sb.append("<p>"); <br/> } <br/> return sb.toString(); <br/> } <br/>} <html> <br/> <head> <br/> <link rel="stylesheet" type="text/css" href="colors.css"> <br/> <title>Mastermind guessing</title> <br/> <body> <br/> <form method="POST" action="master"> <br/> <input type="hidden" name="guess00" value="3"> <br/> <div class="color3"></div> <br/> <div class="spacer"></div> <br/> <input type="hidden" name="guess01" value="2"> <br/> <div class="color2"></div> <br/> <div class="spacer"></div> <br/> <input type="hidden" name="guess02" value="1"> <br/> <div class="color1"></div> <br/> <div class="spacer"></div> <br/> <input type="hidden" name="guess03" value="0"> <br/> <div class="color0"></div> <br/> <div class="spacer"></div> <br/> <input type="text" <br/> name="full0" value="0" size="1"> <br/> <input type="text" <br/> name="partial0" value="2" size="1"> <br/> <p> <br/> <input type="hidden" name="guess10" value="5"> <br/> <div class="color5"></div> <br/><br/>...deleted content that just looks almost the same... <br/><br/> <p> <br/> <input type="submit" value="submit"> <br/> </form> <br/> </body> <br/> </head> <br/></html> .color0 { <br/> background: red; <br/> width : 20px; <br/> height: 20px; <br/> float:left <br/>} <br/>.color1 { <br/> background-color: green; <br/> width : 20px; <br/> height: 20px; <br/> float:left <br/>} <br/>... .color2 to .color5 is deleted, content is the same except different colors ... <br/><br/>.spacer { <br/> background-color: white; <br/> width : 10px; <br/> height: 20px; <br/> float:left <br/>} Dependency injection with Guice The servlet class is very simple as shown in the following: package packt.java9.by.example.mastermind.servlet; import import import import com.google.inject.Guice; com.google.inject.Injector; org.slf4j.Logger; org.slf4j.LoggerFactory; import import import import import javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; java.io.IOException; public class Mastermind extends HttpServlet { private static final Logger log = LoggerFactory.getLogger(Mastermind.class); public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Injector injector = Guice.createInjector(new MastermindModule()); MastermindHandler handler = injector.getInstance(MastermindHandler.class); handler.handle(request, response); } } Because many threads use servlets concurrently, and thus we cannot use instance fields holding data for a single hit, the servlet class does nothing else but create a new instance of a MastermindHandler class and invoke its handle method. Since there is a new instance of MastermindHandler for each request, it can store objects in fields specific to the request. To create a handler, we use the Guice library created by Google. We have already talked about dependency injection. The handler needs a Table object to play, a ColorManager object to manage the colors, and a Guesser object to create a new guess, but creating these or fetching some prefabricated instances from somewhere is not the core functionality of the handler. The handler has to do one thing: handle the request; the instances needed to do this should be injected from outside. This is done by a Guice injector. To use Guice, we have to list the library among the dependencies in build.gradle: apply plugin: 'java' apply plugin: 'jetty' repositories { jcenter() } dependencies { providedCompile "javax.servlet:javax.servlet-api:3.1.0" testCompile 'junit:junit:4.12' compile 'org.slf4j:slf4j-api:1.7.7' compile 'ch.qos.logback:logback-classic:1.0.11' compile 'com.google.inject:guice:4.1.0' } jettyRun { contextPath '/hello' } Then we have to create an injector instance that will do the injection. The injector is created with the following line in the servlet: Injector injector = Guice.createInjector(new MastermindModule()); The instance of MastermindModule specifies what to inject where. This is essentially a configuration file in the Java format. Other dependency injector frameworks used, and use, XML and annotations to describe the injection binding and what to inject where, but Guice solely uses Java code. The following is the DI configuration code: public class MastermindModule extends AbstractModule { @Override protected void configure() { bind(int.class) .annotatedWith(Names.named("nrColors")).toInstance(6); bind(int.class) .annotatedWith(Names.named("nrColumns")).toInstance(4); bind(ColorFactory.class).to(LetteredColorFactory.class); bind(Guesser.class).to(UniqueGuesser.class); } } The methods used in the configure method are created in a fluent API manner so that the methods can be chained one after the other and that the code can be read almost like English sentences. A good introduction to fluent API can be found at https://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/. For example, the first configuration line could be read in English as Bind to the class int wherever it is annotated with the @Name annotation having value "nrColor" to the instance 6. (Note that the int value 6 is autoboxed to an Integer instance.) The MastermindHandler class contains fields annotated with @Inject annotation: @Inject @Named("nrColors") private int NR_COLORS; @Inject @Named("nrColumns") private int NR_COLUMNS; @Inject private HtmlTools html; @Inject Table table; @Inject ColorManager manager; @Inject Guesser guesser; This annotation is not Guice-specific. @Inject is a part of the javax.inject package and is a standard part of JDK. JDK does not provide the dependency injector (DI) framework but supports the different frameworks so that they can use standard JDK annotations, and in case the DI framework is replaced, the annotations may remain the same and not framework-specific. When the injector is called to create an instance of MastermindHandler, it looks at the class and sees that it has an int field annotated with @Inject and @Named("nrColors"), and finds in the configuration that such a field should have the value 6. It injects the value to the field before returning the MastermindHandler object. Similarly, it also injects the values into the other fields, and if it should create any of the objects to be injected, it does. If there are fields in these objects, then they are also created by injecting other objects and so on. This way the DI framework removes the burden from the programmers' shoulder to create the instances. This is something fairly boring and is not the core feature of the classes anyway. Instead, it creates all the objects needed to have a functional MastermindHandler and links them together via the Java object references. This way, the dependencies of the different objects (MastermindHandler needs Guesser, ColorManager, and Table; ColorManager needs ColorFactory; and Table also needs ColorManager, and so on) become a declaration, specified using annotations on the fields. These declarations are inside the code of the classes, and it is the right place for them. Where else could we specify what the class needs to properly function than in the class itself? The configuration in our example specifies that wherever there is a need for ColorFactory, we will use LetteredColorFactory, and that wherever we need Guesser, we will use UniqueGuesser. This is separated from the code and it has to be like that. If we want to change the guessing strategy, we replace the configuration and the code should work without modifying the classes that use the guesser. Guice is clever enough and you need not specify that wherever there is a need for Table, we will use Table: there is no bind(Table.class).to(Table.class). First I created a line like that in the configuration, but Guice rewarded me with an error message, and now, writing it again in plain English, I feel really stupid. If I need a table I need a table. Really? The MastermindHandler class We have already started the listing of the MastermindHandler class, and since this class is more than a hundred lines, I will not include it here as a whole. The most important method of this class is handle: public void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Game game = buildGameFromRequest(request); Guess newGuess = guesser.guess(); response.setContentType("text/html"); PrintWriter out = response.getWriter(); if (game.isFinished() || newGuess == Guess.none) { displayGameOver(out); } else { log.debug("Adding new guess {} to the game", newGuess); game.addGuess(newGuess, 0, 0); displayGame(out); } bodyEnd(out); } We perform three steps. Step 1 is creating the table and we do it from the request. If this is not the start of the game, there is already a table and the HTML form contains all previous guess colors and the answers to those. Then, as the second step, we create a new guess based on that. Step 3 is to send the new HTML page to the client. Again, this is not a modern approach, creating HTML on the servlet code, but demonstrating pure servlet functionality with REST, JSON, and JavaScript with some framework would make this chapter alone a few hundred pages long, and it would definitely distract our focus from Java. Printing HTML text to a PrintWriter is not something that should be new to you at this point in this book; therefore, we will not list that code here. You can download the working example on GitHub. The branch for this version of the code is nosession. Instead of printing, we will focus on the servlet parameter handling. The request parameters are available via the getParameter method, which returns the string value of a parameter. This method assumes that any parameter, be it GET or POST, appears only once in the request. In case there are parameters that appear multiple times, the value should have been a string array. In such a case, we should use getParameterMap, which returns the whole map with the String keys and String[] values. Even though we do not have multiple values for any key this time, and we also know the values of the keys coming as POST parameters, we will still use the latter method. The reason for this is that we will later use the session to store these values, and we want to have a method that is reusable in that case. If you look at the earlier commits in the Git repository, you will see that the first version used getParameter and I refactored it only later when I created the second version of the program, which stores the state in a session. Never believe if anyone tells you that programs are created perfectly upfront without any refactoring during development. Do not feel ashamed to create foolish code and refactor it later. It is only shameful if you do not refactor it. To get to that we convert the request's Map<String,String[]> to Map<String,String>: private Game buildGameFromRequest(HttpServletRequest request) { return buildGameFromMap(toMap(request)); } private Map<String, String> toMap(HttpServletRequest request) { log.debug("converting request to map"); return request.getParameterMap().entrySet(). stream().collect( Collectors.toMap( Map.Entry::getKey, e -> e.getValue()[0])); } Then, we use that map to re-create the game: private Game buildGameFromMap(Map<String, String> params) { final Guess secret = new Guess(new Color[NR_COLUMNS]); final Game game = new Game(table, secret); for (int row = 0; params.containsKey(html.paramNameGuess(row, 0)); row++) { Color[] colors = getRowColors(params, row); Guess guess = new Guess(colors); final int full = Integer.parseInt(params.get(html.paramNameFull(row))); final int partial = Integer.parseInt(params.get(html.paramNamePartial(row))); log.debug("Adding guess to game"); game.addGuess(guess, full, partial); } return game; } The conversion from String to int is done via the method parseInt. This method throws NumberFormatException when the input is not a number. Try to run the game, use the browser, and see how Jetty handles the case when the servlet throws an exception. How much valuable information do you see in the browser that can be used by a potential hacker? Fix the code so that it asks the user again if any of the numbers are not well formatted! Storing state on the server The application state should usually not be saved on the client. There may be some special case in addition to the one where you write educational code and want to demonstrate how to do it. Generally, the state of the application related to the actual use is stored in the session object or on some database. This is especially important when the application requests the user to enter a lot of data and does not want the user to lose the work if there is some hiccup in the client computer. You spend a lot of time selecting the appropriate items in an online shop, choosing the appropriate items that work together, creating a configuration of your new model airplane, and all of a sudden, there is a blackout in your home. If the state were stored on the client you'd have had to start from scratch. If the state is stored on the server, the state is saved to disk; the servers are duplicated, fed by battery-backed power supplies, and when you reboot your client machine when the power comes back in your home, you log in, and miraculously, the items are all there in your shopping basket. Well, it is not a miracle; it is web programming. In our case, the second version will store the state of the game in the session. This will let the user have the game restore so long as the session is there. If the user quits and restarts the browser, the session gets lost and a new game can start. Since there is no need to send the actual colors and matching in hidden fields this time, the HTML generation is modified a bit, and the generated HTML will also be simpler: <html> <head> <link rel="stylesheet" type="text/css" href="colors.css"> <title>Mastermind guessing</title> <body> <form method="POST" action="master"> <div class="color3"></div> <div class="spacer"></div> <div class="color2"></div> <div class="spacer"></div> <div class="color1"></div> <div class="spacer"></div> <div class="color0"></div> <div class="spacer"></div>0 <div class="spacer"></div>2<p> <div class="color5"></div> ... <div class="spacer"></div> <div class="color1"></div> <div class="spacer"></div> <input type="text" name="full2" value="0" size="1"><input type="text" name="partial2" value="0" size="1"> <p> <input type="submit" value="submit"> </form> </body> </head></html> The number of full and partially matching colors is displayed as a simple number, so this version does not allow cheating or changing previous results. (These are the numbers 0 and 2 after the div tags that have the CSS class spacer.) The handle method in MastermindHandler also changes, as shown in the following: public void handle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Game game = buildGameFromSessionAndRequest(request); Guess newGuess = guesser.guess(); response.setContentType("text/html"); PrintWriter out = response.getWriter(); if (game.isFinished() || newGuess == Guess.none) { displayGameOver(out); } else { log.debug("Adding new guess {} to the game", newGuess); game.addGuess(newGuess, 0, 0); sessionSaver.save(request.getSession()); displayGame(out); } bodyEnd(out); } This version of the class gets a SessionSaver object injected by the Guice injector. This is a class that we create. This class will convert the current Table into something that is stored in the session, and it also recreates the table from the data stored in the session. The handle method uses the buildGameFromSessionAndRequest method to restore the table and to add the full and partial match answers that the user just gave in the request. When the method creates a new guess and fills it in the table, and also sends it to the client in the response, it saves the state in the session by calling the save method via the sessionSaver object. The buildGameFromSessionAndRequest method replaces the other version, which we named buildGameFromRequest: private Game buildGameFromSessionAndRequest(HttpServletRequest request) { Game game = buildGameFromMap(sessionSaver.restore(request.getSession())); Map<String, String> params = toMap(request); int row = getLastRowIndex(params); log.debug("last row is {}", row); if (row >= 0) { final int full = Integer.parseInt(params.get(html.paramNameFull(row))); final int partial = Integer.parseInt(params.get(html.paramNamePartial(row))); log.debug("setting full {} and partial {} for row {}", full, partial, row); table.setPartial(row, partial); table.setFull(row, full); if (full == table.nrOfColumns()) { game.setFinished(); } } return game; } Note that this version has the same illness of using the parseInt method from the Integer class in JDK, which throws an exception. The GameSessionSaver class This class has three public methods: : This saves a table to the user session restore: This gets a table from the user session reset: This deletes any table that may be in the session save The code of the class is the following: public class GameSessionSaver { private static final String STATE_NAME = "GAME_STATE"; @Inject private HtmlTools html; @Inject Table table; @Inject ColorManager manager; public void save(HttpSession session) { Map<String,String> params = convertTableToMap(); session.setAttribute(STATE_NAME,params); } public void reset(HttpSession session) { session.removeAttribute(STATE_NAME); } public Map<String,String> restore(HttpSession session){ Map<String,String> map= (Map<String,String>) session.getAttribute(STATE_NAME); if( map == null ){ map = new HashMap<>(); } return map; } private Map<String,String> convertTableToMap() { Map<String, String> params = new HashMap<>(); for (int row = 0; row < table.nrOfRows(); row++) { for (int column = 0; column < table.nrOfColumns(); column++) { params.put(html.paramNameGuess(row,column), table.getColor(row,column).toString()); } params.put(html.paramNameFull(row), ""+table.getFull(row)); params.put(html.paramNamePartial(row), ""+table.getPartial(row)); } return params; } } When we save the session and convert the table to a map, we use a HashMap. The implementation in this case is important. The HashMap class implements the Serializable interface; therefore, we can be safe putting it to the session. This alone does not guarantee that everything in HashMap is Serializable. The keys and the values in our case are Strings, and fortunately, the String class also implements the Serializable interface. This way, the converted HashMap object can be safely stored in the session. Also note that, although serialization can be slow, storing HashMap in a session is so frequent that it implements its own serialization mechanism. This implementation is optimized and avoids serialization being dependent on the internal structure of the map. It is time to think about why we have the convertTableToMap method in this class and buildGameFromMap in MastermindHandler. Converting the game and the table in it to a Map and the other way round should be implemented together. They are just two directions of the same conversion. On the other hand, the implementation of the Table to Map direction should use a Map version that is Serializable. This is very much related to session handling. Converting a Map object, in general, to a Table object is one level higher, restoring the table from wherever it was stored: client, session, database, or in the moisture of the cloud. Session storage is only one possible implementation, and methods should be implemented in the class that meets the abstraction level. The best solution could be to implement these in a separate class. You have homework! The reset method is not used from the handler. This is invoked from the Mastermind class, that is, the servlet class to reset the game when we start it: public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { GameSessionSaver sessionSaver = new GameSessionSaver(); sessionSaver.reset(request.getSession()); doPost(request, response); } Without this, playing the game against the machine once would just display the finished game every time we want to start it again, until we exit the browser and restart it or explicitly delete the JSESSIONID cookie somewhere in the advanced menu of the browser. Calling reset does not delete the session. The session remains the same, and thus the value of JSESSIONID too, but the game is deleted from the session object that the servlet container maintains. Running the Jetty web servlet Since we have included the Jetty plugin into our Gradle build, the targets of the plugin are available. To start Jetty is as easy as typing the following: gradle jettyRun This will compile the code, build the WAR file, and start the Jetty servlet container. To help us remember, it also prints the following on the command line: Running at http://localhost:8080//hello We can open this URL and see the opening screen of the game with the colors that the program created as a first guess: Now it is time to have some fun and play with our game, giving answers to the program. Do not make it easy for the code! Refer to the following screenshot: At the same time, if you look at the console where you have typed gradle jettyRun, you will see that the code is printing out log messages, as shown in the following screenshot: These printouts come through the logger that we have in our code. In the previous chapters, we used the System.out.println method calls to send informational messages to the console. This is a practice that should not be followed in any program that is more complex than a hello world Logging There are several logging frameworks available for Java and each has advantages and disadvantages. There is one built into JDK in the java.util.logging package and accessing the logger is supported by the System.getLogger method: the System.Logger and System.LoggerFinder classes. Even though java.util.logging has been available in Java since JDK 1.4, a lot of programs use other logging solutions. In addition to the built-in logging, we have to mention log4j, slf4j and Apache Commons Logging. Before getting into the details of the different frameworks, let's discuss why it is important to use logging instead of just printing to the standard output. Configurability The most important reason is configurability and ease of use. We use logging to record information about the operation of code. This is not the core functionality of the application but is inevitable to have a program that can be operated. There are messages we print out to the log, which can be used by the operating personnel to identify environmental issues. For example, when an IOException is thrown and it gets logged, the operation may look at the logs and identify that the disk got full. They may delete files, or add a new disk and extend the partition. Without the logs, the only information would be that the program does not work. The logs are also used many times to hunt down bugs. Some of the bugs do not manifest in the test environment and are very difficult to reproduce. In such a case, the logs that print out detailed information about the execution of the code are the only source of finding the root cause of some error. Since logging needs CPU, IO bandwidth, and other resources, it should be carefully examined what and when to log. This examination and the decisions could be done during programming, and as a matter of fact, that is the only possibility if we used System.out.println for logging. If we need to find a bug, we should log a lot. If we log a lot, the performance of the system will go down. The conclusion is that we have to log only if it is needed. If there is a bug in the system that cannot be reproduced, the developers ask the operation to switch on debug logging for a short period. Switching on and off different parts of logging is not possible when System.out.println is used. When the debug level log is switched on, the performance may go down for a while, but at the same time, the logs become available for analysis. At the same time, the analysis is simpler when we have to find the log lines that are relevant (and you do not know beforehand which are relevant) if there is a small (a few hundred megabytes log file) rather than a lot of 2-GB compressed log files to find the lines in. Using a log framework, you can define loggers that identify the source of the log messages and log levels. A string usually identifies the logger, and it is a common practice to use the name of the class from which the log message is created. This is such a common practice that the different log frameworks provide factory classes that get the class itself, instead of its name, to get a logger. The possible logging levels may be slightly different in different logging frameworks, but the most important levels are as follows: : This is used when the log message is about some error that prevents the program from continuing its execution. ERROR: This is used when there is some severe error, but the program can still go on functioning although, probably, in some limited manner. WARNING: This is used when there is some condition that is not a direct problem but may later lead to an error if not attended. For example, the program recognizes that a disk is near full, some database connections answer within limits but close to the timeout value, and similar situations. INFO: This is used to create messages about normal operations that may be interesting to operate and are not an error or warning. These messages may help the operation to debug the operational environment settings. DEBUG: This is used to log information about the program that is detailed enough (hopefully) to find a FATAL bug in the code. The trick is that when we put the log statement into the code, we do not know what bug it could be. If we knew, we better fixed it. TRACE: This is even more detailed information about the execution of the code. The log frameworks are usually configured using some configuration file. The configuration may limit the logging, switching off certain levels. In a normal operational environment, the first three levels are usually switched on, and INFO, DEBUG, and TRACE are switched on when really needed. It is also possible to switch on and off certain levels only for certain loggers. If we know that the error is certainly in the GameSessionSaver class, then we can switch on the DEBUG level only for that class. Log files may also contain other information that we did not directly code and would be very cumbersome to print to the standard output. Usually, each log message contains the precise time when the message was created, the name of the logger, and, many times, the identifier of the thread. Imagine if you were forced to put all this to each and every println argument; you would probably soon write some extra class to do that. Don't! It has already been done professionally: it is the logger framework. Loggers can also be configured to send the message to different locations. Logging to the console is only one possibility. Logging frameworks are prepared to send messages to files, database, Windows Event Recorder, syslog service, or to any other target. This flexibility, which message to print, what extra information to print, and where to print is reached by separating the different tasks that the logger framework does into several classes following the single responsibility principle. The logger frameworks usually contain loggers that create the logs, formatters that format the message from the original log information, many times, adding information such as thread ID and time stamp, and appenders that append the formatted message to some destination. These classes implement interfaces defined in the logging framework and nothing but the size of the book stops us from creating our own formatters and appenders. When a log is configured, the appenders and formatters are configured, given the class that implements them. Therefore, when you want to send some logs to some special destination, you are not limited to the appenders that are provided by the authors of the framework. There are a lot of independent open-source projects for different logging frameworks providing appenders for different targets. Performance The second reason to use a logging framework is performance. Although it is not good to optimize for performance before we profile the code (premature optimization), using some methodology known to be slow and inserting several lines into our performance-critical code, invoking slow methods is not really professional either. Using a well-established, highly optimized framework in a way that is industry best practice should not be questionable. Using System.out.println sends the message to a stream and returns only when the IO operation is done. Using real logging handles the information to the logger and lets the logger do the logging asynchronously, and it does not wait for completion. It is really a drawback that log information may be lost if there is some system failure, but this is usually not a serious issue considering how rarely that happens and what is on the other side of the wage: performance. What do we lose if there is a missing debug log line when the disk got full, anyway rendering the system unusable? There is one exception to this: audit logging—when some log information about the transactions of the system has to be saved for legal reasons so that the operation and the actual transactions can be audited. In such a case, the log information is saved in a transactional manner, making the log part of the transaction. Because that is a totally different type of requirement, audit logging is not usually done with any of these frameworks. Also, System.out.println is not synchronized and that way different threads may just garble the output. Log frameworks pay attention to this issue. Log frameworks The most widely used logging framework is Apachelog4j. It currently has a second version that is a total rewrite of the first version. It is very versatile and has many appenders and formatters. The configuration of log4j can be in XML or properties file format, and it can also be configured through API. The author of log4j version 1 created a new logging framework: slf4j. This logging library is essentially a façade that can be used together with any other logging framework. Thus, when you use slf4j in a library you develop, and your code is added to a program as a dependency that uses a different logging framework, it is easy to configure slf4j to send the logs to the loggers of the other framework. Thus, the logs will be handled together and not in separate file, which is desirable to decrease the cost of operation. When developing your library code or an application that uses slf4j, there is no need to select another log framework to slf4j. It has its own simple implementation called backlog. Apache Commons Logging is also a façade with its own logging implementation if nothing else fails. The major difference from slf4j is that it is more flexible in configuration and what underlying logging to use, and it implements a run-time algorithm to discover which logging framework is available and is to be used. The industry best practice shows that this flexibility, which also comes with higher complexity and cost, is not needed. Java 9 logging Java 9 includes a facade implementation for logging. The use is very simple and we can expect that logging frameworks will very soon start to support this façade. The fact that this façade is built into the JDK has two major advantage: The libraries that want to log do not need to have any dependency on any logging framework or logging façade any more. The only dependency is the JDK log façade that is there anyway. The JDK libraries that log themselves use this façade and thus they will log into the same log file as the application. If we use the JDK-provided logging façade the start of the ColorManager class will be changed to the following: package packt.java9.by.example.mastermind; import import import import import import javax.inject.Inject; javax.inject.Named; javax.inject.Singleton; java.util.HashMap; java.util.Map; java.lang.System.Logger; import static java.lang.System.Logger.Level.DEBUG; @Singleton public class ColorManager { protected final int nrColors; protected final Map<Color, Color> successor = new HashMap<>(); private Color first; private final ColorFactory factory; private static final Logger log = System.getLogger(ColorManager.class.getName()); @Inject public ColorManager(@Named("nrColors") int nrColors, ColorFactory factory) { log.log(DEBUG,"creating colorManager for {0} colors", nrColors); In this version we do not import the slf4j classes. Instead we import the java.lang.System.Logger class. Note that we do not need to import the System class, because the classes from the java.lang package are automatically imported. This is not true for the classes that are nested classes in the System class. To get access to the logger the System.getLogger static method is called. This method finds the actual logger that is available and returns one for the name that we pass as argument. There is no version of the method getLogger that accepts the class as the argument. If we want to stick to the convention then we have to write ColorManager.class.getName() to get the name of the class or we can write there the name of the class as a string. The second approach has the drawback that it does not follow the change of the name of the class. Intelligent IDEs like IntelliJ, Eclipse, or Netbeans rename the references to classes automatically but they have a hard time when the name of the class is used in a string. The interface System.Logger does not declare the convenience methods error, debug, warning, and so on, that are familiar from other logging frameworks and façade. There is only one method named log and the first argument of this method is the level of the actual log we issue. There are eight levels defined: ALL, TRACE, DEBUG, INFO, WARNING, ERROR, and OFF. When creating a log message we are supposed to use one of the middle six levels. ALL and OFF are meant to be passed to the isLoggable method. This method can be used to check if the actual logging level gets logged or not. For example, if the level is set to INFO then messages sent with DEBUG or TRACE will not be printed. The actual implementation is located by the JDK using the service loader functionality. The log implementation has to be in a module that provides the interface java.lang.System.LoggerFinder via some implementation. In other words the module should have a class that implements the LoggerFinder interface and the module-info.java should declare which class it is using the code: provides java.lang.System.LoggerFinder with packt.java9.by.example.MyLoggerFinder; The MyLoggerFinder class has to extend the LoggerFinder abstract class with the method getLogger. Logging practice The practice of logging is very simple. If you do not want to spend too much time experimenting with different logging solutions and you do not have some special requirement, then simply go with slf4j, add the JAR to the dependency list as a compile dependency, and start using logging in the source code. Since logging is not instance-specific, and loggers implement thread safety, the log objects that we usually use are stored in a static field, and since they are used as long as the class is used, the program running the field is also final. For example using the slf4j façade we can get a logger with the following command: private static final Logger log = LoggerFactory.getLogger(MastermindHandler.class); To get the logger, the logger factory is used, which just creates the logger or returns the one that is already available. The name of the variable is usually log or logger, but do not be surprised if you see LOG or LOGGER. The reason for uppercasing the name of the variable is that some static code analysis checkers treat static final variables as constants, as they really are, and the convention in the Java community is to use uppercase names for such variables. It is a matter of taste; many times log and logger are used in lowercase. To create a log item the methods trace, debug, info, warn, and error create a message with the respective level as the name implies. For example, consider the following line: log.debug("Adding new guess {} to the game", newGuess); It creates a debug message. Slf4j has support for formatting using the {} literal inside strings. This way, there is no need to append the string from small parts, and in case the actual log item is not sent to the log destination, the formatting will not perform. If we use String concatenation in any form to pass a string as an argument, then the formatting will happen even if debug logging is not desired as per the example. The logging methods also have a version that gets only two arguments: a String message and Throwable. In this case, the logging framework will take care of the output of the exception and the stack trace along with it. If you log something in exception handling code, log the exception and let the logger format it. Other technologies We discussed the servlet technology, a bit of JavaScript, HTML, and CSS. When programming in a real professional environment, these technologies are generally used. The creation of the user interface of applications, however, was not always based on these technologies. Older operating system-native GUI applications as well as Swing, AWT, and SWT use a different approach to create UI. They build up the UI facing the user from program code, and the UI is built as a hierarchical structure of components. When web programming started, Java developers had experience with technologies like these and projects created frameworks that tried to hide the web technology layer. One technology worth mentioning is Google Web Toolkit, which implements the server as well as the browser code in Java, but since there is no Java environment implemented in the browsers, it transpiles (converts) the client part of the code from Java to JavaScript. The last release of the toolkit was created two years ago in 2014 and since then Google has released other types of web programming toolkits that support native JavaScript, HTML, and CSS client development. Vaadin is also a toolkit that you may come across. It lets you write GUI code on the server in Java. It is built on top of GWT and is commercially supported. It may be a good choice in case there are developers available who have experience with GUI development in Java but not in web native technologies, and the application does not require special usability tuning on the client side. A typical intranet corporate application can select it as a technology. Java Server Faces (JSF) is a technology that tries to offload the client-side development of the application from the developers providing widgets ready to be used and the server side. It is a collection of several Java Specification Requests (JSR) and there are several implementations. The components and their relations are configured in XML files and the server creates the client native code. In this technology, there is no transpilation from Java to JavaScript. It is more like using a limited but huge set of widgets, limiting the use to those only, and giving up direct programming of the web browser. If one has the experience and knowledge, however, they can create new widgets in HTML, CSS, and JavaScript. There are many other technologies that were developed to support web applications in Java. The modern approach advocated by most of the big players is to develop the server side and the client side using separate toolsets and methodologies, and connect the two using REST communication. Summary In this chapter, you learnt the structure of web programming. This was not possible without understanding the basics of TCP/IP networking, which is the protocol of the Internet. The application level protocol that is used over that is HTTP, currently in a very new version 2.0, which is still not supported by the servlet standard. We created a version of the Mastermind game that, this time, can really be played using the browser and we started it in a development environment using Jetty. We examined how to store the game state and implemented two versions. Finally, we learned the basics of logging and we looked at other technologies. At the same time, we also looked at the dependency injection implementation Guice from Google, and we studied how it works under the hood, and why and how to use it. After this chapter, you will be able to start the development of a web application in Java and will understand the architecture of such a program. You will understand what is under the hood when you start learning how to program web applications using the Spring framework, which hides many of the complexities of web programming. Building a Commercial Web Application Using REST We were playing around till now, but Java is not a toy. We want to use Java for something real and serious, commercial and professional. In this chapter, we will do that. The example is not something that is only interesting to play with, such as Mastermind in the previous three chapters, but rather a real commercial application. Not a real-life application actually. You should not expect anything like that in a book. It would be too long and not educating enough. However, the application that we will develop in this chapter can be extended and can be used as a core for a real-life application in case you decided to do so. In the previous chapter, we created servlets. To do so, we used the servlet specification, and we handimplemented servlets. That is something you will rarely do these days. Instead, we will use a readily available framework, this time, Spring. It is the most widely used framework for Java commercial applications, and I dare say it is the de facto standard. It will do all the tedious work that we had to do (at least to understand and learn how a servlet works) in the previous chapter. We will also use Spring for dependency injection (why use two frameworks when one does it all?), and we will use Tomcat. In the previous chapter, we used Guice as a DI framework and Jetty as a servlet container. They can be a perfectly good choice for some projects. For other projects, other frameworks do better. To have the opportunity to look at different tools in this book, we will use different frameworks even though all the examples could be created by simply using Tomcat and Spring. The commercial application we will develop will be an ordering system targeting resellers. The interface we will provide to the users will not be a web browser; rather, it will be REST. The users will themselves develop applications that communicate with our system and place orders for different products. The structure of the application we will develop will be microservices architecture, and we will use soapUI to test the application, in addition to the standard Chrome developer tool features. The MyBusiness web shop Imagine that we have a huge trading and logistics company. There are tens of thousands of different products on the shelves; hundreds of lorries come to our warehouse bringing new goods, and hundreds of lorries deliver goods to our customers. To manage the information, we have an inventory system that keeps track of the goods every day, hour, and minute to know what we actually have in the warehouse. We serve our customers without humans managing the warehouse information. Formerly, there were phones, fax machines, and even telex, but today, all we use is the Internet and web services. We do not provide a website for our customers. We have never directly served the end users in our imagined business, but these days, we have a subsidiary that we started off as a separate company to do just that. They have a website, and it is totally independent from us. They are just one of our hundreds of registered partners who each use a web service interface to see the products we have, order products, and track the order status. Sample business architecture Our partners are also large companies with automated administration, with several programs running on several machines. We have no interest in their architecture and the technology they use, but we want to integrate their operations. We want to serve them in a way that doesn't require any human interaction for the administration to order goods on either of our sides. To do so, a web service interface is provided that can be utilized no matter what IT infrastructure they use. On our side, as we imagine the example, we recently replaced our monolithic application with microservices architecture, and though there are still some SOAP-based solutions in the system, most of the backend modules communicate using HTTPS and REST protocols. Some of the modules still rely on asynchronous file transfers done on a daily basis using FTP started from a UNIX cron job. The General Ledger system was programmed in COBOL. Fortunately, we do not need to deal with these dinosaurs. All this structure is an imagined setup but a realistic one. I made up and described these parts to give you a picture of how you may see mixed technologies in a large enterprise. What I described here is a very simple setup. There are companies that have more than a thousand software modules in their systems using different technologies and totally different interfaces, all interconnected with each other. This is not because they like the mess, but that is the way it becomes after 30 years of continuous IT development. New technologies come and old technologies fade out. The business changes and you cannot stick to the old technologies if you want to stay competitive. At the same time, you just cannot replace the entire infrastructure instantaneously. The result is that we see in an enterprise fairly old technologies still running and, many times, new technologies. Old technologies get rolled out by time. They do not stay forever, and still, we are surprised sometimes when a dinosaur comes in front of us. What we have to deal with is the two frontend components that we will develop. These are as follows: Product Information Order Placement and Tracking In the following image, you can see the architectural UML diagram of the structure that we look at. The parts we will have interaction with are only the frontend components, but it helps understand the working and their role if we have a bigger picture: Product Information delivers information about a single product, but it can also deliver a list of products based on the query criteria. Order Placement and Tracking provides functions to place an order and also lets the client to query the state of past orders. To provide product information, we need access to the Product Catalog module that holds the actual product details. There can be a lot of other tasks that the Product Catalog does, and that is the reason it is a separate module. It can have, for example, a workflow and approval engine that lets product administrators to enter product data and managers to check and approve the data. Approval is usually a complex process, considering typos and legal questions (we do not want to trade unlicensed drugs, explosives, and so on), and checking the quality and approval state of the source of the goods. Many complex tasks are included that make it a backend module. In large enterprise applications, the frontend systems rarely do anything else other than the very basic functionality of serving the outside parties. But this is good for us; we can focus on the service that we have to deliver. And this is also good for the architecture. It is the same principle as in object-oriented programming: single responsibility. The Product Information module also has to consult with the Access Control module to see if a certain product can be delivered to the actual customer, and with the inventory to see if there is any product left, so we do not offer a product that is out of stock. The Order Placement and Tracking also needs access to Product Inventory and Access Control modules to check whether the order can be fulfilled. At the same time, it also needs services from the Pricing module, which can calculate the price for the order, and from the Logistics module, which triggers the collection of goods from the inventory locations and shipment to the customer. Logistics also has a connection to invoicing, which has a connection to the General Ledger, but these are on the picture only to show that the travel of information does not end there. There are many other modules that run the company, all of which are none of our interest at the moment. Microservices The architecture described in the previous chapter is not a clean microservice architecture. You will never meet one in its pure form in any enterprise. It is more like something that we really meet in a real company moving from monolithic to microservices. We talk about the microservice architecture when the application is developed in the form of many small services that communicate with each other using some simple API, usually over HTTP and REST. The services implement business functionalities and can be deployed independently. Many times, it is desirable that the service deployment is automated. The individual services can be developed using different programming languages, can use different data storage, and can run on different operating systems; thus, they are highly independent of each other. They can be, and usually are, developed by different teams. The important requirement is that they can cooperate; thus, the API one service implements is usable by the other services that build upon it. The microservice architecture is not the Holy Grail of all architectures. It gives different answers to some problems from monolithic architectures, and many times, these answers work better using modern tools. The applications still have to be tested and debugged, performance has to be managed, and bugs and issues have to be addressed. The difference is that testing can be separated along different technologies; debugging may need more network-related work. These may be good, bad, or both at the same time. For the developers, however, the advantage is clear. They can work on a smaller unit independently and can see the result of their work faster. When developing a single module of a monolithic application, the result can be seen when the entire application gets deployed. In the case of a large application, that may be rare. A typical deployment cycle in a large corporate developing monolithic is every few months, say 3, but it is not rare to see the release development twice or even once a year. Developing microservices, the new module can be deployed as soon as it is ready and tested. If you want to read more on microservices, the first and the most authentic source is the article by Martin Fowler (http://www.martinfowler.com/articles/microservices.html). Service interface design We design the two interfaces that we will implement. When we design interfaces, we focus on the functionality first. Formatting and protocol come later. Interfaces generally should be simple and, at the same time, should accommodate the future change. This is a hard problem because we cannot see the future. Business, logistics, and all other experts may see some part of the future: how the world will change and what it will impose on the operation of the company and, especially, on the interface we provide for our partners. The stability of an interface is of utmost importance because the partners are outside entities. We cannot refactor the code they use. When we change a Java interface in our code, the compiler will complain at all the code locations where the change should be followed. In case of an interface that is used outside of our realm, this is not the case. Even if it is only a Java interface that we publish as open source on GitHub, we should be prepared that our users will face issues if we change the library in an incompatible way. In that case, their software will not compile and work with our library. In the case of an ordering system, it means that they will not order from us and we will soon be out of business. This is one of the reasons why interfaces should be simple. Although this is generally true for most of the things in life, it is extremely important for such interfaces. It is tempting to provide convenience features for the partners because they are easy to implement. In the long run, however, these features may become very expensive as they need maintenance, should be kept backward compatible, and, in the long run, may not gain as much as they cost. To access product information, we need two functions. One of them lists certain products and another returns the details of a specific product. If it were a Java API, it would look as follows: List<ProductId> query(String query); ProductInformation byId(ProductId id); Similarly, order placement may look as shown in the following: OrderId placeOrder(Order order); We provide these functionalities in our application via a web service interface and, more specifically, REST using JSON. We will discuss these technologies in a bit more detailed manner along with the Spring framework and Model View Controller design pattern, but first let's look at the product information controller to get some feeling of how our program will look: package packt.java9.by.example.mybusiness.productinformation; import ... @RestController public class ProductInformationController { @Autowired ProductLookup lookup; @RequestMapping("/pi/{productId}") public ProductInformation getProductInformation(@PathVariable String productId) { ProductInformation productInformation = lookup.byId(productId); return productInformation; } @RequestMapping("/query/{query}") public List<String> lookupProductByTitle(@PathVariable String query, HttpServletRequest request) { //to be developed later } } If you compare the code of the servlet with the preceding code, you can see that this is much simpler. We do not need to deal with the HttpServletRequest object, call an API to get a parameter, or create an HTML output and write it to the response. The framework does this. We annotate the @RestController class, telling Spring that this is a controller that utilizes the REST web services; thus, it will by default create a JSON response from the object we return. We do not need to care about the conversion of the object to JSON, although we can if there is really a need. The object will automatically be converted to JSON using the field names used in the class and the field values of the instance we return. If the object contains more complex structures than just plain String, int, and double values, then the converter is prepared for nested structures and the most common data types. To have different code handling and different URLs on the servlet, all we need to do is to annotate the method with @RequestMapping, providing the path part of the URL. The {productId} notation inside the mapping string is readable and easy to maintain. Spring just cuts the value from there and puts it for us in the productId variable, as requested by the @PathVariable annotation. The actual lookup of the product is not implemented in the controller. That is not the function of the controller. The controller only decides what business logic to invoke and what view to use. A part of it is implemented in the framework, and the very small part you can see the preceding code. The business logic is implemented in a service class. An instance of this class is injected to the lookup field. This is also done by Spring. The actual work we have to do is to invoke the business logic, which this time, since we have only one, is fairly easy. Most of these things seem magic without some more details about what the framework does for us. Therefore, before going on, we will have a look at the building blocks: JSON, REST, MVC, and a bit of the Spring framework. JSON JSON stands for JavaScript Object Notation. It is defined on the site, http://www.json.org/. This is a textual notation in the same way as the object literals are defined in JavaScript . An object representation starts with the { character and ends with the } character. The text in between defines the fields of the objects in the form, string : value. The string is the name of the field, and since JSON wants to be language agnostic, it allows any characters to be a part of the name of a field, and thus this string (as well as any string in JSON) should start and end with the " characters. This may seem strange and, many times, when you start working with JSON, it is easy to forget and write { myObject : "has a string" } instead of the correct { "myObject" : "has a string" } notation. Commas separate the fields. You can also have arrays in JSON. They start and end with [ and ] characters, respectively, and they contain comma-separated values. The value in an object field or in an array can be a string, a number, an object, an array, or one of the constants, true, false, and null. Generally speaking, JSON is a very simple notation to describe data that can be stored in an object. It is easy to write using text editors and easy to read, and thus it is easier to debug any communication that uses JSON instead of more complex formats. Ways to convert JSON to a Java object and the other way round, are readily available in libraries that we will use in this chapter. A sample JSON object that describes a product from our sample code is also available in the source code of the program, as follows: {"id":"125","title":"Bar Stool","description":"another furniture","size":[20.0,2.0,18.0],"weight":300.0} Note that the formatting of JSON does not require a new line, but at the same time, this is also possible. Program-generated JSON objects are usually compact and are not formatted. When we edit some object using a text editor, we tend to format the indentation of the fields in the same way as we usually do in Java programming. REST There is no exact definition of the REST protocol. It stands for Representational state transfer, which probably does not mean a thing to someone who has never heard of it. When we program the REST API, we use the HTTP(S) protocol. We send simple requests to the server, and we get simple answers that we program. This way, the client of the web server is also a program (by the way, the browser is also a program) that consumes the response from the server. The format of the response, therefore, is not HTML formatted using CSS and enriched by client-side functionalities by JavaScript, but rather some data descriptive format such as JSON. REST does not set restrictions on the actual format, but these days, JSON is the most widely used. The wiki page that describes REST is available at https://en.wikipedia.org/wiki/Representational_state_transfer. REST interfaces are usually made simple. The HTTP requests almost always use the GET method. It also makes the testing of REST services simple since nothing is easier than issuing a GET request from a browser. POST requests are only used when the service performs some transaction or change on the server, and that way, the request is sending data to the server rather than getting some data. In our application, we will use the GET method to query a list of products and get information about a product, and we will only use POST to order products. The application that serves these requests will run in a servlet container. You have learnt how to create a naked servlet without the use of a framework. In this chapter, we will use the Spring framework, which offloads many of the tasks from the developer. There are many program constructs in servlet programming that are just the same most of the time. They are called boilerplate code. The Spring framework utilizes the Model View Controller design pattern to develop web applications; thus, we will look at it in brief, before discussing Spring in general. Model View Controller Model View Controller (MVC) is a design pattern. Design patterns are programming constructs: simple structures that give some hint on how to solve some specific problems. The term, design pattern was coined and formally described in the book, Design Patterns, Elements of Reusable Object-Oriented Software, written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. The book defines a design pattern as a structure with a name, a problem, and a solution. The name describes the pattern and gives the vocabulary for the developer community to use when talking about these patterns. It is important that different developers use the same language terminology in order to understand each other. The problem describes the situation, that is, the design problem where the pattern can be applied. The solution describes classes and objects and the relations between them, which contribute to a good design. One of them is MVC, which is suitable for programming web applications but generally for any application that has a user interface. In our case, we do not have a classical user interface because the client is also a program; still, MVC can be and is a good choice to use. The MVC pattern, as the name also indicates, has three parts: a model, a view, and a controller. This separation follows the single responsibility principle, requiring one part for each distinct responsibility. The controller is responsible for handling the inputs of the system, and it decides what model and view to use. It controls the execution but usually does not do any business logic. The model does the business logic and contains the data. View converts the model data to a representation that is consumable by the client. MVC is a well-known and widely used design pattern, and it is directly supported by Spring in such a way that when you create a web application, you program the controller built into the framework, using annotations; thus, you essentially configure it. You can program the view, but it is more likely that you will use one that is built into the framework. You will want to send data to the client in XML, JSON, or HTML. If you are very exotic, you may want to send YAML, but generally, that is it. You do not want to implement a new format that needs to be programmed on the server and, since this is new, also on the client. We create the model, and this time, we also program it. After all, that is the business logic. Frameworks can do many things for us, mainly the things that are the same for most of the applications but for the business logic. Business logic is the code that distinguishes our code from other programs. That is what we have to program. On the other hand, that is what we like to do. Focus on the business code and avoid all boilerplate provided by the framework. Now that we know what JSON, REST, and the general Model View Controller design pattern are, let's look at how these are managed by Spring and how we can put these technologies into action. Spring framework The Spring framework is a huge one with several modules. The first version of the framework was released in 2003, and since then, there have been four major releases delivering new and enhanced features. Currently, Spring is the de facto enterprise framework used, perhaps more widely than the standard EJB 3.0 Spring supports dependency injection, Aspect-Oriented Programming (AOP), persistence for SQL and NoSQL databases in a conventional and Object Relational Mapping way, transactional support, messaging, web programming, and many other features. You can configure it using XML configuration files, annotations, or Java classes. Architecture of Spring Spring is not monolithic. You can use a part of it, or only some of the features. You can include some of the modules of Spring that you need and leave out others. Some modules depend on some others, but Gradle, Maven, or some other build tool handles that. The following image shows you the modules of the Spring framework for version 4: Spring is constantly developing since its first release, and it is still considered as a modern framework. The core of the framework is a dependency injection container similar to the one we saw in the previous chapter. As the framework developed, it also supported AOP and many other enterprise functionalities, such as message oriented patterns and web programming with an implementation of Model View Controller, supporting not only servlets but also portlets and WebSockets. Since Spring targets the enterprise application arena, it also supports database handling in many different ways. It supports JDBC using templates, Object Relational Mapping (ORM), and transaction management. In the sample program, we use a fairly recent module: Spring boot. This module makes it extremely easy to start writing and running applications, assuming a lot of configurations that are usually the same for many programs. It contains an embedded servlet container that it configures for default settings and configures Spring wherever it is possible, so we can focus on the programming aspect rather than on the Spring configuration. Spring core The central element of the core module is the context. When a Spring application starts, the container needs a context in which the container can create different beans. This is very general and true for any dependency injection container. If we programmatically create two different contexts, they may live independent of each other in the same JVM. If there is a bean declared as a singleton so that there should be only one single instance of it, then the container will create a single instance of it for a context when we need one instance. The objects representing the context have a reference to the object that we have already created. If there are multiple contexts, however, they will not know that there is another context in the JVM that already has an instance, and the container will create a new instance of the singleton bean for the other context. Usually, we do not use more than one context in a program, but there are numerous examples of there being many contexts in a single JVM. When different servlets run in the same servlet container, they run in the same JVM separated by the class loader and they may each use Spring. In this case, the context will belong to the servlet and each will have a new context. In the previous chapter, we used Guice. The Spring context is similar to the Guice injector. In the previous chapter, I was cheating a bit because I was programming Guice to create a new injector for each request. This is far from optimal, and Guice provides an injector implementation that can handle servlet environments. The reason for cheating was that I wanted to focus more on the DI architecture essentials, and I did not want to complicate the code by introducing a complex (well, more complex) implementation of the injector. In the Spring context behavior, what it does, is defined by the interface ApplicationContext. There are two extensions of this interface and many implementations. ConfigurableApplicationContext extends ApplicationContext, defining setters, and ConfigurableWebApplicationContext defines methods needed in the web environment. When we program web applications, we usually do not need to interfere directly with the context. The framework configures the servlet container programmatically, and it contains servlets that create the context and invoke our methods. This is all boilerplate code created for us. The context keeps track of the beans created, but it does not create them. To create beans, we need bean factories (at least one). The topmost interface of bean factories in Spring is BeanFactory. The difference between an object and a bean is that a bean factory creates the bean, it is registered in the context, and it has a String name. This way, the program can refer to the bean by the name. Different beans can be configured in several different ways in Spring. The oldest approach is to create an XML file that describes the different beans, specifying the names, the class that has to be instantiated to create the bean, and fields in case the bean needs other beans to be injected for its creation. The motivation behind this approach is that this way, the bean wiring and configuration can be totally independent of the application code. It becomes a configuration file that can be maintained separately. If we have a large application that may work in several different environments, the access to inventory data may be available in multitude ways. In one environment, the inventory is available by calling SOAP services. In another environment, the data is accessible in an SQL database. In the third environment, it can be available in some NoSQL store. Each of these accesses is implemented as a separate class, implementing a common inventory access interface. The application code depends only on the interface, and it is the container that has to provide one or the other implementation. When the configuration of the bean wiring is in XML, then only this XML file is to be edited, and the code can be started with the implementation of the interface that is suitable for that environment. The next possibility is to configure the beans using annotations. Many times, we use beans and Spring not because there are many implementations for a bean functionality, but because we want to separate the creation of the object instance from the functionality. This is a good style: separation of the concerns even if the implementation is single without alternatives. However, in this case, creating the XML configuration is redundant. If there is an interface and a single implementation of it in our code, then why should I specify in an XML that by creating an object with a class that implements that interface, I should use the class that implements that interface? Quite obvious, isn't it? We do not like programming things that can be automated. To signal that a class can be used as a bean, and to possibly provide a name, we can use the @Component annotation. We do not need to provide a name as an argument. In that case, the name will be an empty string, but why have a name if we do not refer to it? Spring scans all the classes that are on the classpath and recognizes the classes annotated, and it knows that they are the candidates to be used for bean creation. When a component needs another bean to be injected, the field can be annotated with @Autowired or @Inject. The @Autowired annotation is a Spring annotation and existed before the @Inject annotation was standardized. If you intend to use your code outside of the Spring container, it is recommended to use standard annotations. Functionally, they are equivalent. In our code, when Spring creates an instance of the ProductInformationController component, it sees that it needs an instance of ProductLookup. This is an interface, and thus, Spring starts to look for some class that implements this interface, creates an instance of it, possibly first creating other beans, and then injects it, setting the field. You can decide to annotate the setter of the field instead of the field itself. In such a case, Spring will invoke the setter even if the setter is private. You can inject dependencies through constructor arguments. The major difference between the setter, field injection, and constructor injection is that you cannot create a bean without dependency in case you use constructor injection. When the bean is instantiated, it should and will have all other beans injected so that it depends on using the constructor injection. At the same time, the dependencies that need to be injected through the setter injection, or directly into a field, could be instantiated later by the container sometime between instantiating the class and readying the bean. This slight difference may not seem interesting or important until your constructor code may become more complex than the simple dependency settings or until the dependencies become complex. In the case of a complex constructor, the code should pay attention to the fact that the object is not fully created. This is generally true for any constructor code, but in the case of beans created by a dependency injection container, it is even more important. Thus, it may be advisable to use constructor injection. In that case, the dependencies are there; if a programmer makes a mistake, forgetting that the object is not fully initialized, and uses it in the constructor or a method that is called from a constructor, the dependency is there. Also, it is clean and well-structured to use the constructor to initialize the dependencies and have those fields declared final. On the other hand, constructor injection has its downsides. If different objects depend on each other and there is a ring in the dependency graph, then Spring will face a hard time if you use constructor dependencies. When class A needs class B and the other way round, as the simplest circle, then neither A nor B can be created without the other if the dependency injection is constructor dependency. In situations like this, the constructor injection cannot be used, and the circle should be broken at least as a single dependency. In situations like this, setter injection is inevitable. Setter injection may also be better when there are optional dependencies. Many times, some class may not need all its dependencies at the same time. Some class may use a database connection or a NoSQL database handle but not both at the same time. Although it may also be a code smell and probably a sign of poor OO design, it may happen. It may be a deliberate decision to do that because the pure OO design would result in too deep object hierarchies and too many classes, beyond the maintainable limit. If such is the situation, the optional dependencies may be better handled using setter injection. Some are configured and set; some are left with default values, usually null. Last but not least, we can configure the container using Java classes in case the annotations are not enough. For example, there are multiple implementations of the ProductLookup interface, as it is, in our code base. (Don't worry if you did not recognize that; I have not told you about that yet.) There is a ResourceBasedProductLookup class that reads properties files from the package and is mainly to test the application, and there is RestClientProductLookup, which is a production-like implementation of the interface. If I have no other configuration than annotating the lookup field with @Autowired, Spring will not know which implementation to use and will reward the use during startup with the following error message: Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enab 2016-11-03 07:25:01.217 ERROR 51907 --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: Parameter 0 of constructor in packt.java9.by.example.mybusiness.productinformation.ProductInformationController requi - resourceBasedProductLookup: defined in file [/.../sources/ch07/productinformation/build/classes/main/packt/ - restClientProductLookup: defined in file [/.../sources/ch07/productinformation/build/classes/main/packt/jav Action: Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to This is a fairly self-explanatory error message; it tells a lot. Now is the time when we can configure the bean in XML, but at the same time, we can also configure it using Java. Many developers do not get the point the first time. I did not get it either. The whole XML configuration was to separate the configuration from the code. It was to create the possibility that a system administrator changes the configuration and is free to select one or the other implementation of some interface, wiring the application together. Now Spring tells me that it is better to return to the programmatic way? At the same time, I could hear concerns for many years that XML is not really any better than Java code. XML writing is essentially programming, except that the tooling and IDE support is not as good for XML as it is for Java code (the latter developed a lot in recent years, although for Spring XML configuration). To understand the concept of returning to Java code from XML, we have to get back to the pure reason and aim of the XML way of configuration. The main advantage of XML Spring configuration is not that the format is not programmatic but rather that the configuration code is separated from application code. If we write the configuration in Java and keep those configuration classes to the bare minimum, and they stay as they should, then the separation of application versus configuration code still stands. It is only the format of the configuration that we change from XML to Java. The advantages are numerous. One is that the names of the classes are recognized by the IDE as we edit and we can have autocomplete in Java (note that this also works using XML in some of the IDEs utilizing some of the extensions of plugins). In the case of Java, IDE support is ubiquitous. Java is more readable than XML. Well, this is a matter of taste, but most of us like Java more than XML. System administrators can also edit Java code. When they edit the XML configuration, they usually have to extract it from a JAR or WAR file, edit it, and then package the archive again. In the case of Java editing, they also have to issue a gradle war command or something similar. This should not be a showstopper for a system manager who runs Java applications on a server. And again, it is not Java programming. It is only editing some Java code files and replacing some class name literals and string constants. We follow this approach in our sample application code. We have two configuration files in the application: one for local deployment and testing and another for production. The @Profile annotation specifies which profile the configuration should use. The profile, when the code is executed, can be specified on the command line as a system property, as follows: $ gradle -Dspring.profiles.active=local bootRun The configuration class is annotated with @Configuration. The methods that are bean factories are annotated with @Bean: package packt.java9.by.example.mybusiness.productinformation; import ... @Configuration @Profile("local") public class SpringConfigurationLocal { @Bean @Primary public ProductLookup productLookup() { return new ResourceBasedProductLookup(); } @Bean public ProductInformationServiceUrlBuilder urlBuilder(){ return null; } } The bean factory simply returns a new instance of the ResourceBasedProductLookup class that implements the ProductLookup interface. This implementation can be used to run the application for local testing when there are no external services to rely on. This implementation reads the product data from local resource files packaged into the JAR application. The production version of the configuration is not much different, but as it may be expected, there are a few more things to configure: @Configuration @Profile("production") public class SpringConfiguration { @Bean @Primary public ProductLookup productLookup() { return new RestClientProductLookup(urlBuilder()); } @Bean public ProductInformationServiceUrlBuilder urlBuilder(){ return new ProductInformationServiceUrlBuilder( "http://localhost"); } } This version of the ProductLookup service class uses an external REST service to retrieve the data that it will present to the clients. To do so, it needs the URLs of these services. Such URLs should usually be configured. In our example, we implement a solution where these URLs can be computed on the fly. I tried to make up a situation where it may be needed in real life, but all reasoning was contorted and I gave up. The real reason is that, this way, we can see code that contains a bean that needs another bean to be injected. For now, note that the ProductInformationServiceUrlBuilder instance bean is defined in the same way as the ProductLookup bean, and when it has to be injected into the constructor of the ProductLookup bean, its defining bean method is used and not the following expression directly: new ProductInformationServiceUrlBuilder("http://localhost"); The latter may work, but not in all situations and we should not use it. For the reasons, we will return when we discuss AOP with Spring in a subsequent section. Also note that there is no need to define an interface to define a bean. The type that the bean method returns can also be a class. The context will use the method that fits the needed type, and if there are more than one suitable types and the configuration is not precise enough, as we saw, the container will log an error and will not work. In the configuration that serves the local profile, we create a null value for ProductInformationServiceBuilder. This is because we do not need it when we use local testing. Also, if any method from this class is invoked, it will be an error. Errors should be detected as soon as possible; thus, a null value is a good choice. The ProductInformationServiceUrlBuilder class is very simple: package packt.java9.by.example.mybusiness.productinformation; public class ProductInformationServiceUrlBuilder { private final String baseUrl; public ProductInformationServiceUrlBuilder(String baseUrl) { this.baseUrl = baseUrl; } public String url(String service, String parameter) { final String serviceUrl; switch (service) { case "pi": serviceUrl = baseUrl + ":8081/product/{id}"; break; case "query": serviceUrl = baseUrl + ":8081/query/{query}"; break; case "inventory": serviceUrl = baseUrl + ":8083/inventory/{id}"; break; default: serviceUrl = null; break; } return serviceUrl; } } This bean also needs a constructor parameter, and we used a string constant in the configuration. This clearly shows that it is possible to use a simple object to initialize some of the dependencies (what would stop us, it is pure Java after all), but it may hinder the working of some Spring features. Service classes We have two service classes. These classes serve the controllers with data and implement the business logic, no matter how simple they are. One of the service class implementations calls REST-based services, while the other one reads data from properties files. The latter can be used to test the application offline. The one that calls REST services is used in the production environment. Both of them implement the ProductLookup interface: package packt.java9.by.example.mybusiness.productinformation; import java.util.List; public interface ProductLookup { ProductInformation byId(String id); List<String> byQuery(String query); } stores the whole database in a map called products. It is filled from the properties files when one of the service methods is invoked. The private method loadProducts is invoked from each of the service methods when they start, but it loads the data only if it is not loaded yet: ResourceBasedProductLookup package packt.java9.by.example.mybusiness.productinformation.lookup; import... @Service public class ResourceBasedProductLookup implements ProductLookup { private static Logger log = LoggerFactory.getLogger(ResourceBasedProductLookup.class); The class is annotated using @Service. This annotation is practically equivalent to the @Component annotation. This is only an alternative name to the same annotation. Spring also handles the @Component annotation such that if an annotation interface is annotated using the @Component annotation, the annotation can also be used to signal that a class is a Spring component. You can write your own annotation interfaces if you want to signal for better readability that a class is not a simple component but some other special type. For example, start up your IDE and navigate to the source code of the org.springframework.stereotype.Service interface: private ProductInformation fromProperties(Properties properties) { final ProductInformation pi = new ProductInformation(); pi.setTitle(properties.getProperty("title")); pi.setDescription(properties.getProperty("description")); pi.setWeight( Double.parseDouble(properties.getProperty("weight"))); pi.getSize()[0] = Double.parseDouble(properties.getProperty("width")); pi.getSize()[1] = Double.parseDouble(properties.getProperty("height")); pi.getSize()[2] = Double.parseDouble(properties.getProperty("depth")); return pi; } The fromProperties method creates an instance of ProductInformation and fills it from the parameters given in the Properties object. The Properties class is an old and widely used type. Although there are more modern formats and classes, this is still widely used and it is likely that you will meet this class. This is the very reason we use it here. is a simple Data Transfer Object (DTO) that contains no logic, only fields, setters, and getters. It also contains a constant, emptyProductInformation, holding a reference to an instance of the class with empty values. ProductInformation A Properties object is similar to a Map object. It contains String values assigned to String keys. There are methods, as we will see in our examples, that help the programmer to load a Properties object from a socalled properties file. Such a file usually has the .properties extension, and it contains key value pairs in the following format: key=value For example, the 123.properties file contains the following: id=123 title=Book Java 9 by Example description=a new book to learn Java 9 weight=300 width=20 height=2 depth=18 The properties files are used to store simple configuration values and are almost exclusively used to contain language-specific constants. This is a very contorted use because properties files are ISO Latin-1 encoded files, and in case you need to use some special UTF-8 characters, you have to type them using the \uXXXX format or using the native2ascii converter program. You cannot save them simply as UTF-8. Nevertheless, this is the file format used for language-specific strings used for program internationalization (also abbreviated as i18n because there are 18 characters between the starting i and the last n). To get the Properties object, we have to read the files in the project and get them packaged into a JAR file. The Spring class, PathMatchingResourcePatternResolver, helps us in doing so. Gosh, yes, I know! We have to get used to these long names when we use Spring. Anyway, such long and descriptive names are widely used in an enterprise environment and they are needed to explain the functionality of the classes. We declare a map that will contain all the products during the testing: final private Map<String, ProductInformation> products = new HashMap<>(); The key is the product ID, which is a string in our example. The values are the ProductInformation objects that we fill up using the fromProperties method: private boolean productsAreNotLoaded = true; The next field signals that the products are not loaded: Novice programmers usually use the opposite value with the name productsAreLoaded and set to false by default. In that case, the only place where we will read a value will negate the value, or the main branch of the if command becomes the do nothing part. Neither is a best practice. private void loadProducts() { if (productsAreNotLoaded) { try { Resource[] resources = new PathMatchingResourcePatternResolver() .getResources( "classpath:products/*.properties"); for (Resource resource : resources) { loadResource(resource); } } productsAreNotLoaded = false; } catch (IOException ex) { log.error("Test resources can not be read",ex); } } } The getResources method returns all the resources (files) that are on the classpath under the products directory and that have a.properties extension: private void loadResource(Resource resource) throws IOException { final int dotPos = resource.getFilename().lastIndexOf('.'); final String id = resource.getFilename().substring(0, dotPos); Properties properties = new Properties(); properties.load(resource.getInputStream()); final ProductInformation pi = fromProperties(properties); pi.setId(id); products.put(id, pi); } The product ID is given by the name of the file. This is calculated using simple string manipulation, cutting off the extension. The Resource can also provide an input stream that the Properties class's load method can use to load all the properties at once from the file. Finally, we save the new ProductInformation object in the map. We also have a special noProduct list that is empty. This is returned if there is no product for the query when we want to search for products: private static final List<String> noProducts = new LinkedList<>(); The product lookup service just takes a product from the Map and returns it, or if it does not exist, it returns an empty product: @Override public ProductInformation byId(String id) { loadProducts(); if (products.containsKey(id)) { return products.get(id); } else { return ProductInformation.emptyProductInformation; } } The query is a bit more complex. It implements searching for a product by title. Real-life implementations may implement a more complex logic, but this version is for local testing only; thus, the search by title is enough, perhaps even more complex than would be really necessary: @Override public List<String> byQuery(String query) { loadProducts(); List<String> pis = new LinkedList<>(); StringTokenizer st = new StringTokenizer(query, "&="); while (st.hasMoreTokens()) { final String key = st.nextToken(); if (st.hasMoreTokens()) { final String value = st.nextToken(); log.debug("processing {}={} query", key, value); if (!"title".equals(key)) { return noProducts; } for (String id : products.keySet()) { ProductInformation pi = products.get(id); if (pi.getTitle().startsWith(value)) { pis.add(id); } } } } return pis; } The service class that implements the production functionality is much simpler. Strange, but many times the test code is more complex than the production code: package packt.java9.by.example.mybusiness.productinformation.lookup; import ... @Component public class RestClientProductLookup implements ProductLookup { private static Logger log = LoggerFactory.getLogger(RestClientProductLookup.class); final private ProductInformationServiceUrlBuilder piSUBuilder; public RestClientProductLookup( ProductInformationServiceUrlBuilder piSUBuilder) { this.piSUBuilder = piSUBuilder; } The constructor is used to inject the URL builder bean and this is all the auxiliary code the class has. The rest are the two service methods: @Override public ProductInformation byId(String id) { Map<String, String> uriParameters = new HashMap<>(); uriParameters.put("id", id); RestTemplate rest = new RestTemplate(); InventoryItemAmount amount = rest.getForObject( piSUBuilder.url("inventory"), InventoryItemAmount.class, uriParameters); if ( amount.getAmount() > 0) { return rest.getForObject(piSUBuilder.url("pi"), ProductInformation.class, uriParameters); } else { return ProductInformation.emptyProductInformation; } } The byId method first calls the inventory service to see if there are any products on the inventory. This REST service returns a JSON that has the format, { amount : nnn }; thus, we need a class (so simple that we do not list here) that has the int amount field, the setter, and the getter. The Spring RestTemplate provides an easy way to access a REST service. All it needs is the URL template, a type that is used to convert the result, and a Map object with the parameters. The URL template string may contain parameters in the same way as the request mapping in the Spring controllers, the name of the parameter being between the { and } characters. The template class provides simple methods to access REST services. It automatically does marshaling, sending parameters, and un-marshaling, receiving the response. In the case of a GET request, the marshaling is not needed. The data is in the request URL, and the {xxx} placeholders are replaced with the values from the map supplied as a third argument. The unmarshaling is readily available for most of the formats. In our application, the REST service sends JSON data, and it is indicated in the response Content-Type HTTP header. RestTemplate converts the JSON to the type provided as argument. If ever the server decides to send the response in XML, and it will also be indicated in the HTTP header, RestTemplate will handle the situation automatically. As a matter of fact, looking at the code, we cannot tell how the response is encoded. This is also nice because it makes the client flexible and at the same time, we do not need to deal with such technical details. We can focus on the business logic. At the same time, the class also provides configuration parameters in the case of marshaling or some other functionality so that it automatically needs that. You can, for example, provide marshaling methods, though I recommend that you use whatever is available by default. In most cases, when a developer thinks that there is a need for a special version of any of these functions, the original design of their code is flawed. The business logic is very simple. We first ask the inventory if there is any product in stock. If there is (more than zero), then we query the product information service and return the details. If there is none, then we return an empty record. The other service is even simpler. It simply calls the underpinning service and returns the result: @Override public List<String> byQuery(String query) { Map<String, String> uriParameters = new HashMap<>(); uriParameters.put("query", query); RestTemplate rest = new RestTemplate(); return rest.getForObject( piSUBuilder.url("query"), List.class, uriParameters); } } Compiling and running the application We use gradle to compile and run the application. Since the application does not have any specific configuration that would not appear in most similar applications, it is wise to use the Spring boot. The Spring boot makes it extremely simple to create and run a web application. We need a Java standard public static void main method that starts up the application via Spring: package packt.java9.by.example.mybusiness.productinformation; import ... @SpringBootApplication( scanBasePackageClasses = packt.java9.by.example.mybusiness.SpringScanBase.class) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } The method does nothing but start the StringApplication class's run method. It passes the original arguments and also the class that the application is in. Spring uses this class to read the annotation. The @SpringBootApplication annotation signals that this class is a Spring boot application and provides arguments to configure the packages that contain the application. To do so, you can provide the name of the package that contains the classes, but you can also provide a class in the base package that contains all the classes that Spring has to be aware of. You may not be able to use the class version of the annotation parameter because the root package may not contain any class, only sub-packages. At the same time, providing the name of the root package as String, will not reveal any typo or misalignment during compile time. Some IDE may recognize that the parameter is supposed to be a package name, or it may scan the strings of the program for package names when you refactor or rename a package and give you support for that, but this is more heuristics only. It is a common practice to create a placeholder class that does nothing in the root package in case there is no class there. This class can be used to specify scanBasePackageClasses as an annotation parameter instead of scanBasePackages that needs String. In our example, we have an empty interface, SpringScanBase, as a placeholder. Spring scans all the classes that are on the classpath, recognizes the components and field annotations that it can interpret, and uses this knowledge to create beans without configuration when needed. Note that the abstract class, ClassLoader, included in the JDK does not provide any class scanning method. Since Java environments and frameworks can implement their own ClassLoaders, it is possible (but very unlikely) that some implementation does not provide the scanning functionality provided by the URLClassLoader. URLClassLoader is a non-abstract implementation of the class loading functionality and is a part of the JDK just as well as ClassLoader. We will discuss the intricacies of the class loading mechanism in the subsequent chapters. The gradle build file contains the usual things. It specifies the repositories, the plugins for Java, the IDEs, and also for Spring boot. It also specifies the name of the JAR file that it generates during build. The most important part is the dependency list: buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.4.1.RELEASE") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'spring-boot' jar { baseName = 'packt-ch07-microservice' version = '1.0.0' } repositories { mavenCentral() } bootRun { systemProperties System.properties } sourceCompatibility = 1.9 targetCompatibility = 1.9 dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-devtools") compile("org.springframework:spring-aop") compile("org.springframework:spring-aspects") testCompile("org.springframework.boot:spring-boot-starter-test") } We depend on Spring boot packages, some test packages, AOP support (which we will look at soon), and also on Spring boot devtools. Spring boot devtools make it possible to restart a web application whenever it is recompiled, without restarting the built-in Tomcat server. Suppose, we start the application using the following command line: gradle -Dspring.profiles.active=production bootRun The Gradle starts up the application and whenever it sees that the classes it runs are modified, it reloads them, and we can test the modified application within a few seconds. The -Dspring.profiles.active=production argument specifies that the production profile should be active. To be able to use this command line parameter, we will also need the bootRun{} configuration closure in the build file. Testing the application The application should have unit tests for each and every class it has except, perhaps, for the DTO classes that contain no functionality. The setters and getters are created by the IDE and are not typed in by the programmer, so it is unlikely that there will be any errors in those. If there is some error related to those classes, it is more likely that it is some integration problem that cannot be discovered using unit tests. Since we discussed unit tests in the previous chapters in detail, we will focus more on integration tests and application tests here. Integration test Integration tests are very similar to unit tests, and many times, novice programmers claim they do unit testing when they actually do integration testing. Integration tests drive the code but do not test the individual classes (units) in isolation, mocking everything that the class may use. Rather, they test the functionality of most of the classes that are needed to perform a test. This way, the integration test does test that the classes are able to work together and not only satisfy their own specifications but also ensure that these specifications work together. In integration test, the external world (like external services) and access to database are mocked only. That is because the integration tests are supposed to run on integration servers, in the same environment where the unit tests are executed, and there these external interfaces may not be available. Many times, databases are mocked using in-memory SQL, and external services are mocked using some mock classes. Spring provides a nice environment to execute such integration tests. In our project, we have a sample integration test: package packt.java9.by.example.mybusiness.productinformation; import ... @RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) @AutoConfigureMockMvc @ActiveProfiles("local") public class ProductInformationControllerTest { @Autowired private MockMvc mockMvc; @Test public void noParamGreetingShouldReturnDefaultMessage() throws Exception { this.mockMvc.perform(get("/pi")).andDo(print()) .andExpect(status().isNotFound()); } @Test public void paramGreetingShouldReturnTailoredMessage() throws Exception { this.mockMvc.perform(get("/pi/123")) .andDo(print()).andExpect(status().isOk()) .andExpect(jsonPath("$.title") .value("Book Java 9 by Example")); } } This is far from being a complete and full-fledged integration test. There are many situations that are not tested, but here it is good as an example. To have all the support for the Spring environment, we have to use the SpringRunner class. The @RunWith annotation is handled by the JUnit framework, all other annotations are for Spring. When the JUnit framework sees that there is a @RunWith annotation and a runner class specified, it starts that class instead of the standard runner. SpringRunner sets up a Spring context for the test and handles the annotations. specifies the applications that we need to test. This helps Spring to read that class and the annotation on that class, identifying the packages to be scanned. @SpringBootTest @AutoConfigureMockMvc tells Spring to configure a mock version of the Model View Controller framework, which can be executed without a servlet container and web protocol. Using that, we can test our REST services without really going to the network. tells Spring that the active profile is local and that Spring has to use the configuration that is denoted by the annotation, @Profile("local"). This is a version that uses the .properties files instead of external HTTP services; thus, this is appropriate for integration testing. @ActiveProfiles The test performs GET requests inside the mocking framework, executes the code in the controller, and tests the returned value using the mocking framework and fluent API in a very readable way. Note that using the properties files and having the service implementation based on properties file is a bit of an overkill. I created this so that it is possible to start up the application interactively without any real backing service. Consider the following command: gradle -Dspring.profiles.active=local bootRun . If we issue the preceding command, then the server starts up using this local implementation. If we only aim for integration testing, then the local implementation of the service classes should be under the test directory and should be much simpler, mainly only returning constant responses for any expected request and throwing errors if any non-expected request comes. Application test Consider the following command: gradle -Dspring.profiles.active=production bootRun If we start up the application issuing the preceding command and fire up the browser to the URL, http://localhost:8080/pi/123, we will get a fat error message on the browser screen. Ouch... It says Internal Server Error, status=500 or something similar. That is because our code wants to connect to the backing services, but we do not have any yet. To have some to test the application on this level, we should create the backing services or at least something that mocks them. The easiest way is to use the soapUI program. The soapUI is a Java program available from https://www.soapui.org/. There is an open source and free version of it, and there is a commercial version. For our purposes, the free version is enough. We can install it in the simplest click-forward way as it has a setup wizard. After that, we can start it up and use the graphical user interface. We create a new test project, Catalog and inventory, and set up two REST mock services in it: Catalog and Inventory, as shown in the following screenshot: We set up, for each of the mock services, requests to be matched and responses. The content of the response is text and can be typed into the text field on the user interface. It is important that we do not forget to set the media type of the response to application/json (the default is XML). Before starting the services, we have to set the port numbers by clicking on the cogwheel to something that is available on the server. Since 8080 is used by the Tomcat server executed by Gradle, and 8082 is used by soapUI to list the mock services that are currently running, I set the catalog to listen on 8081 and inventory on 8083. You can also see these port numbers in the listing of the ProductInformationServiceUrlBuilder class. The soapUI saves the project in an XML file, and it is available for you on GitHub in the project directory. After starting the mock services, the error message disappears from the browser screen when we press refresh: What we see is exactly what we typed into soapUI. If now I change the inventory mock service to return 0 instead of 100, as in the original version, what I get is the following empty record: {"id":"","title":"","description":"","size":[0.0,0.0,0.0],"weight":0.0} The testing even on this level can be automated. Now, we were playing around using the browser and this is something nice. Somehow, I feel I am producing something when there is a program that is really doing something, when I can see that there is some response in the browser window. However, after a while, this becomes boring and testing manually that the application is still working is cumbersome. It is especially boring for those functions that were not changed. The fact is that they do change miraculously many times even when we do not touch the code that influences them. We touch the code that does influence the function except that we are not aware of it. Poor design, poor coding, or maybe we just forgot, but it happens. Regression test is inevitable. Although browser testing user interfaces can also be automated, this time, we are having a REST service that we can test and that is what soapUI is for. We have already installed the tool, we have already started it, and we have some mock services running in it. The next thing is to add a New REST service from URI to the project and specify the URL, http://localhost:8080/pi/{id}, exactly the same way as we did for Spring: When we have a REST service defined in the project, we can create a new Test Suite and a Test Case inside the suite. We can then add a step to the Test Case that will call the REST service using the parameter 123 if we modify the default value, which is the same as the name of the parameter, in this case, id. We can run the test step using the green triangle on the upper-left corner of the window, and since we have the tested application and the soapUI mock services running, we should get an answer in JSON. We have to select JSON on the response side; otherwise, soapUI tries to interpret the response as XML, and since we have a JSON response, it is not too fruitful. What we see is the following window: It is the same response that we saw in the browser. There are no miracles when we program computers. Sometimes, we do not understand what happens, and some things are so complex that they seem to be a miracle, but they are actually not. There is an explanation for everything, it may just not be known to us. In this case, we certainly know what is happening, but why is it any better to see the JSON on the screen of soapUI than it is on the browser? The reason is that soapUI can execute assertions and in some cases, further test steps based on the result of the REST invocation, and the final result is a simple YES or NO. The test is OK, or it FAILS. To add an assertion, click on the Assertions text on the lower-left corner of the window. As you can see in the preceding screenshot, I have already added one that compares the "title" field of the returned JSON with the text "Bar Stool". When we add the assertion, the default value it suggests is the one that was actually returned, which is just a very handy feature. After this, running the whole test suite again will run all the test cases (we have only one), and all the test steps, one after the other (we again have only one), and finally it will display a green FINISHED bar on the UI, as shown in the following screenshot: This is not all that soapUI can do. This is a well-developed test tool that has been in the market for many years. soapUI can test SOAP services and REST services, and it can handle JMS messages. You can create tests of many steps with these calls, loops, and assertions in calls or in separate tests, and in case all else fails, you can do just anything by creating programmed steps in the Groovy language or creating extensions in Java. Servlet filters The services work fine by now and anyone can query the details of our products. That may be a problem. The details of the products are not necessarily public information. We have to ensure that we serve the data only to partners who are eligible to see it. To ensure that, we need something in the request that proves that the request comes from a partner. This information is typically a password or some other secret. It could be placed into the GET request parameters or into the HTTP request header. It is better to put it into the header because the information is secret and not to be seen by anybody. The GET parameters are a part of the URL, and the browser history remembers that. It is also very easy to enter this information into the browser location window, copy paste it, and send it over a chat channel or over e-mail. This way, a user of the application, who is not so educated and concerned about security, may disclose secret information. Although it is not impossible to do the same with information that is sent in an HTTP header, it is not likely to happen. If the information is in the header and somebody sends the information in an e-mail, they probably know what they are doing; they cross a security border willingly and not by simple negligence. To send authentication information along the HTTP request, Spring provides a security module that can easily be configured with annotations and configuration XMLs and/or classes. This time, we will do it a bit differently to introduce servlet filters. We will require that the vendors insert the X-PartnerSecret header into the request. This is a non-standard header, and thus it must have the X- prefix. Following this approach is also some extra security feature. This way, we can prevent the user from reaching the service using a simple browser. There is, at least, a need for some extra plugin that can insert a custom header or some other program such as soapUI. This way, it will ensure that our partners will use the interface programmatically, or if ever they need to test the interface ad hoc, only users with a certain level of technology can do so. This is important to keep the support costs controlled. Since this secret has to be checked in the case of each and every service, we better not insert the checking code into each and every service controller. Even if we create the code properly and factor the check for the secret into a separate class, the invocation of the method asserting that the secret is there and is correct will have to be inserted in each and every controller. The controller does the service; checking the client authenticity is an infrastructure issue. They are different concerns, and thus, they have to be separated. The best way that the servlet standard provides for us is a servlet filter. A servlet filter is a class invoked by the servlet container before the servlet itself if the filter is configured. The filter can be configured in the web.xml configuration file of the servlet container or by using an annotation when we use the Spring boot. The filter does not only get the request and response as parameters but also a third argument of the FilterChain type that it should use to call the servlet or the next filter in the chain. There can be more than one filter defined and they get chained up. The filter may, at its discretion, decide to call or not to call the next in the chain. We put our servlet filter into the auth sub-package of our application: package packt.java9.by.example.mybusiness.productinformation.auth; import ... @Component public class AuthFilter implements Filter { private static Logger log = LoggerFactory.getLogger(AuthFilter.class); public static final int NOT_AUTHORIZED = 401; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; final String secret = httpRequest.getHeader("X-PartnerSecret"); log.info("Partner secret is {}", secret); if ("packt".equals(secret)) { chain.doFilter(request, response); } else { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.sendError(NOT_AUTHORIZED); } } @Override public void destroy() { } } The filter implements the Filter interface that defines three methods. In our case, we do not have any parameters to consider in the filter, and we do not allocate any resources to release; thus, both init and destroy methods are empty. The main work of the filter is the doFilter method. It has three parameters, two of them are the same as the parameters of a servlet and the third is FilterChain. The request is converted to HttpServletRequest, so we can get access to the X-PartnerSecret header through the getHeader method. If the value sent in this header field is good, we call the next in the chain. In our application, there are no more filters configured; therefore, the next in the chain is the servlet. If the secret is not acceptable, then we do not call the next in the chain. Instead, we return the 401 Not Authorized HTTP error to the client. In this application, the secret is very simple. This is the constant string packt. This is not really a big secret, especially now that it is published in this book. A real-life application would require something more cryptic and less known. It is very probable that each partner would use different secrets and that the secret has to change from time to time. When there is an error condition in a servlet that our program handles, it is a good practice to use the HTTP error handling mechanism. Instead of sending back a message with the status code 200 OK and explaining, for example, in a JSON format that the authentication was not successful, we have to send back the 401 code. This is defined by the standard and does not need any further explanation or documentation. There is one thing left in our program, and that is audit logging. Audit logging and AOP We have logging in our sample code and for that we use slf4j, which we covered in the previous chapter. Logging is more or less the decision of the developer and supports technical levels of operation. There, we also touched on a few sentence audit loggings. This type of logging is usually explicitly required in a functional requirement. Generally, AOP is separating the different aspects of code functionality into separate code fragments, and implementing them independent of each other. This is very much the single responsibility principle. This time, it is implemented in a way that not only the different functionalities are implemented separately but also how we connect them together is defined separately. What is executed before and after what other parts are encoded separately gets to the Spring configuration. We have seen something similar already. The dependencies that a class needs to properly operate are defined in a separate segment (XML or Java code). It is not a surprise that in the case of AOP, the same is done using Spring. Aspects are configured in the configuration file or class. A typical aspect is audit logging, and we will use this as an example. There are many topics that can be implemented using aspects, and some of them are even worth implementing that way. We do not want to implement the audit logging code in each business method or class that needs it. Instead, we implement a general aspect and configure the wiring such that whenever a bean method that needs audit logging is invoked, Spring invokes the audit logging. There are other important terminologies that we should understand for AOP and especially how AOP can be configured in Spring. The first and most important is the aspect. This is the functionality that we want to implement, in our example, the audit logging. Join point is the point in execution when an aspect is invoked. When using a full-scale aspect solution in Java that modifies the byte code of the generated class, a join point can be almost anything. It can be access to a field, read or write; it can be the invocation of a method or exception throwing. In the case of Spring, the class byte code is not modified; thus, Spring is not able to identify the access of a field or an exception throwing. Using Spring, a join point is always used when a method is invoked. An advice is how the aspect is invoked at the join point. It can be before advice, after advice, or around advice. When the advice is before, the aspect is invoked before the method is called. When the advice is after, the aspect is invoked after the method is invoked. Around means that the aspect is invoked before the method call, and the aspect also has an argument to call the method and still perform some actions after the method is called. This way, the around advice is very similar to servlet filters. The before advice is called before the method call, and after it returns, the framework will invoke the method. There is no way for the aspect to prevent the invocation of the original method. The only exception is when the aspect, well, throws an exception. The after advice is also affected by exceptions. There can be an after returning advice that is invoked when the method is returning. The after throwing is invoked only if the method were throwing an exception. After finally is invoked in the case of an exception or return. Pointcut is a special string expression that identifies join points. A pointcut expression may match zero, one, or more join points. When the aspect is associated with a pointcut expression, the framework will know the join points and when and where to invoke the aspect. In other words, pointcut is the string that tells when and for which method to invoke the aspect. Even though Spring implementation of AOP does not use AspectJ and does not modify the byte code that was created for the classes, it supports the pointcut expression language. Although this expression language provides more features than what Spring implements, it is a well-established and widely used and accepted expression language to describe pointcuts, and it just would not make sense to invent something new. Introduction is adding methods or fields to a type that already exists and doing it during runtime. Spring allows this AOP functionality to add an interface to an existing type and add an implementation of the interface in the form of an advice class. In our example, we do not use this functionality. Target object is the object that is being advised by the aspect. This is the bean that contains the method around the aspect, that is, before or after the aspect is invoked. That was just a condensed set of definitions, almost like in a math book. If you did not get the point just reading it, don't worry. I did not understand it either. That is why we have the following example, after which all we just covered will make more sense: package packt.java9.by.example.mybusiness.productinformation; import ... @Configuration @Aspect public class SpringConfigurationAspect { private static Logger log = LoggerFactory.getLogger("AUDIT_LOG"); @Around("execution(* byId(..))") public ProductInformation byIdQueryLogging( ProceedingJoinPoint jp) throws Throwable { log.info("byId query is about to run"); ProductInformation pi = (ProductInformation) jp.proceed(jp.getArgs()); log.info("byId query was executed"); return pi; } @Around("execution(* url(..))") public String urlCreationLogging(ProceedingJoinPoint jp) throws Throwable { log.info("url is to be created"); String url = (String) jp.proceed(jp.getArgs()); log.info("url created was "+url); return url; } } The class is annotated with the @Configuration annotation so that Spring knows that this class contains the configuration. The @Aspect annotation denotes that this configuration may also contain aspect definitions. The @Around annotation on the methods gives the type of advice, and the argument string for the annotation is the pointcut expression. If the type of advice is different, one of the annotations, @Before, @After, @AfterReturning, or @AfterThrowing, should be used. In our example, we use the @Around aspect to demonstrate the most complex scenario. We log the execution of the target method before and after the execution of the method, and we also call the original method through the ProceedingJoinPoint object. Because the two objects return different types and we want to log differently, we define two aspect methods. The argument of the advice annotation is the pointcut string. In this case, it is a simple one. The first one, execution(* byId(..)), says that the aspect should be invoked for any execution of any method that has the name byId and has any arguments. The second is very similar, except the name of the method is different. These are simple pointcut expressions, but in a large application that heavily uses AOP, they can be very complex. The pointcut expression syntax in Spring mainly follows the syntax used by AspectJ. The expression uses the notion of point cut designator (PCD) that is usually execution. It is followed by the pattern that defines which method to intercept. The general format is as follows: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?) Except for the return type part, all other parts are optional. For example, we can write the following: execution(public * *(..)) This will intercept all public methods. The following expression intercepts all methods that have a name starting with set: execution(* set*(..)) We can use the * character as a joker in the same way as we can use it on the command line in Windows or Unix shell. The argument matching definition is a bit more complex. (..) means any arguments, () means no arguments, and (*) means exactly one argument of any type. The last one can also be used when there are more arguments; for example, (*,Integer) means that there are two arguments, the second being an Integer, and we just do not care what the type of the first one is. Pointcut expressions can be more complex, joining together match expressions with the && (and) and || (or) logical operators, or using the ! (negation) unary operator. Using the @Pointcut() annotation, the configuration can define pointcuts putting the annotations on methods. For example, consider the following: @Pointcut("execution(* packt.java.9.by.example.service.*.*(..))") public void businessService() {} It will define a join point for any method that is implemented in any class in the packt.java.9.by.example.service package. This merely defines the pointcut expression and assigns it to the name businessService, which is given by the name of the method. Later, we can refer to this expression in aspect annotations, for example: @After("businessService()") Note that the use of the method is purely for its name. This method is not invoked by Spring. It is only used to borrow its name to the expression that is defined on it using the @Pointcut annotation. There is a need for something, such as a method, to put this annotation on, and since methods have names, why not use it: Spring does it. When it scans the configuration classes and sees the annotation, it assigns it in its internal structures to the name of the method, and when that name (along with the parenthesis, to confuse the novice programmer mimicking a method call) is used, it looks up the expression for that name. AspectJ defines other designators. Spring AOP recognizes some of them, but it throws IllegalArgumentException because Spring implements only method execution pointcuts. AspectJ, on the other hand, can also intercept object creation for which the PCD is initialization, as an example. Some other PCDs, in addition to execution, can limit an execution PCD. For example, the PCD, within, can be used to limit the aspect to join points belonging to classes within certain packages, or the @target PCD can be used to limit the matching to methods in objects that have the annotation given between ( and ) after the keyword @target in the pointcut expression. There is a PCD that Spring uses that does not exist in AspectJ. This is a bean. You can define a pointcut expression that contains bean(name pattern) to limit the join point to method executions that are in the named bean. The pattern can be the entire name or it can be, as almost any PCD expression matching, * as a joker character. Dynamic proxy-based AOP Spring AOP, when first presented to Java programmers, seems like magic. How does it happen that we have a variable of classX and we call some method on that object, but instead, it executes some aspect before or after the method execution, or even around it, intercepting the call The technique that Spring does is called dynamic proxy. When we have an object, which implements an interface, we can create another object—the proxy object—that also implements that interface, but each and every method implementation invokes a different object called handler, implementing the JDK interface, InvocationHandler. When a method of the interface is invoked on the proxy object, it will call the following method on the handler object: public Object invoke(Object target, Method m, Object[] args) This method is free to do anything, even calling the original method on the target object with the original or modified argument. When we do not have an interface at hand that the class to be proxied implements, we cannot use JDK methods. Luckily, there are widely used libraries, such as cglib, which are also used by Spring and that can do something similar. Cglib can create a proxy object that extends the original class and implements its methods, invoking the handler object's invoke method in a way similar to how the JDK version does for the interface methods. These technologies create and load classes into the Java memory during runtime, and they are very deep technical tools. They are advanced topics. I do not say not to play with them while being a novice Java programmer. After all, what can happen? Java is not a loaded gun. It is, however, important that you do not lose your interest when you do not understand some of the details or something does not work first. Or second. Or third... Keep swimming. AOP implementation in Spring works by generating proxy objects for the target objects, and the handlers invoke the aspects that we define in the Spring configuration. This is the reason you cannot put aspects on final classes or on final methods. Also, you cannot configure aspects on private or protected methods. The protected methods could be proxied in principle, but this is not a good practice, and thus Spring AOP does not support it. Similarly, you cannot put aspects on classes that are not Spring beans. They are created by the code directly and not through Spring and have no chance to return a proxy instead of the original object when the object is created. Simply put, if Spring is not asked to create the object, it cannot create a custom one. The last thing we want to do is to execute the program and see how the aspects perform. The implementation of our audit logging is extremely simple. We use the standard logging, which is not really sufficient for a real-life application of audit logging. The only special thing we do is that we use a logger identified by the name, AUDIT_LOG and not by the name of a class. This is a legitimate use of the loggers in most of the logging frameworks. In spite of the fact that we usually use the class to identify the logger, it is absolutely possible to use a string to identify a logger. In the case of our logging, this string will also be printed on the console in the log lines, and it will visually stand out. Consider the following command: gradle -Dspring.profiles.active=production bootRun If we again start the application with the preceding command, start soapUI for the project, start the mock services, and execute the test, we will see on the console the following log lines that the aspects print: 2016-11-10 2016-11-10 2016-11-10 2016-11-10 2016-11-10 2016-11-10 2016-11-10 2016-11-10 2016-11-10 2016-11-10 2016-11-10 2016-11-10 19:14:09.559 19:14:09.567 19:14:09.626 19:14:09.629 19:14:09.655 19:14:09.666 19:14:09.691 19:14:09.715 19:14:09.716 19:14:09.716 19:14:09.716 19:14:09.725 INFO INFO INFO INFO INFO INFO INFO INFO INFO INFO INFO INFO 74643 74643 74643 74643 74643 74643 74643 74643 74643 74643 74643 74643 ------------------------- [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] o.s.web.servlet.DispatcherServlet o.s.web.servlet.DispatcherServlet p.j.b.e.m.p.auth.AuthFilter AUDIT_LOG AUDIT_LOG AUDIT_LOG p.j.b.e.m.p.l.RestClientProductLookup p.j.b.e.m.p.l.RestClientProductLookup AUDIT_LOG AUDIT_LOG AUDIT_LOG : : : : : : : : : : : : Initializing Spr FrameworkServlet FrameworkServlet Partner secret i byId query is ab url is to be cre url created was amount {id: 123, There items from url is to be cre url created was byId query was e Summary In this chapter, we built a simple business application that supports business-to-business transactions. We implemented a REST service in a microservices (almost) architecture using the features that are provided by the de facto standard enterprise framework: Spring. Looking back at the chapter, it is amazing how few lines of code we wrote to achieve all the functionality, and that is good. The less code we need to develop what we want, the better. This proves the power of the framework. We discussed microservices, HTTP, REST, JSON, and how to use them using the MVC design pattern. We learned how Spring is built up, what modules are there, how dependency injection works in Spring, and we even touched a bit of AOP. This was very important because along with AOP, we discovered how Spring works using dynamic proxy objects, and this is something that is very valuable when you need to debug Spring or some other framework that uses a similar solution (and there are a few frequently used). We started to test our code using a simple browser, but after that we realized that REST services are better tested using some professional testing tool, and for that we used soapUI and built up a simple REST test suite with REST test steps and mock services. Having learnt all that, nothing will stop us from extending this application using very modern and advanced Java technologies, such as reflection (which we have already touched on a bit when we discussed the JDK dynamic proxy), Java streams, lambda expressions, and scripting on the server side. Extending Our E-Commerce Application In the last chapter, we started developing an e-commerce application and we created the functionality to look up products based on their ID and, also, by some parameters. In this chapter, we will extend the functionality so that we can also order the products we selected. While doing so, we will learn new technologies, focusing on functional programming in Java and on some other language features, such as reflection and annotation handling during runtime, and scripting interface. As we did in the previous chapters, we will develop the application step by step. As we discover the newly learnt technologies, we will refactor the code to enroll the new tools and methods to produce more readable and effective code. We will also mimic the development of real-life projects in the sense that at the start, we will have simple requirements, and later, new requirements will be set as our imagined business develops and sells more and more products. We will become imagined millionaires. We will use the code base of the previous chapter, and we will develop it further, though, in a new project. We will use Spring, Gradle, Tomcat, and soapUI, which are not new after we got acquainted with these in the previous chapter. In this chapter, you will learn the following topics: Annotation processing Using reflection Functional programming in Java using: Lambda expressions Streams Invoking scripts from Java The MyBusiness ordering The ordering process is a little bit more complicated than just looking up products. The order form itself lists products and amounts, and identifies who the customer for that order is. Identifiers give the products. All that we have to do is check that the products are available in our store, and we can deliver them to the given customer. This is the simplest approach; however, with some products, there are more restrictions. For example, when somebody orders a desk-side lamp, we deliver the power cord separately. The reason for this is that the power cord is specific to the country. We deliver different power cords to the United Kingdom and to Germany. One possible approach could be to identify the country of the customer. But this approach does not take into account that our customers are resellers. All customers could be located in the United Kingdom, and at the same time they may want to deliver the lamp with the power cable to Germany. To avoid such situations and ambiguity, it would be apt that our customers order the desk-side lamp and the power cord as separate items in the same order. In some cases, we deliver the desk-side lamp without the power cord, but this is a special case. We need some logic to identify these special cases. Therefore, we have to implement logic to see if there is a power cord for a desk-side lamp and if there is no automatic handling of the order, it is refused. It does not mean that we will not deliver the product. We will only put the order in a queue and some operator will have to look at it. The problem with this approach is that the desk-side lamp is only one product that needs configuration support. The more products we have, the more specialities they may have, and the piece of code that checks the consistency of an order becomes more and more complex until it reaches a level of complexity that is not manageable. When a class or method becomes too complex, the programmers refactor it, splitting up the method or class into smaller pieces. We have to do the same with the product checking. We shouldn't try to create one huge class that checks for the product and all the possible order constellations, but rather we should have many smaller checks so that each checks only one small set. Checking for consistency is simpler in some cases. Checking whether the lamp has a power cord has a complexity any novice programmer can program. We use this example in our code because we want to focus on the actual structure of the code, and not on the complex nature of the check itself. In real life, however, the checks can be fairly complex. Imagine a shop that sells computers. It puts a configuration together: power supply, graphic cards, and motherboard, the appropriate CPU, and the memory. There are many choices and some of them may not work together. In a real-life situation, we need to check that the motherboard is compatible with the memory selected, that it has as many banks as are in the order, that they are appropriately paired (some memories can only be installed in pairs), that there is a compatible slot for the graphics card, and that the power has enough watts to reliably run the whole configuration. This is very complex and is better not mixed up with the code that checks if there is a power cord for a lamp. Setting up the project Since we are still using Spring boot, the build file does not need any modification; we will use it as we will use the same file as in the last chapter. The package structure, however, is a bit different. This time, we do something more complicated than getting a request and responding to whatever the backend services deliver to us. Now, we have to implement complex business logic that, as we will see, needs many classes. When we have more than 10 classes, give or take, in a certain package, it is time to think about putting them into separate packages. The classes that are related to each other and have a similar functionality should be put into one package. This way, we will have a package for the following: The controllers (though we have only one in this example, but usually there are more) Data storing beans that have no more functionality than storing data, thus, fields, setters, and getters Checkers that will help us check power cords when a desk-side lamp is ordered Services that perform different services for the controller The main package for our program that contains the Application class, SpringConfiguration, and some interfaces Order controller and DTOs When a request comes to the server to order a bunch of products, it comes in an HTTPS POST request. The body of the request is encoded in JSON. Till now, we had controllers that were handling GET parameters, but handling POST requests is not much more difficult when we can rely on the data marshalling of Spring. The controller code itself is simple: package packt.java9.by.example.mybusiness.bulkorder.controllers; import ... @RestController public class OrderController { private Logger log = LoggerFactory.getLogger(OrderController.class); private final Checker checker; public OrderController(@Autowired Checker checker) { this.checker = checker; } @RequestMapping("/order") public Confirmation getProductInformation(@RequestBody Order order) { if (checker.isConsistent(order)) { return Confirmation.accepted(order); } else { return Confirmation.refused(order); } } } There is only one request that we handle in this controller: order. This is mapped to the URL, /order. The order is automatically converted from JSON to an order object from the request body. This is what the @RequestBody annotation asks Spring to do for us. The functionality of the controller simply checks the consistency of the order. If the order is consistent, then we accept the order; otherwise, we refuse it. The real-life example will also check that the order is not only consistent but also comes from a customer who is eligible for buying those products and that the products are available in the warehouse or, at least, can be delivered, based on the promises and lead time from the producers. To check the consistency of the order, we need something that does this job for us. As we know that we have to modularize the code and not implement too many things in a single class, we need a checker object. This is provided automatically based on the annotation on the class and also on the constructor of the controller by @Autowired. The Order class is a simple bean, simply listing the items: package packt.java9.by.example.mybusiness.bulkorder.dtos; import ...; public class Order { private String orderId; private List<OrderItem> items; private String customerId; ... setters and getters ... } The name of the package is dtos, which stands for the plural of Data Transfer Object (DTO). DTOs are objects that are used to transfer data between different components, usually over the network. Since the other side can be implemented in any language, the marshaling can be JSON, XML, or some other format that is capable of delivering nothing but data. These classes do not have real methods. DTOs usually have only fields, setters, and getters. The following is the class that contains one item in an order: package packt.java9.by.example.mybusiness.bulkorder.dtos; public class OrderItem { private double amount; private String unit; private String productId; ... setters and getters ... } The order confirmation is also in this package, and though this is also a true DTO, it has some simple auxiliary methods: package packt.java9.by.example.mybusiness.bulkorder.dtos; public class Confirmation { private final Order order; private final boolean accepted; private Confirmation(Order order, boolean accepted) { this.order = order; this.accepted = accepted; } public static Confirmation accepted(Order order) { return new Confirmation(order, true); } public static Confirmation refused(Order order) { return new Confirmation(order, false); } public Order getOrder() { return order; } public boolean isAccepted() { return accepted; } } We provide two factory methods for the class. This is a little violation of the single responsibility principle that purists hate. Most of the time, when the code becomes more complex, such short cuts bite back, and the code has to be refactored to be cleaner. The purist solution would be to create a separate factory class. The use of the factory methods either from this class or from a separated class makes the code of the controller more readable. The major task we have is the consistency check. The code, till this point, is almost trivial. Consistency checker We have a consistency checker class, and an instance of it is injected into the controller. This class is used to check the consistency, but it does not actually perform the check itself. It only controls the different checkers that we provide and invokes them one by one to do the real work. We require that a consistency checker, such as the one that checks whether the order contains a power cord when a desk-side lamp is ordered, implements the ConsistencyChecker interface: package packt.java9.by.example.mybusiness.bulkorder; import ... public interface ConsistencyChecker { boolean isInconsistent(Order order); } The method isInconsistent should return true if the order is inconsistent. It returns false if it does not know whether the order is inconsistent or not, but from the aspect that the actual checker examines the order, there is no inconsistency. Having several ConsistencyChecker classes, we have to invoke one after the other until one returns true or we are out of them. If none of them returns true, then we can safely assume, at least from the automated checkers' point of view, that the order is consistent. We know at the start of the development that we will really have a lot of consistency checkers and not all are relevant for all of the orders. We want to avoid the invocation of each checker for each order. To do so, we implement some filtering. We let products specify what type of checks they need. This is a piece of product information, such as the size or the description. To accommodate this, we need to extend the ProductInformation class. We will create each ConsistencyChecker interface, implementing the class to be a Spring bean (annotated with the @Component annotation), and at the same time, we will annotate them with an annotation that specifies what type of checks they implement. At the same time, ProductInformation is extended, containing a set of Annotation class objects that specify which checkers to invoke. We could simply list the checker classes instead of the annotations, but this gives us some extra freedom in configuring the mapping between the products and the annotations. The annotation specifies the type of the products, and the checker classes are annotated. The desk-side lamp has the PoweredDevice type, and the checker class, NeedPowercord, is annotated with the @PoweredDevice annotation. If there is any other type of products that also needs a power cord, then the annotation of that type should be added to the NeedPowercord class, and our code will work. Since we start diving deep into annotations and annotation handling, we have to first learn what annotations really are. We have already used annotations since Chapter 3, Optimizing the Sort, Making Code Professional but all we knew was how to use them, and that is usually dangerous without understanding what we did. Annotations Annotations are used with the @ character in front of them and can be attached to packages, classes, interfaces, fields, methods, method parameters, generic type declaration and use, and, finally, to annotations. Annotations can be used almost everywhere and they are used to describe some program meta information. For example, the @RestController annotation does not directly alter the behavior of the OrderController class. The behavior of the class is described by the Java code that is inside. The annotation helps Spring to understand what the class is and how it can and should be used. When Spring scans all the packages and classes to discover the different Spring beans, it sees the annotation on the class and takes it into account. There can be other annotations on the class that Spring does not understand. They may be used by some other framework or program code. Spring ignores them as any well-behaving framework. For example, as we will see later, we have in our code base, the NeedPowercord class , which is a Spring bean and, as such, annotated with the @Component annotation. At the same time, it is also annotated with the @PoweredDevice annotation. Spring has no idea about what a powered device is. This is something that we define and use. Spring ignores this. Packages, classes, interfaces, fields, and so on, can have many annotations attached to them. These annotations should simply be written in front of the declaration of the syntactical unit they are attached to. In the case of packages, the annotation has to be written in front of the package name in the package-info.java file. This file can be placed in the directory of the package and can be used to edit the JavaDoc for the package and also to add an annotation to the package. This file cannot contain any Java class since the name, package-info, is not a valid identifier. We cannot just write anything in front of anything as an annotation. Annotations should be declared. They are in the runtime of Java special interfaces. The Java file that declares the @PoweredDevice annotation, for example, looks like this: package packt.java9.by.example.mybusiness.bulkorder.checkers; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface PoweredDevice { } The @ character in front of the interface keyword shows us that this is a special one: an annotation type. There are some special rules; for example, an annotation interface should not extend any other interface, not even an annotation one. On the other hand, the compiler automatically makes the annotation interface so that it extends the JDK interface, java.lang.annotation.Annotation. Annotations are in the source code, and thus, they are available during the compilation process. They can also be retained by the compiler and put into the generated class files, and when the class loader loads the class file, they may also be available during runtime. The default behavior is that the compiler stores the annotation along with the annotated element in the class file, but the class loader does not keep it available for runtime. To handle annotations during the compilation process, the Java compiler has to be extended using annotation processors. This is a fairly advanced topic and there are only a few examples you can meet while working with Java. An annotation processor is a Java class that implements a special interface and is invoked by the compiler when it processes an annotation in the source file that the processor is declared to have an interest in. Annotation retention Spring and other frameworks usually handle annotations during runtime. The compiler and the class loader have to be instructed that the annotation is to be kept available during runtime. To do so, the annotation interface itself has to be annotated using the @Retention annotation. This annotation has one parameter of the RetentionPolicy type, which is an enum. We will soon discuss how annotation parameters should be defined. It is interesting to note that the @Retention annotation on the annotation interface has to be available in the class file; otherwise, the class loaders would not know how to treat an annotation. How do we signal that an annotation is to be kept by the compiler after the compilation process? We annotate the annotation interface declaration. Thus, the declaration of @Retention is annotated by itself and it is declared to be available in runtime. The annotation declaration can be annotated using @Retention(RetentionPolicy.SOURCE), @Retention(RetentionPolicy.CLASS), or @Retention(RetentionPolicy.RUNTIME). Annotation target The last retention type will be the most frequent used. There are also other annotations that can be used on annotation declarations. The @Target annotation can be used to restrict the use of the annotation to certain locations. The argument to this annotation is either a single java.lang.annotation.ElementType value or an array of these values. There is a good reason to restrict the use of annotations. It is much better to get a compilation time error when we place an annotation in the wrong place than hunting during runtime why the framework ignores our annotation. Annotation parameters Annotations, as we saw, can have parameters. To declare these parameters in the @interface declaration of the annotation, we use methods. These methods have a name and a return value, but they should not have an argument. You may try to declare some parameters, but the Java compiler will be strict and will not compile your code. The values can be defined at the place where the annotation is used, using the name of the method and with the = character, assigning to them some value that is compatible with the type of the method. For example, let's suppose that we modify the declaration of the annotation PoweredDevice to the following: public @interface ParameteredPoweredDevice { String myParameter(); } In such a case, at the use of the annotation, we should specify some value for the parameter, such as the following: @Component @ParameteredPoweredDevice(myParameter = "1966") public class NeedPowercord implements ConsistencyChecker { ... If the name of the parameter is a value and at the place of use of the annotation there is no other parameter defined, then the name, "value", may be skipped. For example, modifying the code as follows is a handy shorthand when we have only one parameter: public @interface ParameteredPoweredDevice{ String value(); } ... @Component @ParameteredPoweredDevice("1966") public class NeedPowercord implements ConsistencyChecker { ... We can define optional parameters also using the default keyword following the method declaration. In this case, we have to define a default value for the parameter. Modifying the sample annotation we have further, we still can, but need not, specify the value. In the latter case, it will be an empty string: public @interface ParameteredPoweredDevice { String value() default ""; } Since the value we specify should be constant and calculable during compile time, there is not much use of complex types. Annotation parameters are usually strings, integers, and sometimes, doubles, or other primitive types. The exact list of the types given by the language specification is as follows: Primitive (double, int, and so on) String Class An enum Another annotation An array of any of the aforementioned types We have seen examples of String and also that enum:Retention and Target both have enum parameters. The interesting part we want to focus on is the last two items of the preceding list. When the value of the parameter is an array, the value can be specified as comma-separated values between the { and} characters. For example: String[] value(); This can then be added to the @interface annotation we can write: @ParameteredPoweredDevice({"1966","1967","1991"}) However, in case there is only one value we want to pass as the parameter value, we can still use the format: @ParameteredPoweredDevice("1966") In this case, the value of the attribute will be an array of length 1. When the value of an annotation is an array of annotation types, things get a bit more complex. We create an @interface annotation (note the plural in the name): @Retention(RetentionPolicy.RUNTIME) public @interface PoweredDevices { ParameteredPoweredDevice[] value() default {}; } The use of this annotation could be as follows: @PoweredDevices( {@ParameteredPoweredDevice("1956"), @ParameteredPoweredDevice({"1968", "2018"})} ) Note that this is not the same as having the ParameteredPoweredDevice annotation with three parameters. This is an annotation that has two parameters. Each parameter is an annotation. The first has one string parameter and the second has two. As you can see, annotations can be fairly complex, and some of the frameworks (or rather the programmers who created them) ran amok using them. Before you start writing a framework, research to see whether there is already a framework that you can use. Also, check whether there is some other way to solve your problem. 99% of annotation handling code could be avoided and made simpler. The less code we write for the same functionality, the happier we are. We programmers are the lazy types and this is the way it has to be. The last example, where the parameter of the annotation is an array of annotations, is important to understand how we can create repeatable annotations. Repeatable annotations Annotate the declaration of the annotation with @Repeatable to denote that the annotation can be applied multiple times at one place. The parameter to this annotation is an annotation type that should have a parameter of type, which is an array of this annotation. Don't try to understand! I'll give an example instead. I already have, in fact: we have @PoweredDevices. It has an argument that is an array of @ParameteredPoweredDevice. Consider that we now annotate this @interface as the following: ... @Repeatable(PoweredDevices.class) public @interface ParameteredPoweredDevice { ... Then, we can simplify the use of @ParameteredPoweredDevice. We can repeat the annotation multiple times and the Java runtime will automatically enclose it in the wrapping class, which, in this case, is @PoweredDevices. In this case, the following two will be equivalent: ... @ParameteredPoweredDevice("1956") @ParameteredPoweredDevice({"1968", "2018"}) public class NeedPowercord implements ConsistencyChecker { ... @PoweredDevices( {@ParameteredPoweredDevice("1956"), @ParameteredPoweredDevice({"1968", "2018"})} ) public class NeedPowercord implements ConsistencyChecker { ... The reason for this complex approach is again an example of backward compatibility that Java strictly follows. Annotations were introduced in Java 1.5 and repeatable annotations have been available only since version 1.8. We will soon talk about the reflection API that we use to handle the annotations during runtime. This API in the java.lang.reflect.AnnotatedElement interface has a getAnnotation(annotationClass) method, which returns an annotation. If a single annotation can appear more than once on a class, method, and so on, then there is no way of calling this method to get all the different instances with all the different parameters. Backward compatibility was ensured by introducing the containing type that wraps the multiple annotations. Annotation inheritance Annotations, just like methods or fields, can be inherited between class hierarchies. If an annotation declaration is marked with @Inherited, then a class that extends another class with this annotation can inherit it. The annotation can be overridden in case the child class has the annotation. Because there is no multiple inheritance in Java, annotations on interfaces cannot be inherited. Even when the annotation is inherited, the application code that retrieves the annotation of a certain element can distinguish between the annotations that are inherited and those that are declared on the entity itself. There are methods to get the annotations and separate methods to get the declared annotations that are declared on the actual element, and not inherited. @Documented annotations The @Documented annotation expresses the intent that the annotation is part of the contract of the entity and, this way, it has to get into the documentation. This is an annotation that the JavaDoc generator looks at when creating the documentation for an element that references the @Documented annotation. JDK annotations There are other annotations defined in the JDK in addition to those that are to be used to define annotations. We have already seen some of these. The most frequently used is the @Override annotation. When the compiler sees this annotation, it checks that the method really overrides some inherited method. Failing to do so will result in an error, saving us from miserable runtime debugging. The @Deprecated annotation signals in the documentation of a method, class, or some other element that the element is not to be used. It is still there in the code, because some users may still use it, but in the case of a new development that depends on the library containing the element, the newly developed code should not use it. The annotation has two parameters. One parameter is since, which can have a string value and may deliver version information about how long or since which version of the method, or class is deprecated. The other parameter is forRemoval, which should be true if the element will not appear in the future versions of the library. Some methods may be deprecated because there are better alternatives but the developers do not intend to remove the method from the library. In such a case, the forRemoval can be set to false. The @SuppressWarning annotation is also a frequently used one, though its use is questionable. It can be used to suppress some of the warnings of the compiler. It is recommended to write code, if possible, which can be compiled without any warning. The @FunctionalInterface annotation declares that an interface intends to have only one method. Such interfaces can be implemented as lambda expressions. You will learn about lambda expressions later in this chapter. When this annotation is applied on an interface and there is more than one method declared in the interface, the compiler will signal compilation error. This will prevent any developer early on from adding another method to an interface intended to be used together with functional programming and lambda expressions. Using reflection Now that you have learnt how to declare annotations and how to attach them to classes and methods, we can return to our ProductInformation class. Recall that we wanted to specify the type of products in this class and that each product type is represented by an @interface annotation. We have already listed it in the previous few pages, the one we will implement in our @PoweredDevice example. We will develop the code assuming that later there will be many such annotations, product types, and consistency checkers that are annotated with @Component and with one or more of our annotations. Getting annotations We will extend the ProductInformation class with the following field: private List<Class<? extends Annotation>> check; Since this is a DTO, and Spring needs the setters and getters, we will also add a new getter and setter to it. This field will contain the list of classes that each class implement one of our annotations and also the built-in JDK interface, Annotation, because that is the way the Java compiler generates them. At this point, this may be a bit murky but I promise that the dawn will break and there will be light as we go on. To get the product information, we have to look it up by ID. This is the interface and service that we developed in the last chapter, except, this time, we have another new field. This is, in fact, a significant difference although the ProductLookup interface did not change at all. In the last chapter, we developed two versions. One of the versions was reading the data from a properties file, the other one was connecting to a REST service. Properties files are ugly and old technology but a must if ever you intend to pass a Java interview or work on enterprise applications developed at the start of the 21st century. I had to include it in the last chapter. It was my own urge to include it in the book. At the same time, while coding for this chapter, I did not have the stomach to keep using it. I also wanted to show you that the same content could be managed in a JSON format. Now, we will extend the implementation of ResourceBasedProductLookup to read the product information from JSON formatted resource files. Most of the code remains the same in the class; therefore, we only list the difference here: package packt.java9.by.example.mybusiness.bulkorder.services; import ... @Service public class ResourceBasedProductLookup implements ProductLookup { private static final Logger log = LoggerFactory.getLogger(ResourceBasedProductLookup.class); private ProductInformation fromJSON(InputStream jsonStream) throws IOException { ObjectMapper mapper = new ObjectMapper(); return mapper.readValue(jsonStream, ProductInformation.class); } ... private void loadProducts() { if (productsAreNotLoaded) { try { Resource[] resources = new PathMatchingResourcePatternResolver(). getResources("classpath:products/*.json"); for (Resource resource : resources) { loadResource(resource); } productsAreNotLoaded = false; } catch (IOException ex) { log.error("Test resources can not be read", ex); } } } private void loadResource(Resource resource) throws IOException { final int dotPos = resource.getFilename().lastIndexOf('.'); final String id = resource.getFilename().substring(0, dotPos); final ProductInformation pi = fromJSON(resource.getInputStream()); pi.setId(id); products.put(id, pi); } ... In the project resources/products directory we have a few JSON files. One of them contains the desk lamp product information: { "id" : "124", "title": "Desk Lamp", "check": [ "packt.java9.by.example.mybusiness.bulkorder.checkers.PoweredDevice" ], "description": "this is a lamp that stands on my desk", "weight": "600", "size": [ "300", "20", "2" ] } The type of product is specified in a JSON array. In this example, this array has only one element and that element is the fully qualified name of the annotation interface that represents the type of product. When the JSON marshaller converts the JSON to a Java object, it recognizes that the field that needs this information is a List, so it converts the array to a list and, also, the elements from String to Class objects representing the annotation interface. Now that we have the resources loaded from JSON formatted resources and we saw how easy it is to read JSON data when using Spring, we can get back to the order consistency check. The Checker class implements the logic to collect the pluggable checkers and to invoke them. It also implements the annotation-based screening so as not to invoke the checkers we don't really need for the actual products in the actual order: package packt.java9.by.example.mybusiness.bulkorder.services; import ... @Component() @RequestScope public class Checker { private static final Logger log = LoggerFactory.getLogger(Checker.class); private final Collection<ConsistencyChecker> checkers; private final ProductInformationCollector piCollector; private final ProductsCheckerCollector pcCollector; public Checker( @Autowired Collection<ConsistencyChecker> checkers, @Autowired ProductInformationCollector piCollector, @Autowired ProductsCheckerCollector pcCollector) { this.checkers = checkers; this.piCollector = piCollector; this.pcCollector = pcCollector; } public boolean isConsistent(Order order) { Map<OrderItem, ProductInformation> map = piCollector.collectProductInformation(order); if (map == null) { return false; } Set<Class<? extends Annotation>> annotations = pcCollector.getProductAnnotations(order); for (ConsistencyChecker checker : checkers) { for (Annotation annotation : checker.getClass().getAnnotations()) { if (annotations.contains( annotation.annotationType())) { if (checker.isInconsistent(order)) { return false; } break; } } } return true; } } One of the interesting things to mention is that the Spring auto-wiring is very clever. We have a field with the Collection<ConsistencyChecker> type. Usually, auto-wiring works if there is exactly one class that has the same type as the resources to wire. In our case, we do not have any such candidate since this is a collection, but we have many ConsistencyChecker classes. All our checkers implement this interface and Spring recognizes it, instantiates them all, magically creates a collection of them, and injects the collection into this field. Usually a good framework works logically. I was not aware of this feature of Spring, but I thought that this would be logical and, magically, it worked. If things are logical and just work, you do not need to read and remember the documentation. A bit of caution does not harm however. After I experienced that this functionality works this way, I looked it up in the documentation to see that this is really a guaranteed feature of Spring and not something that just happens to work but may change in future versions without notice. Using only guaranteed features is extremely important but is neglected many times in our industry. When the isConsistent method is invoked, it first collects the product information into HashMap, assigning a ProductInformation instance to each OrderItem. This is done in a separate class. After this, ProductsCheckerCollector collects the ConsistencyChecker instances needed by one or more product items. When we have this set, we need to invoke only those checkers that are annotated with one of the annotations that are in this set. We do that in a loop. In this code, we use reflection. We loop over the annotations that each checker has. To get the collection of annotations, we invoke checker.getClass().getAnnotations(). This invocation returns a collection of objects. Each object is an instance of some JDK runtime generated class that implements the interface we declared as an annotation in its own source file. There is no guarantee, though, that the dynamically created class implements only our @interface and not some other interfaces. Therefore, to get the actual annotation class, we have to invoke the annotationType method. The ProductCheckerCollector and ProductInformationCollector classes are very simple, and we will discuss them later when we learn about streams. They will serve as a good example at that place, when we implement them using loops and, right after that, using streams. Having them all, we can finally create our actual checker classes. The one that helps us see that there is a power cord ordered for our lamp is the following: package packt.java9.by.example.mybusiness.bulkorder.checkers; import ... @Component @PoweredDevice public class NeedPowercord implements ConsistencyChecker { private static final Logger log = LoggerFactory.getLogger(NeedPowercord.class); @Override public boolean isInconsistent(Order order) { log.info("checking order {}", order); CheckHelper helper = new CheckHelper(order); return !helper.containsOneOf("126", "127", "128"); } } The helper class contains simple methods that will be needed by many of the checkers, for example: public boolean containsOneOf(String... ids) { for (final OrderItem item : order.getItems()) { for (final String id : ids) { if (item.getProductId().equals(id)) { return true; } } } return false; } Invoking methods In this example, we used only one single reflection call to get the annotations attached to a class. Reflection can do many more things. Handling annotations is the most important use for these calls since annotations do not have their own functionality and cannot be handled in any other way during runtime. Reflection, however, does not stop telling us what annotations a class or any other annotable element has. Reflection can be used to get a list of the methods of a class, the name of the methods as strings, the implemented interfaces of a class, the parent class it extends, the fields, the types of fields, and so on. Reflection generally provides methods and classes to walk through the actual code structure down to the method level, programmatically. This walkthrough does not only allow reading types and code structure but also makes it possible to set field values and call methods without knowing the methods' name at compile time. We can even set fields that are private and are not generally accessible by the outside world. It is also to note that accessing the methods and fields through reflection is usually slower than through compiled code because it always involves lookup by the name of the element in the code. The rule of thumb is that if you see that you have to create code using reflection, then realize that you are probably creating a framework (or writing a book about Java that details reflection). Does it sound familiar? Spring also uses reflection to discover the classes, methods, and fields, and also to inject an object. It uses the URL class loader to list all the JAR files and directories that are on the class path, loads them, and examines the classes. For a contrived example, for the sake of demonstration, let's assume that the ConsistencyChecker implementations were written by many external software vendors, and the architect who originally designed the program structure just forgot to include the isConsistent method in the interface. (At the same time, to save our mental health, we can also imagine that this person is not working anymore in the company for doing so.) As a consequence, the different vendors delivered Java classes that "implement" this interface but we cannot invoke the method, not only because we do not have a common parent interface that has this method but also because the vendors just happened to use different names for their methods. What can we do in this situation? Business-wise, asking all the vendors to rewrite their checkers is ruled out because them knowing we are in trouble attaches a hefty price tag to the task. Our managers want to avoid that cost and we developers also want to show that we can mend the situation and do miracles. (Later, I will have a comment on that.) We could just have a class that knows every checker and how to invoke each of them in many different ways. This would require us to maintain the said class whenever a new checker is introduced to the system, and we want to avoid that. The whole plugin architecture we are using was invented for this very purpose in the first place. How can we invoke a method on an object that we know has only one declared method, which accepts an order as a parameter? That is where reflection comes into the picture. Instead of calling checker.isInconsistent(order), we implement a small private method, isInconsistent, which calls the method, whatever its name is, via reflection: private boolean isInconsistent(ConsistencyChecker checker, Order order) { Method[] methods = checker.getClass().getDeclaredMethods(); if (methods.length != 1) { log.error( "The checker {} has zero or more than one methods", checker.getClass()); return false; } final Method method = methods[0]; final boolean inconsistent; try { inconsistent = (boolean) method.invoke(checker, order); } catch (InvocationTargetException | IllegalAccessException | ClassCastException e) { log.error("Calling the method {} on class {} threw exception", method, checker.getClass()); log.error("The exception is ", e); return false; } return inconsistent; } We can get the class of the object by calling the getClass method, and on the object that represents the class itself, we can call getDeclaredMethods. Fortunately, the checker classes are not littered by many methods, so we check that there is only one method declared in the checker class. Note that there is also a getMethods method in the reflection library but it always will return more than one method. It returns the declared and the inherited methods. Because each and every class inherits from java.lang.Object, at least the methods of the Object class will be there. After this, we try to invoke the class using the Method object that represents the method in the reflection class. Note that this Method object is not directly attached to an instance. We retrieved the method from the class, and thus, when we invoke it, we should pass the object it should work on as a first parameter. This way, x.y(z), becomes method.invoke(x,z). The last parameter of invoke is a variable number of arguments that are passed as an Object array. In most cases, when we invoke a method, we know the arguments in our code even if we do not know the name of the method and have to use reflection. When even the arguments are not known but are available as a matter of calculation, then we have to pass them as an Object array. Invoking a method via reflection is a risky call. If we try to call a method the normal way, which is private, then the compiler will signal an error. If the number of arguments or types are not appropriate, the compiler will again will give us an error. If the returned value is not boolean, or there is no return value at all, then we again get a compiler error. In the case of reflection, the compiler is clueless. It does not know what method we will invoke when the code is executing. The invoke method, on the other hand, can and will notice all these failures when it is invoked. If any of the aforementioned problems occur, then we will get exceptions. If the invoke method itself sees that it cannot perform what we ask of it, then it will throw InvocationTargetException or IllegalAccessException. If the conversion from the actual return value to boolean is not possible, then we will get ClassCastException. About doing magic, it is a natural urge that we feel like making something extraordinary, something outstanding. This is okay when we are experimenting with something, doing a hobby job. On the other hand, this is strongly not okay when we are working on a professional job. Average programmers, who do not understand your brilliant solution, will maintain the code in an enterprise environment. They will turn your nicely combed code into haystack while fixing some bugs or implementing some minor new features. Even if you are the Mozart of programming, they will be, at best, no-name singers. A brilliant code in an enterprise environment can be a requiem, with all the implications of that metaphor. Last but not least, the sad reality is that we are usually not the Mozarts of programming. Note that in case the return value of the original value is primitive, then it will be converted to an object by reflection, and then we will convert it back to the primitive value. If the method does not have a return value, in other words, if it is void, then the reflection will return a java.lang.Void object. The Void object is only a placeholder. We cannot convert it to any primitive value or any other type of objects. It is needed because Java is strict and invoke has to return an Object, so the runtime needs something that it can return. All we can do is check that the returned value class is really Void. Let's go on with the storyline and our solution. We submitted the code and it works in production for a while till a new update from a software vendor breaks it. We debug the code in the test environment and see that the class now contains more than one method. Our documentation clearly states that they should only have one public method, and they provided a code that has...hmm...we realize that the other methods are private. They are right; they can have private methods according to the contract, so we have to amend the code. We replace the lines that look up the one and only method: Method[] methods = checker.getClass().getDeclaredMethods(); if (methods.length != 1) { ... } final Method method = methods[0]; The new code will be as follows: final Method method = getSingleDeclaredPublicMethod(checker); if (method == null) { log.error( "The checker {} has zero or more than one methods", checker.getClass()); return false; } The new method we write to look up the one and only public method is as follows: private Method getSingleDeclaredPublicMethod( ConsistencyChecker checker) { final Method[] methods = checker.getClass().getDeclaredMethods(); Method singleMethod = null; for (Method method : methods) { if (Modifier.isPublic(method.getModifiers())) { if (singleMethod != null) { return null; } singleMethod = method; } } return singleMethod; } To check whether the method is public or not, we use a static method from the Modifier class. There are methods to check all possible modifiers. The value that the getModifiers method returns is an int bit field. Different bits have different modifiers and there are constants that define these. This simplification leads to inconsistency, which you can check if a method is an interface or volatile, that is, actually nonsense. The fact is that bits that can only be used for other types of reflection objects will never be set. There is one exception, which is volatile. This bit is reused to signal bridge methods. Bridge methods are created by the compiler automatically and can have deep and complex issues that we do not discuss in this book. The reuse of the same bit does not cause confusion because a field can be volatile, but as a field, it cannot be a bridge method. Obviously, a field is a field and not a method. In the same way, a method cannot be a volatile field. The general rule is: do not use methods on reflection objects where they do not have a meaning; or else, know what you do. Making the storyline even more intricate, a new version of a checker accidentally implements the checking method as a package private. The programmer simply forgot to use the public keyword. For the sake of simplicity, let's assume that the classes declare only one method again, but it is not public. How do we solve this problem using reflection? Obviously, the simplest solution is to ask the vendors to fix the problem: it is their fault. In some cases, however, we must create a workaround over some problems. There is another solution: creating a class with a public method in the same package, invoking the package private methods from the other class, thus relaying the other class. As a matter of fact, this solution, as a workaround for such a bug, seems to be more logical and cleaner, but this time, we want to use reflection. To avoid java.lang.IllegalAccessException, we have to set the method object as accessible. To do so, we have to insert the following line in front of the invocation: method.setAccessible(true); Note that this will not change the method to public. It will only make the method accessible for invocation through the very instance of the method object that we set as accessible. I have seen code that checks whether a method is accessible or not by calling the isAccessible method and saves this information; it sets the method as accessible if it was not accessible and restores the original accessibility after the invocation. This is totally useless. As soon as the method variable goes out of scope, and there is no reference to the object we set the accessibility flag to, the effect of the setting wears off. Also, there is no penalty for setting the accessibility of a public or an otherwise callable method. Setting fields We can also call setAccessible on Field objects and then we can even set the value of private fields using reflection. Without further fake stories, just for the sake of the example, let's make a ConsistencyChecker named SettableChecker: @Component @PoweredDevice public class SettableChecker implements ConsistencyChecker { private static final Logger log = LoggerFactory.getLogger(SettableChecker.class); private boolean setValue = false; public boolean isInconsistent(Order order) { return setValue; } } This checker will return false, unless we set the field to true using reflection. We do set it as such. We create a method in the Checker class and invoke it from the checking process for each checker: private void setValueInChecker(ConsistencyChecker checker) { Field[] fields = checker.getClass().getDeclaredFields(); for( final Field field : fields ){ if( field.getName().equals("setValue") && field.getType().equals(boolean.class)){ field.setAccessible(true); try { log.info("Setting field to true"); field.set(checker,true); } catch (IllegalAccessException e) { log.error("SNAFU",e); } } } } The method goes through all the declared fields and if the name is setValue and the type is boolean, then it sets it to true. This will essentially render all orders that contain a powered device as rejected. Note that although boolean is a built-in language primitive, which is not a class by any means, it still has a class so that reflection can compare the type of the field gainst he class that boolean artificially has. Now boolean.class is a class literal in the language, and for each primitive, a similar constant can be used. The compiler identifies these as class literals and creates the appropriate pseudo class references in the byte code so that primitives can also be checked in this way, as demonstrated in the sample code of the setValueInChecker method. We checked that the field has the appropriate type, and we also called the setAccessible method on the field. Even though the compiler does not know that we really did everything to avoid IllegalAccessException, it still believes that calling set on field can throw such an exception, as it is declared. However, we know that it should not happen. (Famous last words of a programmer?) To handle this situation, we surround the method call with a try block, and in the catch branch, we log the exception. Functional programming in Java Since we have created a lot of code in our example for this chapter, we will look at the functional programming features of Java, which will help us delete many lines from our code. The less code we have, the easier it is to maintain the application; thus, programmers love functional programming. But this is not the only reason why functional programming is so popular. It is also an excellent way to describe certain algorithms in a more readable and less error prone manner than conventional loops. Functional programming is not a new thing. The mathematical background was developed for it in the 1930s. One of the first (if not the first) functional programming languages is LISP. It was developed in the 1950s and it is still in use, so much that there is a version of the language implemented on the JVM (Clojure). Functional programming, in short, means that we express the program structure in terms of functions. In this meaning, we should think of functions as in mathematics and not as the term is used in programming languages such as C. In Java, we have methods, and when we are following the functional programming paradigm, we create and use methods that behave like mathematical functions. A method is functional if it gives the same result no matter how many times we invoke it, just as sin(0) is always zero. Functional programming avoids changing the state of objects, and because the state is not changing, the results are always the same. This also eases debugging. If a function has once returned a certain value for the given arguments, it will always return the same value. We can also read the code as a declaration of the calculation more than as commands that are executed one after the other. If the execution order is not important, then the readability of the code may also increase. Java helps functional programming style with lambda expressions and streams. Note that these streams are not I/O streams and do not really have any relation to those. We will first take a short look at lambda expressions and what streams are, and then, we will convert some parts of our program to use these programming constructs. We will also see how much more readable these codes become. Readability is a debatable topic. A code may be readable to one developer and may be less readable to another. It very much depends on what they got used to. I experience many times that developers get distracted with streams. When developers first meet streams, the way to think about them and how they look is just strange. But this is the same as starting to learn using a bicycle. While you are still learning its use and you fall more than you roll, it is definitely slower than walking. On the other hand, once you have learnt how to ride a bike... Lambda We have already used lambda expressions in Chapter 3, Optimizing the Sort - Making Code Professional when we wrote the exception-throwing test. In that code, we set the comparator to a special value that was throwing RuntimeException at each invocation: sort.setComparator((String a, String b) -> { throw new RuntimeException(); }); The argument type is Comparator; therefore, what we have to set there should be an instance of a class that implements the java.util.Comparator interface. That interface defines only one method that implementations have to define: compare. Thus, we can define it as a lambda expression. Without lambda, if we need an instance, we have to type a lot. We have to create a class, name it, declare the compare method in it, and write the body of the method, as shown in the following code segment: public class ExceptionThrowingComparator implements Comparator { public int compare(T o1, T o2){ throw new RuntimeException(); } } At the location of use, we should instantiate the class and pass it as an argument: sort.setComparator(new ExceptionThrowingComparator()); We may save a few characters if we define the class as an anonymous class but the overhead is still there. What we really need is the body of the one and single method that we have to define. This is where lambda comes into the picture. We can use a lambda expression in any place where we would otherwise need an instance of a class that has to define only one method. The methods that are defined and inherited from Object do not count, and we also do not care about the methods that are defined as default methods in the interface. They are there. Lambda defines the one that is not yet defined. In other words, lambda clearly depicts, with much less overhead as an anonymous class, that the value is a functionality that we pass as a parameter. The simple form of a lambda expression is as follows: parameters -> body The parameters can be enclosed between parentheses or can only stand without. The body similarly can be enclosed between the { and} characters or it can be a simple expression. This way a lambda expression can reduce the overhead to a minimum, using the parentheses only where they are really needed. It is also an extremely useful feature of lambda expressions that we do not need to specify the types of the parameters in case it is obvious from the context where we use the expression. Thus, the preceding code segment can even be shorter, as follows: sort.setComparator((a, b) -> { throw new RuntimeException(); }); The parameters, a and b, will have the type as needed. To make it even simpler, we can also omit the ( and) characters around the parameters in case there is only one. The parentheses are not optional if there is more than one parameter. This is to avoid ambiguity in some situations. For example, the method call, f(x,y->x+y) could have been a method with two arguments: x and a lambda expression that has one parameter, y. At the same time, it could also be a method call with a lambda expression that has two parameters, x and y. Lambda expressions are very handy when we want to pass functionality as an argument. The declaration of the type of argument at the place of the method declaration should be a functional interface type. These interfaces can optionally be annotated using @FunctionalInterface. The Java runtime has many such interfaces defined in the java.util.function package. We will discuss some of them in the next section along with their use in streams. For the rest, the standard Java documentation is available from Oracle. Streams Streams were also new in Java 8, just like lambda expressions. They work together very strongly, so their appearance at the same time is not a surprise. Lambda expressions as well as streams support the functional programming style. The very first thing to clarify is that streams do not have anything to do with input and output streams, except the name. They are totally different things. Streams are more like collections with some significant differences. (If there were no differences, they would just have been collections.) Streams are essentially pipelines of operations that can run sequentially or in parallel. They obtain their data from collections or other sources, including data that is manufactured on-the-fly. Streams support the execution of the same calculation on multiple data. This structure is referred to as Single Instruction Multiple Data (SIMD). Don't be afraid of the expression. This is a very simple thing. We have already done that many times in this book. Loops are also kind of SIMD structures. When we loop through the checker classes to see whether any of those opposes the order, we perform the same instruction for each and every checker. Multiple checkers are multiple data. One problem with loops is that we define the order of execution when it is not needed. In the case of checkers, we do not really care what order the checkers are executed in. All we care about is that all are okay with the order. We still specify some order when we program the loop. This comes from the nature of loops, and there is no way we could change that. That is how they work. However, it would be nice if we could just, somehow, say "do this and that for each and every checker". This is one point where streams come into the picture. Another point is that code that uses loops is more imperative rather than descriptive. When we read the program of a loop construct, we focus on the individual steps. We first see what the commands in the loop do. These commands work on the individual elements of the data and not on the whole collection or array. Later putting the individual steps together in our brain we realize what the big picture is, what the loop is for. In the case of streams, the description of operations is a level higher. Once we learn the stream methods, it is easier to read them. Stream methods work on the whole stream and not on the individual elements, and thus are more descriptive. is an interface. An object with a type implementing this interface represents many objects and provides methods that can be used to perform instructions on these objects. The objects may or may not be available when we start the operation on one of them, or may just be created when needed. This is up to the actual implementation of the Stream interface. For example, suppose we generate a stream that contains int values using the following code: java.lang.Stream IntStream.iterate( 0, (s) -> s+1 ) In the preceding code snippet, all the elements cannot be generated because the stream contains an infinite number of elements. This example will return the numbers 0, 1, 2, and so on until further stream operations, which are not listed here, terminate the calculation. When we program Stream, we usually create a stream from a Collection—not always, but many times. The Collection interface was extended in Java 8 to provide the stream and parallelStream methods. Both of them return stream objects that represent the elements of the collection. While stream returns the elements in the same order as they are in the collection in case there is a natural order, the parallelStream creates a stream that may be worked on in a parallel manner. In this case, if some of the methods that we use on the stream are implemented in that way, the code can use the multiple processors available in the computer. As soon as we have a stream, we can use the methods that the Stream interface defines. The one to start with is forEach. This method has one argument, which is usually provided as a lambda expression and will execute the lambda expression for each element of the stream. In the Checker class, we have the isConsistent method. In this method, there is a loop that goes through the annotations of the checker class. If we wanted to log the interfaces that the annotation in the loop implements, we could add the following: for (ConsistencyChecker checker :checkers) { for (Annotation annotation : checker.getClass().getAnnotations()) { Arrays.stream(annotation.getClass().getInterfaces()) .forEach( t ->log.info("annotation implemented interfaces {}",t) ); ... In this example, we create a stream from an array using the factory method from the Arrays class. The array contains the interfaces returned by the reflection method, getInterfaces. The lambda expression has only one parameter; thus, we do not need to use parentheses around it. The body of the expression is a method call that returns no value; thus, we also omit the { and } characters. Why all this hassle? What is the gain? Why couldn't we just write a simple loop that logs the elements of the array? The gains are readability and maintainability. When we create a program, we have to focus on what the program should do and not on how it should do it. In an ideal world, a specification would just be executable. We may actually get there in the future when programming work will be replaced by artificial intelligence. (Not the programmers, though.) We are not there, yet. We have to tell the computers how to do what we want to achieve. We used to have to enter binary codes on the console of PDP-11 to get machine code deployed into the memory to have it executed. Later, we had assemblers; still later, we had FORTRAN and other high-level programming languages that have replaced much of the programming work as it was 40 years ago. All these developments in programming shift the direction from how towards what. Today, we program in Java 9, and the road still has miles to go. The more we can express what to do instead of how to do, the shorter and more understandable our programs will be. It will contain the essence and not some artificial litter that is needed by the machines to just do what we want. When I see a loop in a code I have to maintain, I assume that there is some importance of the order in which the loop is executed. There may be no importance at all. It may be obvious after a few seconds. It may need minutes or more to realize that the ordering is not important. This time is wasted and can be saved with programming constructs that better express the what to do part instead of the how to do. Functional interfaces The argument to the method should be java.util.function.Consumer. This is an interface that requires the accept method to be defined, and this method is void. The lambda expression or a class that implements this interface will consume the argument of the accept method and does not produce anything. There are several other interfaces defined in that package, each serving as a functional interface used to describe some method arguments that can be given as lambda expressions in the actual parameters. For example, the opposite of Consumer is Supplier. This interface has a method named get that does not need any argument but gives some Object as a return value. If there is an argument and also a returned value, the interface is called Function. If the returned value has to be the same type as the argument, then the UnaryOperator interface is our friend. Similarly, there is a BinaryOperator interface, which returns an object of the same type as the arguments. Just as we got from Function to UnaryOperator, we can see that in the other direction, there is also BiFunction in case the arguments and the return values do not share the type. These interfaces are not defined independently of each other. If a method requires Function and we have UnaryOperator to pass, it should not be a problem. UnaryOperator is nothing else but Function that has the same type of arguments. A method that can work with Function, which accepts an object and returns an object, should not have a problem if they have the same type. Those can be, but need not be, different. To let that happen, the UnaryOperator interface extends Function and thus can be used in the place of Function. The interfaces in this class we met so far are defined using generics. Because generic types cannot be primitives, the interfaces that operate on primitive values should be defined separately. Predicate, for example, is an interface that defines booleantest(T t). It is a function that returns a boolean value and is used many times in stream methods. There are also interfaces, such as BooleanSupplier, DoubleConsumer, DoubleToIntFunction, and more, that work with primitive boolean, double, and int. The number of possible combinations of the different argument types and return values is infinite... almost. Fun fact: To be very precise, it is not infinite. A method can have at most 254 arguments. This limit is specified in the JVM and not in the Java language specification. Of course, one is useless without the other. There are 8 primitive types (plus Object, plus the possibility that there are less than 254 arguments), which means that the total number of possible functional interfaces is 10254, give or take, a few magnitudes. Practically, infinite! We should not expect to have all the possible interfaces defined in the JDK in this package. These are only those interfaces that are the most useful. There is no interface, for example, that uses short or char. If we need anything like that, then we can define the interface in our code. Or just think hard and find out how to use an already defined one. (I have never used the short type during my professional carrier. It was never needed.) How are these functional interfaces used in streams? The Stream interface defines the methods that have some functional interface types as arguments. For example, the allMatch method has a Predicate argument and returns a Boolean value, which is true if all the elements in the stream match Predicate. In other words, this method returns true if and only if Predicate, supplied as an argument, returns true for each and every element of the stream. In the following code, we will rewrite some of the methods that we implemented in our sample code using loops to use streams, and through these examples, we will discuss the most important methods that streams provide. We saved up two classes, ProductsCheckerCollector and ProductInformationCollector, to demonstrate the stream usage. We can start with these. ProductsCheckerCollector goes through all the products that are contained in the Order and collects the annotations that are listed in the products. Each product may contain zero, one, or many annotations. These are available in a list. The same annotation may be referenced multiple times. To avoid duplicates, we use HashSet, which will contain only one instance of the elements even if there are multiple instances in the products: public class ProductsCheckerCollector { private final ProductInformationCollector pic; public ProductsCheckerCollector(@Autowired ProductInformationCollector pic) { this.pic = pic; } public Set<Class<? extends Annotation>> getProductAnnotations(Order order) { Map<OrderItem, ProductInformation> piMap = pic.collectProductInformation(order); final Set<Class<? extends Annotation>> annotations = new HashSet<>(); for (OrderItem item : order.getItems()) { final ProductInformation pi = piMap.get(item); if (pi != null && pi.getCheck() != null) { for (Class<? extends Annotation> check : pi.getCheck()) { annotations.addAll(pi.getCheck()); } } return annotations; } } Now, let's see how this method looks when we recode it using streams: public Set<Class<? extends Annotation>> getProductAnnotations(Order order) { Map<OrderItem, ProductInformation> piMap = pic.collectProductInformation(order); return order.getItems().stream() .map(piMap::get) .filter(Objects::nonNull) .peek(pi -> { if (pi.getCheck() == null) { log.info("Product {} has no annotation", pi.getId()); } }) .filter(pi -> pi.getCheck() != null) .peek(pi -> log.info("Product {} is annotated with class {}", pi.getId(), pi.getCheck())) .flatMap(pi -> pi.getCheck().stream()) .collect(Collectors.toSet()); } The major work of the method gets into a single, though huge, stream expression. We will cover the elements of the expression in the coming pages. List returned by order.getItems is converted calling the stream method: returnorder.getItems().stream() As we have already mentioned it briefly, the stream method is part of the Collection interface. Any class that implements the Collection interface will have this method, even those that were implemented before streams were introduced in Java 8. This is because the stream method is implemented in the interface as a default method. This way, if we happen to implement a class implementing this interface, even if we do not need streams, we get it for free as an extra. The default methods in Java 8 were introduced to support backward compatibility of interfaces. Some of the interfaces of the JDK were to be modified to support lambda and functional programming. One example is the stream method. With the pre-Java 8 feature set, the classes implementing some of the modified interfaces should have been modified. They would have been required to implement the new method. Such a change is not backward compatible, and Java as a language and JDK was paying keen attention to be backward compatible. Thus, default methods were introduced. These let a developer extend an interface and still keep it backward compatible, providing a default implementation for the methods, which are new. Contrary to this philosophy, brand new functional interfaces of Java 8 JDK also have default methods, though, having no prior version in the JDK, they have nothing to be compatible with. In Java 9, interfaces were also extended and now they can contain not only default and static methods but also private methods. This way, interfaces became kind of equivalent to abstract classes, though there are no fields in an interface except constant static fields. This interface functionality open up is a much criticized feature, which just poses the programming style and structural issues that other languages allowing multiple class inheritance face. Java was avoiding this till Java 8 and Java 9. What is the take-away from this? Be careful with default methods and also with private methods in interfaces. Use them wisely if at all. The elements of this stream are OrderItem objects. We need ProductInformation for each OrderItem. Method references Lucky that we have Map, which pairs order items with product information, so we can invoke get on Map: .map(piMap::get) The map method is again something that has the same name as something else in Java and should not be confused. While the Map class is a data structure, the map method in the Stream interface performs mapping of the stream elements. The argument of the method is a Function (recall that this is a functional interface we recently discussed). This function converts a value, T, which is available as the element of the original stream (Stream<T>) to a value, R, and the return value of the map method is Stream<R>. The map method converts Stream<T> to Stream<R> using the given Function<T,R>, calling it for each element of the original stream and creating a new stream from the converted elements. We can say that the Map interface maps keys to values in a data structure in a static way, and the Stream method, map, maps one type of values to another (or the same) type of values dynamically. We have already seen that we can provide an instance of a functional interface in the form of a lambda expression. This argument is not a lambda expression. This is a method reference. It says that the map method should invoke the get method on Map piMap using the actual stream element as an argument. We are lucky that get also needs one argument, aren't we? We could also write as follows: .map( orderItem ->piMap.get(orderItem)) However, this would have been exactly the same as piMap::get. This way, we can reference an instance method that works on a certain instance. In our example, the instance is the one referenced by the piMap variable. It is also possible to reference static methods. In this case, the name of the class should be written in front of the :: characters. We will soon see an example of this when we will use the static method, nonNull, from the Objects class (note that the class name is in plural, and it is in the java.util package and not java.lang). It is also possible to reference an instance method without giving the reference on which it should be invoked. This can be used in places where the functional interface method has an extra first parameter, which will be used as the instance. We have already used this in Chapter 3, Optimizing the Sort - Making Code Professional, when we passed String::compareTo, when the expected argument was a Comparator. The compareTo method expects one argument, but the compare method in the Comparator interface needs two. In such a situation, the first argument will be used as the instance on which compare has to be invoked and the second argument is passed to compare. In this case, String::compareTo is the same as writing the lambda expression (String a, String b) -> a.compareTo(b). Last but not least, we can use method references to constructors. When we need a Supplier of (let's be simple) Object, we can write Object::new. The next step is to filter out the null elements from the stream. Note that, at this point, the stream has ProductInformation elements: .filter(Objects::nonNull) The filter method uses Predicate and creates a stream that contains only the elements that match the predicate. In this case, we used the reference to a static method. The filter method does not change the type of stream. It only filters out the elements. The next method we apply is a bit anti-functional. Pure functional stream methods do not alter the state of any object. They create new objects that they return but, other than that, there is no side effect. peek itself is no different because it only returns a stream of the same elements as the one it is applied on. However, this no-operation feature lures the novice programmer to do something non-functional and write code with side-effects. After all, why use it if there is no (side) effect in calling it? .peek(pi -> { if (pi.getCheck() == null) { log.info("Product {} has no annotation", pi.getId()); } }) While the peek method itself does not have any side effects, the execution of the lambda expression may have. However, this is also true for any of the other methods. It is just the fact that, in this case, it is more tempting to do something inadequate. Don't. We are disciplined adults. As the name of the method suggests, we may peek into the stream but we are not supposed to do anything else. With programming being a particular activity, in this case, peeking, is adequate. And that is what we actually do in our code: we log something. After this, we get rid of the elements that have no ProductInformation; we also want to get rid of the elements that have, but there is no checker defined: .filter(pi ->pi.getCheck() != null) In this case, we cannot use method references. Instead, we use a lambda expression. As an alternative solution, we may create a boolean hasCheck method in ProductInformation, which returns true if the private field check is not null. This would then read as follows: .filter(ProductInformation::hasCheck) This is totally valid and works, although the class does not implement any functional interface and has many methods, not only this one. However, the method reference is explicit and specifies which method to invoke. After this second filter, we log the elements again: .peek(pi -> log.info( "Product {} is annotated with class {}", pi.getId(), pi.getCheck())) The next method is flatMap and this is something special and not easy to comprehend. At least for me, it was a bit more difficult than understanding map and filter when I learned functional programming: .flatMap(pi ->pi.getCheck().stream()) This method expects that the lambda, method reference, or whatever is passed to it as an argument, creates a whole new stream of objects for each element of the original stream the method is invoked on. The result is, however, not a stream of streams, which also could be possible, but rather the returned streams are concatenated into one huge stream. If the stream we apply it to is a stream of integer numbers, such as 1, 2, 3, ..., and the function for each number n returns a stream of three elements n, n+1, and n+2, then the resulting stream, flatMap, produces a stream containing 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, and so on. Finally, the stream we have should be collected to a Set. This is done by calling the collector method: .collect(Collectors.toSet()); The argument to the collector method is (again a name overuse) Collector. It can be used to collect the elements of the stream into some collection. Note that Collector is not a functional interface. You cannot just collect something using a lambda or a simple method. To collect the elements, we definitely need some place where the elements are collected as the ever-newer elements come from the stream. The Collector interface is not simple. Fortunately, the java.util.streams.Collectors class (again note the plural) has a lot of static methods that create and return Object that create and return Collector objects. One of these is toSet, which returns a Collector that helps collect the elements of the stream into a Set. The collect method will return the Set when all the elements are there. There are other methods that help collect the stream elements by summing up the elements, calculating the average, or to a List, Collection, or to a Map. Collecting elements to a Map is a special thing, since each element of a Map is actually a key-value pair. We will see the example for that when we look at ProductInformationCollector. The ProductInformationCollector class code contains the collectProductInformation method, which we will use from the Checker class as well as from the ProductsCheckerCollector class: private Map<OrderItem, ProductInformation> map = null; public Map<OrderItem, ProductInformation> collectProductInformation(Order order) { if (map == null) { map = new HashMap<>(); for (OrderItem item : order.getItems()) { final ProductInformation pi = lookup.byId(item.getProductId()); if (!pi.isValid()) { map = null; return null; } map.put(item, pi); } } return map; } The simple trick is to store the collected value in Map, and if that is not null, then just return the already calculated value, which may save a lot of service calls in case this method is called more than once handling the same HTTP request. There are two ways of coding such a structure. One is checking the non-nullity of the Map and returning if the Map is already there. This pattern is widely used and has a name. This is called guarding if. In this case, there is more than one return statement in the method, which may be seen as a weakness or anti-pattern. On the other hand, the tabulation of the method is one tab shallower. It is a matter of taste and in case you find yourself in the middle of a debate about one or the other solution, just do yourself a favor and let your peer win on this topic and save your stamina for more important issues, for example, whether you should use streams or just plain old loops. Now, let's see how we can convert this solution into a functional style: public Map<OrderItem, ProductInformation> collectProductInformation(Order order) { if (map == null) { map = order.getItems() .stream() .map(item -> tuple(item, item.getProductId())) .map(t -> tuple(t.r, lookup.byId((String) t.s))) .filter(t -> ((ProductInformation)t.s).isValid()) .collect( Collectors.toMap( t -> (OrderItem)t.r, t -> (ProductInformation)t.s ) ); if (map.keySet().size() != order.getItems().size()) { log.error("Some of the products in the order do not have product information, {} != {} ",map.keySet().siz map = null; } } return map; } We use a helper class, Tuple, which is nothing but two Object instances named r and s. We will list the code for this class later. It is very simple. In the streams expression, we first create the stream from the collection, and then we map the OrderItem elements to a stream of OrderItem and productId tuples. Then we map these tuples to tuples that now contain OrderItem and ProductInformation. These two mappings could be done in one mapping call, which would perform the two steps only in one. I decided to create the two to have simpler steps in each line in a vain hope that the resulting code will be easier to comprehend. The filter step is also nothing new. It just filters out invalid product information elements. There should actually be none. It happens if the order contains an order ID to a non-existent product. This is checked in the next statement when we look at the number of collected product information elements to see that all the items have proper information. The interesting code is how we collect the elements of the stream into a Map. To do so, we again use the collect method and also the Collectors class. This time, the toMap method creates the Collector. This needs two Function resulting expressions. The first one should convert the element of the stream to the key and the second should result in the value to be used in the Map. Because the actual type of the key and the value is calculated from the result of the passed lambda expressions, we explicitly have to cast the fields of the tuple to the needed types. Finally, the simple Tuple class is as follows: public class Tuple<R, S> { final public R r; final public S s; private Tuple(R r, S s) { this.r = r; this.s = s; } public static <R, S> Tuple tuple(R r, S s) { return new Tuple<>(r, s); } } There are still some classes in our code that deserve to be converted to functional style. These are the Checker and CheckerHelper classes. In the Checker class, we can rewrite the isConsistent method: public boolean isConsistent(Order order) { Map<OrderItem, ProductInformation> map = piCollector.collectProductInformation(order); if (map == null) { return false; } final Set<Class<? extends Annotation>> annotations = pcCollector.getProductAnnotations(order); return !checkers.stream().anyMatch( checker -> Arrays.stream( checker.getClass().getAnnotations() ).filter( annotation -> annotations.contains( annotation.annotationType()) ).anyMatch( x -> checker.isInconsistent(order) )); } Since you have already learnt most of the important stream methods, there is hardly any new issue here. We can mention the anyMatch method, which will return true if there is at least one element so that the Predicate parameter passed to anyMatch is true. It may also need some accommodation so that we could use a stream inside another stream. It very well may be an example when a stream expression is overcomplicated and needs to split up into smaller pieces using local variables. Finally, before we leave the functional style, we rewrite the containsOneOf method in the CheckHelper class. This contains no new elements and will help you check what you have learned about map, filter, flatMap, and Collector. Note that this method, as we discussed, returns true if order contains at least one of the order IDs given as strings: public boolean containsOneOf(String... ids) { return order.getItems().stream() .map(OrderItem::getProductId) .flatMap(itemId -> Arrays.stream(ids) .map(id -> tuple(itemId, id))) .filter(t -> Objects.equals(t.s, t.r)) .collect(Collectors.counting()) > 0; } We create the stream of the OrderItem objects, and then we map it to a stream of the IDs of the products contained in the stream. Then we create another stream for each of the IDs with the elements of the ID and one of the string IDs given as the argument. Then, we flatten these substreams into one stream. This stream will contain order.getItems().size() times ids.length elements: all possible pairs. We will filter out those pairs that contain the same ID twice, and finally, we will count the number of elements in the stream. Scripting in Java 9 We are almost ready with our sample program for this chapter. There is one issue, though it is not professional. When we have a new product that needs a new checker, we have to create a new release of the code. Programs in professional environments have releases. When the code is modified, bugs are fixed, or a new function is implemented, there are numerous steps that the organization requires before the application can go into production. These steps compose the release process. Some environments have lightweight release processes; others require rigorous and expensive checks. It is not because of the taste of the people in the organization, though. When the cost of a non-working production code is low and it does not matter if there is an outage or wrong functioning in the program, then the release process can be simple. This way, releases get out faster and cheaper. An example can be some chat program that is used for fun by the users. In such a situation, it may be more important to release new fancy features than ensuring bug-free working. On the other end of the palette, if you create code that controls an atomic power plant, the cost of failure can be pretty high. Serious testing and careful checking of all the features, even after the smallest change, can pay off. In our example, simple checkers may be an area that is not likely to induce serious bugs. It is not impossible but the code is so simple...Yes, I know that such an argument is a bit fishy, but let's assume that these small routines could be changed with less testing and in an easier way than the other parts of the code. How to separate the code for these little scripts, then, so that they do not require a technical release, a new version of the application, and not even restarting the application? We have a new product that needs a new check and we want to have some way to inject this check into the application environment without any service disruption. The solution we choose is scripting. Java programs can execute scripts written in JavaScript, Groovy, Jython (which is the JVM version of the language Python), and many other languages. Except JavaScript, the language interpreters of these languages are not a part of the JDK, but they all provide a standard interface, which is defined in the JDK. The consequence is that we can implement script execution in our code and the developers, who provide the scripts, are free to choose any of the available languages; we do not need to care to execute a JavaScript code. We will use the same API as to execute Groovy or Jython. The only thing we should know is what language the script is in. This is usually simple: we can guess that from the file extension, and if guessing is not enough, we can demand that the script developers put JavaScript into files with the .js extension, Jython into files with .jy or .py, Groovy into files with .groovy, and so on. It is also important to note that if we want our program to execute one of these languages, we should make sure that the interpreter is on the classpath. In the case of JavaScript, this is given; therefore, as a demonstration in this chapter, we will write our scripts in JavaScript. There will not be a lot; this is a Java book and not a JavaScript book after all. Scripting is usually a good choice when we want to pass the ability of programmatically configuring or extending our application. This is our case now. The first thing we have to do is to extend the production information. In case there is a script that checks the consistency of an order that a product is in, we need a field where we can specify the name of the script: private String checkScript; public String getCheckScript() { return checkScript; } public void setCheckScript(String checkScript) { this.checkScript = checkScript; } We do not want to specify more than one script per product; therefore, we do not need a list of script names. We have only one script specified by the name. To be honest, the data structure for the checker classes and the annotations, allowing multiple annotations per product and also per checker class, was too complicated. We could not avoid that, though, to have a complex enough structure that could demonstrate the power and capability of stream expressions. Now that we are over that subject, we can go on using simpler data structures focusing on script execution. We also have to modify the Checker class to not only use the checker classes but also the scripts. We cannot throw away the checker classes because, by the time we realize that we better need scripts for the purpose, we already have a lot of checker classes and we have no financing to rewrite them to be scripts. Well yes, we are in a book and not in real life, but in an enterprise, that would be the case. That is why you should be very careful while designing solutions for a corporate. The structures and the solutions will be there for a long time and it is not easy to throw a piece of code out just because it is technically not the best. If it works and is already there, the business will be extremely reluctant to spend money on code maintenance and refactoring. Summary: we modify the Checker class. We need a new class that can execute our scripts; thus, the constructor is modified: private final CheckerScriptExecutor executor; public Checker( @Autowired Collection<ConsistencyChecker> checkers, @Autowired ProductInformationCollector piCollector, @Autowired ProductsCheckerCollector pcCollector, @Autowired CheckerScriptExecutor executor ) { this.checkers = checkers; this.piCollector = piCollector; this.pcCollector = pcCollector; this.executor = executor; } We also have to use this executor in the isConsistent method: public boolean isConsistent(Order order) { final Map<OrderItem, ProductInformation> map = piCollector.collectProductInformation(order); if (map == null) { return false; } final Set<Class<? extends Annotation>> annotations = pcCollector.getProductAnnotations(order); Predicate<Annotation> annotationIsNeeded = annotation -> annotations.contains(annotation.annotationType()); Predicate<ConsistencyChecker> productIsConsistent = checker -> Arrays.stream(checker.getClass().getAnnotations()) .parallel().unordered() .filter(annotationIsNeeded) .anyMatch( x -> checker.isInconsistent(order)); final boolean checkersSayConsistent = !checkers.stream(). anyMatch(productIsConsistent); final boolean scriptsSayConsistent = !map.values(). parallelStream(). map(ProductInformation::getCheckScript). filter(Objects::nonNull). anyMatch(s -> executor.notConsistent(s,order)); return checkersSayConsistent && scriptsSayConsistent; } Note that in this code, we use parallel streams because, why not? Whenever it is possible, we can use parallel streams, even unordered, to tell the underlying system and also to the programmer fellows maintaining the code that order is not important. We also modify one of our product JSON files to reference a script instead of a checker class through some annotation: { "id" : "124", "title": "Desk Lamp", "checkScript" : "powered_device", "description": "this is a lamp that stands on my desk", "weight": "600", "size": [ "300", "20", "2" ] } Even JSON is simpler. Note that as we decided to use JavaScript, we do not need to specify the file name extension when we name the script. We may later consider further development when we will allow the product checker script maintainers to use different scripting languages. In such a case, we may still require that they specify the extension, and in case there is no extension, it will be added by our program as .js. In our current solution, we do not check that, but we may devote a few seconds to think about it to be sure that the solution can be further developed. It is important that we do not develop extra code for the sake of further development. Developers are not fortunetellers and cannot tell reliably what the future needs will be. That is the task of the business people. We put the script into the resource directory of our project under the scripts directory. The name of the file has to be powered_device.js because this is the name we specified in the JSON file: function isInconsistent(order){ isConsistent = false items = order.getItems() for( i in items ){ item = items[i] print( item ) if( item.getProductId() == "126" || item.getProductId() == "127" || item.getProductId() == "128" ){ isConsistent = true } } return ! isConsistent } This is an extremely simple JavaScript program. As a side note, when you iterate over a list or an array in JavaScript, the loop variable will iterate over the indexes of the collection or the array. Since I rarely program in JavaScript, I fell into this trap and it took me more than half an hour to debug the error I made. We have prepared everything we need to call the script. We still have to invoke it. To do so, we use the JDK scripting API. First, we need a ScriptEngineManager. This manager is used to get access to the JavaScript engine. Although the JavaScript interpreter has been a part of the JDK since Java 7, it is still managed in an abstract way. It is one of the many possible interpreters that a Java program can use to execute script. It just happens to be there in the JDK, so we do not need to add the interpreter JAR to the classpath. ScriptEngineManager discovers all the interpreters that are on the classpath and registers them. It does so using the Service Provider specification, which has been a part of the JDK for a long time, and by Java 9, it also got extra support in module handling. This requires the script interpreters to implement the ScriptEngineFactory interface and also to list the class that does it in the METAINF/services/javax.script.ScriptEngineFactory file. These files, from all the JAR files that are part of the classpath, are read as resources by ScriptEngineManager, and through this, it knows which classes implement script interpreters. The ScriptEngineFactory interface requires that the interpreters provide methods such as getNames, getExtensions, and getMimeTypes. The manager calls these methods to collect the information about the interpreters. When we ask a JavaScript interpreter, the manager will return the one created by the factory that said that one of its names is JavaScript. To get access to the interpreters through the name, file name extension or mime-type is only one of the functions of ScriptEngineManager. The other one is to manage Bindings. When we execute a script from within the Java code, we don't do it because we want to increase our dopamine levels. In the case of scripts, it does not happen. We want some results. We want to pass parameters and after the execution of the script, we want values back from the script that we can use in the Java code. This can happen in two ways. One is by passing parameters to a method or function implemented in the script and getting the return value from the script. This usually works, but it may even happen that some scripting language does not even have the notion of the function or method. In such a case, it is not a possibility. What is possible is to pass some environment to the script and read values from the environment after the script is executed. This environment is represented by Bindings. Bindings is a map that has String keys and Object values. In the case of most scripting languages, for example, in JavaScript, Bindings is connected to global variables in the script we execute. In other words, if we execute the following command in our Java program before invoking the script, then the JavaScript global variable, globalVariable, will reference the myObject object: myBindings.put("globalVariable",myObject) We can create Bindings and pass it to ScriptEngineManager but just as well we can use the one that it creates automatically, and we can call the put method on the engine object directly. There are two Bindings when we execute scripts. One is set on the ScriptEngineManager level. This is named global binding. There is also one managed by ScriptEngine itself. This is the local Bindings. From the script point of view, there is no difference. From the embedding side, there is some difference. In case we use the same ScriptEngineManager to create multiple ScriptEngine instances, then the global bindings are shared by them. If one gets a value, all of them see the same value; if one sets a value, all others will later see that changed value. The local binding is specific to the engine it is managed by. Since we only introduce Java scripting API in this book, we do not get into more details and we will not use Bindings. We are good with invoking a JavaScript function and to get the result from it. The class that implements the script invocation is CheckerScriptExecutor: package packt.java9.by.example.mybusiness.bulkorder.services; import ... @Component public class CheckerScriptExecutor { private static final Logger log = ... private final ScriptEngineManager manager = new ScriptEngineManager(); public boolean notConsistent(String script, Order order) { try { final Reader scriptReader = getScriptReader(script); final Object result = evalScript(script, order, scriptReader); assertResultIsBoolean(script, result); log.info("Script {} was executed and returned {}", script, result); return (boolean) result; } catch (Exception wasAlreadyHandled) { return true; } } The only public method, notConsistent, gets the name of the script to execute and also order. The latter has to be passed to the script. First it gets Reader, which can read the script text, evaluates it, and finally returns the result in case it is boolean or can at least be converted to boolean. If any of the methods invoked from here that we implemented in this class is erroneous, it will throw an exception, but only after appropriately logging it. In such cases, the safe way is to refuse an order. Actually, this is something that the business should decide. If there is a check script that cannot be executed, it is clearly an erroneous situation. In this case, accepting an order and later handling the problems manually has certain costs. Refusing an order or confirmation because of some internal bug is also not a happy path of the order process. We have to check which approach causes the least damage to the company. It is certainly not the duty of the programmer. In our situation, we are in an easy situation. We assume that the business representatives said that the order in such a situation should be refused. In real life, similar decisions are many times refused by the business representatives saying that it just should not happen and the IT department has to ensure that the program and the whole operation is totally bug free. There is a psychological reason for such a response, but this really leads us extremely far from Java programming. Engines can execute a script passed through Reader or as String. Because now we have the script code in a resource file, it seems to be a better idea to let the engine read the resource instead of reading it to a String: private Reader getScriptReader(String script) throws IOException { final Reader scriptReader; try { final InputStream scriptIS = new ClassPathResource( "scripts/" + script + ".js").getInputStream(); scriptReader = new InputStreamReader(scriptIS); } catch (IOException ioe) { log.error("The script {} is not readable", script); log.error("Script opening exception", ioe); throw ioe; } return scriptReader; } To read the script from a resource file, we use the Spring ClassPathResource class. The name of the script is prepended with the scripts directory and appended by the.js extension. The rest is fairly standard and nothing we have not seen in this book. The next method that evaluates the script is more interesting: private Object evalScript(String script, Order order, Reader scriptReader) throws ScriptException, NoSuchMethodException { final Object result; final ScriptEngine engine = manager.getEngineByName("JavaScript"); try { engine.eval(scriptReader); Invocable inv = (Invocable) engine; result = inv.invokeFunction("isInconsistent", order); } catch (ScriptException | NoSuchMethodException se) { log.error("The script {} thruw up", script); log.error("Script executing exception", se); throw se; } return result; } To execute the method in the script, first of all, we need a script engine that is capable of handling JavaScript. We get the engine from the manager by its name. If it is not JavaScript, we should check that the returned engine is not null. In the case of JavaScript, the interpreter is part of the JDK and checking that the JDK conforms to the standard would be paranoid. If ever we want to extend this class to handle not only JavaScript but also other types of scripts, this check has to be done, and also the script engine should probably be requested from the manager by the file name extension, which we do not have access to in this private method. But that is future development, not in this book. When we have the engine, we have to evaluate the script. This will define the function in the script so that we can invoke it afterwards. To invoke it, we need some Invocable object. In the case of JavaScript, the engine also implements an Invocable interface. Not all script engines implement this interface. Some scripts do not have functions or methods, and there is nothing to invoke in them. Again, this is something to do later, when we want to allow not only JavaScript scripting but also other types of scripting. To invoke the function, we pass its name to the invokeFunction method and also the arguments that we want to pass on. In this case, this is the order. In the case of JavaScript, the integration between the two languages is fairly developed. As in our example, we can access the field and the methods of the Java objects that are passed as arguments and the returned JavaScript true or false value is also converted to Boolean magically. There are some situations when the access is not that simple though: private void assertResultIsBoolean(String script, Object result) { if (!(result instanceof Boolean)) { log.error("The script {} returned non boolean", script); if (result == null) { log.error("returned value is null"); } else { log.error("returned type is {}", result.getClass()); } throw new IllegalArgumentException(); } } } The last method of the class checks that the returned value, which can be anything since this is a script engine, is convertible to boolean. It is important to note that the fact that some of the functionality is implemented in script does not guarantee that the application works seamlessly. There may be several issues and scripts may affect the inner working of the entire application. Some scripting engines provide special ways to protect the application from bad scripts, others do not. The fact that we do not pass but order to the script does not guarantee that a script cannot access other objects. Using reflection, static methods, and other techniques there can be ways to access just anything inside our Java program. We may be a bit easier with the testing cycle when only a script changes in our code base, but it does not mean that we should blindly trust any script. In our example, it probably would be a very bad idea to let the producers of the products upload scripts to our system. They may provide their check scripts, but these scripts have to be reviewed from the security point of view before being deployed into the system. If this is properly done, then scripting is an extremely powerful extension to the Java ecosystem, giving great flexibility to our programs. Summary In this chapter, we have developed the ordering system of our enterprise application. Along with the development of the code, we met many new things. You learned about annotations and how they can be handled by reflections. Although not strongly related, you learned how to use lambda expressions and streams to express some programming constructs simpler than conventional loops. In the last part of the chapter, we extended the application using scripting, by invoking JavaScript functions from Java and also by invoking Java methods from JavaScript. In fact, with all this knowledge, we matured to a Java level that is needed for enterprise programming. The rest of the topics the book covers are for the aces. But you want to be one, don't you? This is why I wrote the rest of the chapters. Read on! Building an Accounting Application Using Reactive Programming In this chapter, we will develop a sample program that does the inventory management part of the company we created the order handling code for. Do not expect a fully developed, ready-to-use, professional application, and also, do not expect that we will get into the details of accounting and bookkeeping. That is not our aim. We will focus more on the programming technique that is of our interest —reactive programming. Sorry pals, I know that bookkeeping and accounting is fun, but this is not that book. Reactive programming is an old (well, what is old in computer science?) approach that has come recently to Java. Java 9 is the first release that supports some of the aspects of reactive programming in the standard JDK. In one sentence, reactive programming is about focusing more on how the data flows and less on how the implementation handles the data flow. As you may recall, this is also a step towards describing what we want to do from the description of how to do it. After going through this chapter, you will understand what reactive programming is and what tools there are in Java that you can utilize. You will also understand what reactive programming is good for and when and how you can utilize this principle in the future, as there will be more and more frameworks supporting reactive programming in Java. In this chapter, you will learn the following topics: Reactive programming in general Reactive streams in Java How to implement our sample code in a reactive way Reactive... what? There are reactive programming, reactive systems, and reactive streams. These are three different things related to each other. It is not without reason that all the three are called reactive. Reactive programming is a programming paradigm similar to object-oriented programming and functional programming. A reactive system is a system design that sets certain aims and technological constraints on how a certain type of information systems should be designed to be reactive. There are a lot of resemblances to reactive programming principles in this. A reactive stream is a set of interface definitions that helps to achieve similar coding advantage to reactive systems and which can be used to create reactive systems. Reactive stream interfaces are a part of JDK 9, but are available not only in Java, but also in other languages. We will look at these in separate sections, at the end of which, you will presumably have a better understanding of why each of them is called reactive. Reactive programming in a nutshell Reactive programming is a paradigm that focuses more on where the data flows during computation than on how to compute the result. If the problem is best described as several computations that depend on the output of each other but several may be executed independent of the other, reactive programming may come into the picture. As a simple example, we can have the following computation that calculates the value of h from some given b, c, e, and f values, using f1, f2, f3, f4, and f5 as simple computational steps: a d k g h = = = = = f1(b,c) f2(e,f) f3(e,c) f4(b,f,k) f5(d,a,g) If we write these in Java in the conventional way, the methods f1 to f5 will be invoked one after the other. If we have multiple processors and are able to parallelize the execution, we may perform some of the methods in parallel. This, of course, assumes that these methods are purely computational methods and do not change the state of the environment, and, in this way, can be executed independent of each other. For example, f1, f2, and f3 can be executed independent of each other. The execution of the function f4 depends on the output of f3, and the execution of f5 depends on the output of f1, f2, and f4. If we have two processors, we can execute f1 and f2 together, followed by the execution of f3, then f4, and finally, f5. These are four steps. If we look at the preceding calculation not as commands but rather as expressions and how the calculations depend on each other, then we do not dictate the actual execution order and the environment may decide to calculate f1 and f3 together, then f2 and f4, and finally f5, saving one step. This way, we can concentrate on the data flow and let the reactive environment act upon it without putting extra constraints. This is a very simple approach of reactive programming. The description of the calculation in the form of expressions gives the data flow, but in the explanation, we still assumed that the calculation is executed synchronously. If the calculations are executed on different processors that are on different machines connected to a network, then the calculation may not and does not need to be synchronous. Reactive programs can be asynchronously executed if the environment is asynchronous. It may happen that the different calculations, f1 to f4, are implemented and deployed on different machines. In such a case, the values calculated are sent from one to the other over the network and the nodes execute the calculation every time there is a change in the inputs. This is very similar to good old analog computers that were created using simple building blocks and the calculations were done using analogue signals. The program was implemented as an electronic circuit, and when the input voltage or current (usually voltage) changed in the inputs, the analog circuits followed it in light's speed, and the result appeared in the output. In such a case, the signal propagation was limited by the speed of light on the wires and analog circuitry speed in the wired modules, which was extremely fast and may beat digital computers. When we talk about digital computers the propagation of the signal is digital, and this way, it needs to be sent from one calculation node to the other one, be it some object in JVM or some program on the network. A node has to execute its calculation if: Some of the values in the input have changed The output of the calculation is needed If the input has not changed, then the result should eventually be the same as the last time; thus, the calculation does not need to be executed again—it would be a waste of resources. If the result of the calculation is not needed, then there is no need to perform the calculation even if the result would not be the same as the last one. No one cares. To accommodate this, reactive environments implement two approaches to propagate the values. The nodes may pull the values from the output of other modules. This will ensure that no calculation that is not needed will be executed. The modules may push their output to the next module that depends on them. This approach will ensure that only changed values ignite calculation. Some of the environments may implement a hybrid solution. When values change in the system, the change is propagated towards the other nodes that again propagate the changes to another node and so on. If we imagine the calculation dependencies as a directed graph, then the changes travel towards the transitive closure of the changed values along the nodes connected. The data may travel with all the values from one node output to the other node input or only the change may travel. The second approach is more complex because it needs the changed data and also meta information that describes what has changed. On the other hand, the gain may be significant when the output and input set of data is huge and only a small portion of it is changed. It may also be important to calculate and propagate only the actual delta of the change when there is a high probability that some of the nodes do not change the output for many of the different inputs. In such a case, the change propagation may stop at the node where there is no real change in spite of the changed input values. This can save up a lot of calculation in some of the networks. In the configuration of the data propagation, the directed acyclic graph can be expressed in the code of the program, it can be configured or it can even be set up and changed during the execution of the code dynamically. When the program code contains the structure of the graph, the routes and the dependencies are fairly static. To change the data propagation, the code of the program has to be changed, recompiled, and deployed. In the case of multiple network node programs, this may even need multiple deployments that should be carefully furnished to avoid different incompatible versions running on different nodes. There should be similar considerations when the graph is described in some configuration. In such a case, the compilation of the program(s) may not be needed when only the wiring of the graph is changed, but the burden to have compatible configuration on different nodes in the case of a network execution is still there. Letting the graph change dynamically also does not solve this problem. The setup and the structure are more flexible and, at the same time, more complex. The data propagated along the edges of the graph may contain not only computational data but also data that drives change in the graph. Many times, this leads to a very flexible model called higher-order reactive programming. Reactive programming has a lot of benefits but, at the same time, may be very complex, sometimes too complex, for simple problems. It is to be considered when the problem to be solved can easily be described using data graph and simple data propagations. We can separate the description of the problem and the order of the execution of the different blocks. This is the same consideration that we discussed in the previous chapter. We describe more about the what to do part and less about the how to do part. On the other hand, when the reactive system decides the order of execution, what is changed, and how that should be reflected on the output of other blocks, it should do so without knowing the core of the problem that it is solving. In some situations, coding the execution order manually based on the original problem could perform better. This is similar to the memory management issue. In modern runtime environments, such as the JVM, Python runtime, Swift programming, or even Golang, there is some automated memory management. When programming in C, the programmer has full control over memory allocation and memory release. In the case of real-time applications, where the performance and response time is of the utmost importance, there is no way to let an automated garbage collector take time and delay the execution from time to time. In such a case, the C code can be optimized to allocate memory when needed; there is a resource for the allocation and release of memory when possible and there is time to manage memory. These programs are better performing than the ones created for the same purpose using a garbage collector. Still, we do not use C in most of the applications because we can afford the extra resource needed for automated memory collection. Even though it would be possible to write a faster code managing the memory manually, automated code is faster than what an average programmer would have created using C, and also, the frequency of programming errors is much lower. Just as there are some issues that we have to pay attention to when using automated memory management, we have to pay attention to some issues in a reactive environment, which would not exist in the case of manual coding. Still, we use the reactive approach for its benefits. The most important issue is to avoid loops in the dependency graph. Although it is absolutely perfect to write the definition of calculations, a reactive system would probably not be able to cope with these definitions. Some reactive systems may resolve in some simple-case cyclic redundancy, but that is some extra feature and we generally just have to avoid that. Consider the following computations: a = b + 3 b = 4 / a Here, a depends on b, so when b changes, a is calculated. However, b also depends on a, which is recalculated and, in this way, the system gets into an infinite loop. The preceding example seems to be simple, but that is the feature of a good example. Real-life problems are not simple, and in a distributed environment, it is extremely hard sometimes to find cyclic redundancy. Another problem is called glitch. Consider the following definition: a = b + 3 q = b + a When the parameter b is changed, for example, from 3 to 6, the value of a will change from 6 to 9, and thus, q will change from 9 to 15. This is very simple. However, the execution order based on the recognition of the changes may first alter the value of q from 9 to 12 before modifying it to 15 in a second step. This can happen if the calculating node responsible for the calculation of q recognizes the change in b before the value of a as a consequence of the change in the value of b. For a short period of time, the value of q will be 12, which does not match the previous and also does not the changed state. This value is only a glitch in the system that happens after an input changes and also disappears without any further change in the input in the system. If you have ever learnt the design of logical circuits, then static hazards may ring a bell. They are exactly the same phenomenon. Reactive programming also assumes that the calculations are stateless. The individual nodes that perform the calculation may have a state in practice and, many times, they do. It is not inherently evil to have a state in some calculation. However, debugging something that has a state is significantly more complex than debugging something that is stateless, functional. It is also an important aid to the reactive environment, letting it perform different optimizations based on the fact that the calculations are functional. If the nodes have a state, then the calculations may not be rearranged freely because the outcome may depend on the actual evaluation order. These systems may not really be reactive, or, at least, it may be debated. Reactive systems Reactive system is defined in the reactive manifesto at http://www.reactivemanifesto.org/. The creators of the manifesto realized that with the change of technology, new system patterns will need to be developed in enterprise computing to leverage the new technology and yield better outcomes. The manifesto envisions systems that are: Responsive Resilient Elastic Message-driven. The first three features are user values; the last one is more of a technological approach to get the values. Responsive A system is responsive if it gives results in a reliable manner. If you talk to me, I will answer your question or, at least, tell you that I do not know the answer or that I was not able to understand the question. Better if you get the answer, but if a system cannot give that to you it is still expected to give something back. If you have past experience with client operating systems from just ten years ago and some old computers, you can understand this. Getting a rotating hourglass is frustrating. You just do not know whether the system is working to get you the answer or is totally frozen. A reactive system has to be responsive. The response should come in a timely manner. The actual timing depends on the actual system. It may be milliseconds, seconds, or even hours in case the system is running on a space ship travelling towards the other side of Jupiter. The important thing is that the system should guarantee some soft upper limit for the response time. This does not necessarily mean that the system should be a real-time solution, which is a much stricter requirement. The advantage of responsiveness is not only that the user does not become nervous in front of the computer. After all, most of these services are used by other services that mainly communicate with each other. The real advantage is that error discovery is more reliable. If a reactive system element becomes non responsive, it is certainly an error condition, and something should be done about it, out of the scope of normal operations (replace a faulty communication card, restart a system, and so on). The sooner we can identify an error state, the cheaper it is to fix it. The more we can identify where the problem is, the less time and money we could spend localizing the error. Responsiveness is not about speed. It is about better operation, better quality. Resilient Resilient systems keep working even when there is some error. Well, not any error. That would be a miracle, or simply nonsense! An error generally is an error. If the Armageddon comes and it is the end of the world as we know it, even resilient systems will not be responsive. For smaller disruptions, however, there may be some cure to make the systems resilient. There are techniques that may help if only a disk fails, there is a power outage, or there is a programming error. Systems may be replicated, so when one of the instances stops responding, some other instance may take up the task of the failing one and can go on working. Systems prone to errors may be isolated from each other in terms of space or time. When there is an earthquake or flood at one location, the other location may still go on working. If different components do not need to communicate in real time and messages are stored and forwarded in a reliable manner, then this is not a problem even if the two systems are never available at the same time. They can still cooperate taking up the messages, performing the task they are supposed to, and sending out the resulting message afterwards. Errors in the system have to be addressed even if the system remains responsive. Errors do not affect the responsiveness of a resilient system, but the level of resilience decreases and should be restored. Elastic Elasticity means that the system is adapting to the load. We can have a huge system, with lots of processors capable of serving the largest anticipated demand. That is not elasticity. Since the demand is not constant and, most of the time, is smaller than the maximum, the resources of such a system are idle. This causes waste of time, CPU cycle, energy, and, thus, ecological footprint. Having systems run on the cloud can avoid such losses. The cloud is nothing but many computers that somebody operates for multiple applications, for multiple corporations even, and each rents only the CPU cycles that it really needs and only when it needs. Other times, when the load is smaller the CPU and the electric power can be used by someone else. Since different applications and different corporations have different peak times, the loss of resources is less with this model. There are many issues that have to be solved, such as data isolation and protection of information from eavesdropping, but these are mainly solved. Secret service corporations will not rent resources from a cloud service to run their computations (perhaps, they'd do for some other purpose) and some other paranoid companies may also refrain from doing that, but most of the companies will do. It is more effective and is thus cheaper even after considering all the side effects one can consider. Elasticity means that the allocated resources follow, or rather anticipate the coming needs. When the system anticipates higher capacity needs, it allocates more resources and at off-peak time, it releases the resources so that other cloud customers can use it. Elasticity also assumes that the system is scalable. The two things, elasticity and scalability, are closely related but are not the same. Scalability means that the application can accommodate higher load, allocating more resources. Scalability does not care whether this allocation is static buying and powering of huge computer boxes in a computing center dedicated to the application or dynamic allocation of resources from the cloud on demand. Scalability simply means that if the demand doubles, then the resources can also be multiplied to meet the demand. If the multiplication factor in the resources needed is the same or is not more than the factor in demand, then the application is scalable. If we need more resources to meet the demand, or if we cannot meet the demand even if the demand increases only moderately, then the application is not scalable. Elastic applications are always scalable; otherwise, they cannot be elastic. Message-driven Reactive systems are message-driven; not because we need message-driven systems but much rather because message-driven systems are those that can deliver responsiveness, resilience, and elasticity at the same time. Message-driven architecture means that the information travels between the components disconnected. One component sends a message and then forgets it. It does not wait for the other component to act upon the message. When the message is sent, all the tasks on behalf of the sending component are performed and all the resources needed to handle the tasks are released, resulting in the message being released and ready to be used for the next task. Message-driven does not necessarily mean networking. Messages can travel between objects, threads, and processes inside the same machine. On the other hand, if the interfaces to the messaging architecture are well-designed, then the components do not need to be modified if the infrastructure changes and the messages that were previously passing between threads will now have to travel through the ocean in IP packets. Sending messages makes it possible to isolate the sender and the receiver in space and time, just as we described, as a means for elasticity. The receiver may pick up the message some time after it arrived, when it has the resources to do so. Responsiveness, though, requires that this time is not in the unreachable distant future but in some limited distance. If the message cannot be processed successfully, another message may signal the error. An error message is not the result we expect, but it is still some response and the system remains responsive with all the benefits it means. Back-pressure Message handling, with the appropriate messaging interfaces and implementation, supports back-pressure. Back-pressure is a means to lessen the burden on a component when it cannot or can barely handle more messages. Messages may be queuing for processing, but no real-life queue has unlimited capacity and reactive systems should not lose a message uncontrolled. Back-pressure signals the load of the component to the message producers, asking them to lessen the production. It is like a water pipe. If you start closing the outlet of the pipe, the pressure starts to increase in the pipe backward, the water source forcing it to deliver less and less water. Back-pressure is an effective way of handling load because it moves load handling to the component that can really do it. In old-fashioned queuing systems, there is a queue that stores the items till the component receiving them can consume them, doing its job. A queue design can be good if there is a well-defined limit for the size of the load and for the maximum size of the queue. If ever the queue is full, the items cannot be delivered and the system stalls. Applying back-pressure is a bit different. A queue may still be used in front of the components for performance optimization and to ensure responsiveness. The producer of the item can still put the produced item in the queue and return to attending to its own duties and does not need to wait till the consumer can attend to the item. This is decoupling, as we mentioned earlier. Seeing that the queue is full or almost full can also act as a very simple back-pressure. It is not true if someone says that queues are totally missing this feature. At times, it may simply be totally sufficient just to look at the capacity of a queue, and also the items in it, to see if there is some need to lessen the load on the receiver the queue belongs to. But the producer does this, not the receiver, and that is an essential problem. The producer sees that the receiver is not keeping pace with the supply but the producer does not have any information about the cause, and not knowing the cause cannot predict the future behavior. Having a backpressure information channel from the receiver to the producer makes the story more fine grained. The producer may see that there are, say, 10 slots in the queue and it thinks that there is no problem; the producer decides to deliver eight more items in the next 150ms. One item usually takes 10ms to process, give or take; thus the items are expected to be processed in less than 100ms, which is just better than the required 200ms maximum. The producer only knows that an item usually takes 10ms to process. The receiver, on the other hand, sees that the last item it got into the queue requires so much processing that, by itself, it will require 200ms. To signal this, it can tell the producer over the back-pressure not to deliver new items till further notice. The receiver knows that the items would have fit in the queue fine but would not be processed in a timely manner. Using this information, the producer will issue some commands to the cloud control to allocate another processing and sends the next eight items to the new receiver, letting the old one do its cumbersome job it has to with that far above than average item. Back-pressure lets you aid the data load control, with information created by the receivers that have the most information about processing the items. Reactive streams Reactive streams started as an initiative to provide a standard of handling data streams in an asynchronous mode by regulating the push of the data using back-pressure. The original site of the project is http://www.reactive-streams.org/. Reactive streams are now implemented in JDK 9 in the java.util.concurrent package. The aim of the definition of reactive streams is to define the interface that can handle the propagation of the generated data in a totally asynchronous way without the need on the receiving side to buffer the unlimited created data. When data is created in a stream and is made available to be worked on the worker that gets the data, has to be fast enough to handle all the data that is generated. The capacity should be high enough to handle the highest production. Some intermediate buffers may handle peaks, but if there is no control that stops or delays production when the consumer is at the top of its capacity, the system will fail. Reactive system interfaces are designed to provide a way to support back-pressure. Backpressure is a process to signal the producer of the data to slow down or even to stop the production to the level that fits the consumer. Every call the interfaces define is asynchronous so that the performance of one part is not affected by the delays in the execution of other parts. The initiative did not aim to define the way in which data is transferred between production and consumption. It focuses on the interfaces to give a clear structure for the programs and also to give an API that will work with all the implementations. Reactive programming in Java Java is not a reactive language. This does not mean that we cannot create reactive programs in Java. There are libraries that support different reactive programming approaches. It is to mention the Akka framework and the ReactiveX that also exist for other languages as well. With Java 9, the JDK starts to support reactive programming, providing a few classes and interfaces for the purpose. We will focus on these features. The JDK contains the java.util.concurrent.Flow class, which contains related interfaces and some static methods to support flow controlled programs. The model that this class supports is based on Publisher, Subscriber, and Subscription. As a very simple explanation, a Publisher accepts a subscription from a Subscriber. A Subscriber gets the data it subscribed to when the data is available. The interfaces focus on the very core of the data flow control of the communication and are a bit abstract. No surprise, they are interfaces. However, it may not be simple to understand their working at first. The Publisher interface defines the subscribe method. This is the only method this interface defines and that is because this is the only thing that a real publisher can be asked. You can subscribe to the publications. The argument of the method is a Subscriber that subscribes to the publications: void subscribe(Flow.Subscriber<? super T> subscriber) There is a readily available Publisher class in the JDK that we will look at later. When the subscribe method of the Publisher is called, it has to decide if the subscriber can get the subscription or not. Usually, the subscription is accepted but the implementation has the freedom to refuse a subscription attempt. Publisher may refuse a subscription if, for example, the subscription for the actual subscriber was already performed and the Publisher implementation does not allow multiple subscriptions from the same subscriber. The implementation of the method is required to call the onError method of subscriber, with Throwable as the argument. In the case of multiple subscriptions, IllegalStateException seems to be suitable, as the JDK documentation defines at the moment. If the subscription is successful, Publisher is expected to call the onSubscribe method of subscriber. The argument to this method is a Subscription object (an instance of a class that implements the interface Subscription). This way, the Publisher notifies the Subscriber that the subscription request was accepted, and also passes an object to manage the subscription. Managing the subscription as an abstraction could be imagined as a complex task, but in the case of reactive streams, it is very simple. All the subscriber can and should do is to set the number of items it can receive at the moment, and the subscription can be cancelled. Why should the Publisher call back the onSubscribe method of Subscriber? Why doesn't it simply return the subscription or throw some error? The reason for this complex behavior is that it may not be the Subscriber that invokes the subscribe method. Just as in real life, I can subscribe and pay for a year of a magazine subscription as a Christmas gift. (This is the season when I am writing this part of the book.) In our code, some wiring component responsible for who is notified about a certain data change calls subscribe and not necessarily the subscriber. The Subscriber is only responsible for the minimal things that a subscriber should be responsible for. The other reason is that the whole approach is asynchronous. When we subscribe to something, the subscription may not be available and ready immediately. There could be some long-running processes that need to finish till the subscription will be available and the caller that is calling subscribe does not need to wait for the completion of the process. When the subscription is ready it is passed to the subscriber, to the very entity that really needs it. The Subscriber interface defines the onSubscribe, onError (we have already talked about these), onComplete and onNext methods. It is important in the definition of these interfaces that the subscriber gets the items from Publisher or from some other object to which the Publisher delegates this task via some push. The subscriber does not need to go to the newsstand to get the next issue; someone calling the onNext method delivers the issue to it directly. This also bears the consequence that unless there are some controls in the hands of the Subscriber, it could happen that the Publisher floods the Subscriber with items. Not every Subscriber is capable of handling unlimited items. The Subscriber gets a Subscription object upon performing the subscription and this object can be used to control the flow of the item objects. The Publisher creates the Subscription object and the interface defines two methods: cancel and request. The cancel method should be called by the Subscriber to notify the Publisher that it should not deliver more items. The subscription is cancelled. The request(long n) method specifies that the subscriber is prepared to get at most n items via subsequent calls to the onNext method: If the subscriber has already invoked the request method, the specified number is added to the subscription counter. In other words, the specified long value does not reflect the actual state of the subscriber. It is a delta, increasing some counters maintained by the Publisher that counts the number of items that can be delivered adding the value of the long argument and decrementing by one on each item delivered to the Subscriber. The most usual approach is to call request(1) each time the Subscriber has finished processing a request. If the request method is invoked with the Long.MAX_VALUE argument, the Publisher may just send any item that it can without counting and without limit. This is essentially switching off the back-pressure mechanism. The specification also mentions that the call to cancel does not necessarily mean that there will be no more issues delivered at all. Cancellation is done on best effort. Just as in real life, when you send your mail to the daily paper with your intent to cancel the subscription, the publisher will not send an agent to stop the postman before he drops the issue to your mailbox. If something was already on its way when the cancellation arrived to the publisher it goes its way. If the Publisher has already started some asynchronous process that cannot reasonably be stopped, then the method onNext method will be invoked with some of the elements. The Publisher and Subscriber interfaces have a generic parameter, T. This is the type of items that the Publisher interface publishes and the Subscriber interface gets in the onNext method. To be a bit more precise, the Subscriber interface can have an R type, which is a superclass of T; thus, it is compatible with the Publisher interface. For example, if Publisher publishes Long values, then the Subscriber interface can accept Long, Number, or Object in the argument of the onNext method, depending on the declaration of the class that implements Subscriber. The Flow class also contains a Processor interface that extends both Publisher and Subscriber. This interface is there to be implemented by classes that also accept data and send data to other components in the reactive flow. Such elements are very common in reactive stream programs because many elements that perform some tasks get the items to work on from other reactive stream elements; thus, they are Subscribers and, at the same time, they send it after they have finished their tasks; thus, they are Publishers. Implementing inventory Now that we have discussed a lot of technologies and programming approach, it is very much the time to implement some sample code. We will implement inventory keeping in our application using reactive streams. For the example, the inventory will be very simple. It is a Map<Product,InventoryItem> that holds the number of items for each product. The actual map is ConcurrentHashMap and the InventoryItem class is a bit more complex than a Long number to properly handle concurrency issues. When we design a program that is built on responsive streams, we do not need to deal with much concurrency locking, but we still should be aware that the code runs in a multithread environment and may exhibit strange behavior if we do not follow some rules. The code for the Inventory class is fairly simple since it handles only a map: package packt.java9.by.example.mybusiness.inventory; import ...; @Component public class Inventory { private final Map<Product, InventoryItem> inventory = new ConcurrentHashMap<>(); private InventoryItem getItem(Product product) { inventory.putIfAbsent(product, new InventoryItem()); return inventory.get(product); } public void store(Product product, long amount) { getItem(product).store(amount); } public void remove(Product product, long amount) throws ProductIsOutOfStock { if (getItem(product).remove(amount) != amount) throw new ProductIsOutOfStock(product); } } The inventory item maintaining the class is a bit more complex since this is the level where we handle a bit of concurrency or, at least, this is the class where we have to pay some attention: package packt.java9.by.example.mybusiness.inventory; import java.util.concurrent.atomic.AtomicLong; public class InventoryItem { private final AtomicLong amountOnStock = new AtomicLong(0); void store(long n) { amountOnStock.accumulateAndGet(n, (stock, delta) -> stock + delta); } long remove(long delta) { class ClosureData { long actNr; } ClosureData d = new ClosureData(); amountOnStock.accumulateAndGet(delta, (stock, n) -> stock >= n ? stock - (d.actNr = n) : stock - (d.actNr = 0) ); return d.actNr; } } When we add products to the inventory, we have no limit. The storage shelves are extremely huge and we do not model that they once may get full and the inventory may not be able to accommodate more items. When we want to remove items from the repository, however, we have to deal with the fact that there may not be enough items from the product. In such a case, we do not remove any items from the repository. We serve the customer to full satisfaction or we do not serve at all. To maintain the number of the items in the inventory, we use AtomicLong. This class has the accumulateAndGet method. This method gets a Long parameter and a LongBinaryOperator that we provide in our code as a lambda. This code is invoked by the accumulateAndGet method to calculate the new value of the stock. If there are enough items, then we remove the requested number of items. If there are not enough items on stock, then we remove zero. The method returns the number of items that we actually return. Since that number is calculated inside the lambda, it has to escape from there. To do so, we use ClosureData defined inside the method. Note that, for example, in Groovy we could simply use a Long d variable and alter the variable inside the closure. Groovy calls lambda to closures, so to say. In Java we cannot do so because the variables that we can access from inside the method should be effectively final. However, this is nothing more than a bit more explicit notation that belongs to the closure environment. The ClosureData d object is final as opposed to the field the class has, which can be modified inside the lambda. The most interesting class that we are really interested in this chapter is InventoryKeeper. This class implements the Subscriber interface and is capable of consuming orders to maintain the inventory: package packt.java9.by.example.mybusiness.inventory; import ... public class InventoryKeeper implements Flow.Subscriber<Order> { private static final Logger log = LoggerFactory.getLogger(InventoryKeeper.class); private final Inventory inventory; public InventoryKeeper(@Autowired Inventory inventory) { this.inventory = inventory; } private Flow.Subscription subscription = null; private static final long WORKERS = 3; @Override public void onSubscribe(Flow.Subscription subscription) { log.info("onSubscribe was called"); subscription.request(WORKERS); this.subscription = subscription; } The onSubscribe method is invoked after the object is subscribed. The subscription is passed to the object and is also stored in a field. Since the subscriber needs this subscription in subsequent calls, when an item passed in onNext is processed and a new item is acceptable, a field is a good place to store this object in. In this method, we also set the initial request to three items. The actual value is simply demonstrative. Enterprise environments should be able to configure such parameters: private ExecutorService service = Executors.newFixedThreadPool((int) WORKERS); The most important part of the code is the onNext method. What it does is actually goes through all the items of the order and removes the number of items from the inventory. If some of the items are out of stock, then it logs an error. This is the boring part. The interesting part is that it does this through an executor service. This is because the call to onNext should be asynchronous. The publisher calls onNext to deliver the item, but we should not make it wait for the actual processing. When the postman brings your favorite magazine, you don't start reading it immediately and make the postman wait for your signature approving acceptance. All you have to do in onNext is fetch the next order and make sure that this will be processed in due time: @Override public void onNext(Order order) { service.submit(() -> { int c = counter.incrementAndGet(); for (OrderItem item : order.getItems()) { try { inventory.remove(item.getProduct(), item.getAmount()); } catch (ProductIsOutOfStock exception) { log.error("Product out of stock"); } } subscription.request(1); counter.decrementAndGet(); } ); } @Override public void onError(Throwable throwable) { log.info("onError was called for {}", throwable); } @Override public void onComplete() { log.info("onComplete was called"); } } The actual implementation in this code uses ThreadPool with three threads in it. Also, the number of required items is three. This is a logical coincidence: each thread works on a single item. It does not need to be like that, even if in most cases it is. Nothing can stop us from making more threads working on the same item if that makes sense. The opposite is also true. One single thread may be created to work on multiple items. These codes will probably be more complex and the whole idea of these complex execution models is to make the coding and the logic simpler, move the multithreading, coding, and implementation issues into the framework, and focus on the business logic in the application code. But I cannot tell that there may not be an example for a subscriber working multiple threads on multiple items, intermingled. The last code we have to look at in this chapter is the unit test that drives the code with some examples: public void testInventoryRemoval() { Inventory inventory = new Inventory(); SubmissionPublisher<Order> p = new SubmissionPublisher<>(); We create Publisher using the JDK class, SubmissionPublisher, which neatly implements this interface delivering multithread functionality for us without much hassle: p.subscribe(new InventoryKeeper(inventory)); We create an inventory keeper and we subscribe to the publisher. This does not start delivering anything because there are no publications yet, but it creates a bond between the subscriber and the publisher telling, them that whenever there is a product submitted, the subscriber wants it. After that, we create the products and store them in the inventory, 20 pieces altogether, and we also create an order that wants 10 products to be delivered. We will execute this order many times. This is a bit of simplification, but for the test, there is no reason to create separate order objects that have the same products and the same amounts in the list of items: Product product = new Product(); inventory.store(product, 20); OrderItem item = new OrderItem(); item.setProduct(product); item.setAmount(10); Order order = new Order(); List<OrderItem> items = new LinkedList<>(); items.add(item); order.setItems(items); After all this has been done, we submit the order to the Publisher 10 times. It means that there are 10 orders for the same product, each asking for 10 pieces, that is, 100 pieces together. Those are 100 pieces against the warehouse where we have only 20 of it. What we should expect is that only the first two orders will be fulfilled and the rest will be rejected and that is what will actually happen when we execute this code: for (int i = 0; i < 10; i++) p.submit(order); log.info("All orders were submitted"); After all the orders are published, we wait for half a second so that the other threads have time to execute and then we finish: for (int j = 0; j < 10; j++) { log.info("Sleeping a bit..."); Thread.sleep(50); } p.close(); log.info("Publisher was closed"); } Note that this is not a regular unit test file. It is some test code to play around, which I also recommend for you to execute, debug, and look at the different log outputs. Summary In this short chapter, we had a look at reactive programming, reactive systems, and reactive streams. We discussed the similarities and the differences between these that may lead to confusions. We paid special attention to Java 9 reactive streams that have practically nothing to do with Stream classes and methods. In the second half of the chapter, we discussed a very simple example that uses reactive streams. After reading this chapter, you have learned a lot about the Java language and programming. We did not detail all the small bits of Java, but that is not possible in a book. I dare say that there is no man (or woman for that matter) on the Earth or around it on an orbital route, wherever humans are, who knows everything about Java. We, however, know enough by now to start coding in an enterprise environment and to learn more and more on the go till we retire, or even after that. What is still left is a little bit of programming. In the previous sentence I said coding to make some distinction. Coding is not the same as programming. Coding is a technique used in the profession of programming. During the next, and last, chapter we will see the aspects of programming and how it can, and should, be done in professional manner. This is rarely a part of an introductory book, but I am happy that we could agree on this topic with the publisher. This way, you can finish the book not only with the knowledge that you learn from this book, but also with a vision, looking ahead on the road you will walk up the hillside to the top. You will know the topics, areas, and subjects that you can go on learning. Finalizing Java Knowledge to a Professional Level By now, you have learned the most important areas and topics needed for a professional Java developer. What we still have ahead of us in this book is to discuss some topics that will lead you from being a junior developer to a senior developer. Reading this chapter will not make anyone a senior developer, though. The previous chapters were the roads that we walked through. This chapter is only the map. If each of the previous chapters covered a short walk of a few miles in the journey of coding to reach the harbor, then this chapter is the nautical map to discover a new continent. We will briefly bite into some very deep and high-level professional areas, such as creating a Java agent, compile-time annotation processing, polyglot programming, a bit of architecture design and tools, and techniques to work in teams. We'll do it just for the taste. Now, you have enough knowledge to understand the importance of these topics, and getting a taste will create an appetite for the coming years of selfdevelopment, or, at least, that is my intention to make you, the reader, addicted. Java deep technologies In this section, we will list three technologies: Java agent Polyglot programming Annotation processing Knowing them is not a must for a Java professional. Knowing about them is. Java agents are used mainly in development environments and in operation. They are complex runtime technologies that interact with the already running JVM. Annotation processing is the other end. Annotation processors are plugged into the Java compiler. Polyglot programming is in the middle. It is JVM programming, just like programming in Java, but by using some different language or, perhaps, some different language and Java together. Or even many languages, such as Jython, Groovy, Clojure, and Java together. We will discuss these technologies so that we will get some idea about what they are and where to look for further information in case we want to learn more about them. Java agent A Java agent is a Java program that is loaded by the Java runtime in a special way and can be used to interfere with the byte code of the loaded classes, altering them. They can be used to: List or log, and report the loaded classes during runtime, as they are loaded Modify the classes so that the methods will contain extra code to report runtime behavior Support debuggers to alter the content of a class as the developer modifies the source code This technology is used in, for example, the products JRebel and XRebel from https://zeroturnaround.com/. Although Java agents work in the deep details of Java, they are not magic. They are a bit complex and you need a deep understanding of Java, but anyone who can program in Java can write a Java agent. All that is required is that the class, which is the agent, has some predefined methods packaged into a JAR file along with the other classes of the agent and has a META-INF/MANIFEST.MF file that defines the names of the classes implementing the premain and/or agentmain methods, and some other fields. The detailed and precise reference documentation is part of the JDK JavaDoc available at http://download.java .net/java/jdk9/docs/api/ in the documentation of the java.lang.instrument package. When a Java application is started with a Java agent, the command line has to contain the following option: -javaagent:jarpath[=options] Here, jarpath points to the JAR file that contains the agent class and the manifest file. The class must have a method named premain or agentmain. It may have one or two arguments. The JVM tries to call the twoargument version first after the JVM is initialized: public static void premain(String agentArgs, Instrumentation inst); If a two-argument version does not exist, then the one-argument version is used, which is essentially the same as the two-argument version but misses the instrumentation argument, which, in my opinion, does not make too much sense since a Java agent cannot do much without the Instrumentation object: public static void premain(String agentArgs); The agentArgs parameter is the string passed as an option on the command line. The second argument, Instrumentation, provides methods to register class transformers that can modify class byte codes and also methods that can ask the JVM to perform redefinition or retransformation of classes during runtime. Java applications can also load an agent after the program has already started. In such a case, the agent cannot be invoked before the main method of the Java application, since it has already started by that time. To separate the two cases, JVM calls agentmain in such a scenario. Note that either premain or agentmain is invoked for an agent and never both. A single agent can implement both so that it is capable of performing its task loaded at the startup, specified on the command line or after the JVM started. If agentmain is used, it has the same arguments as premain. There is one major and important difference between the invocation of premain and agentmain. If an agent cannot be loaded during startup, for example, if it cannot be found, if the JAR file does not exist, if the class does not have the premain method, or if it throws an exception, the JVM will abort. If the agent is loaded after the JVM is started (in this case, agentmain is to be used), the JVM will not abort if there is some error in the agent. This approach is fairly reasonable. Imagine that there is a server application that runs on the Tomcat servlet container. When a new version is started, the system is down for a maintenance period. If the new version cannot be started because the agent is not behaving well, then it is better not started. The damage to debug the situation and fix it, or roll back the application to the old version and call for a longer fixing session may be less than starting up the application and not having the proper agent functionality. If the application starts up only without the agent, then the suboptimal operation may not immediately be recognized. On the other hand, when an agent is attached later, the application is already running. An agent is attached to an already running application to get information from an already running instance. To stop the already running instance and fail it, especially in an operational environment, is more damaging than just not attaching the agent. It may not go unnoticed anyway because the agent that is most probably attached is used by operational personnel. A premain or agentmain agent gets an Instrumentation object as the second argument. This object implements several methods. One of them is: void addTransformer(ClassFileTransformer transformer) The agent implements the transformer, and it has the transform method signature: byte[] transform(Module module, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException This method is called by the JVM when a class is loaded or when it is to be transformed. The method gets the class object itself, but, more importantly, it gets the byte array containing the byte code of the class. The method is expected to return the byte code of the transformed class. Modifying the byte code needs some knowledge of how the byte code is built and what the structure of a class file is. There are libraries that help to do that, such as Javassist (http://www.javassist.org/ ) or ASM (http://asm.ow2.org/). Nevertheless, I will not start coding before getting acquainted with the structure of the byte code. Agents, running in a separate thread and presumably interacting with the user or the filesystem and based upon some external observation at any time, may call the following method to perform the retransformation of the classes using the registered transformers: void retransformClasses(Class<?>... classes) The agent can also call the following method, which will redefine the classes given as arguments: void redefineClasses(ClassDefinition... definitions) The ClassDefinition class is simply a Class and a byte[] pair. This will redefine the classes through the class maintaining mechanism of the JVM. Note that these methods and Java agents interact with the deep, low-level part of the JVM. This also bears the consequence that it is very easy to destroy the whole JVM. The byte code is not checked, unlike during the loading of the class, and thus, if there is some error in it, the consequence may not only be an exception but also the crashing of the JVM. Also, the redefinition and the transformations should not alter the structure of the classes. They should not change their inheritance footprint, add, rename, or remove methods, or change the signature of the methods, and this is also true for fields. Also note that the already created objects will not be affected by the changes; they will still use the old definition of the class and only new instances will be affected. Polyglot programming Polyglot programming is the technique when there are different programming languages used in the same application. Such an approach is not only appropriate when a different part of the application runs on a different environment. For example, the client executes in the browser using JavaScript, CSS, and HTML while the server is programmed to run in a Tomcat environment in Java. This is a different story, and, usually, this is not the typical use when someone is speaking about polyglot programming. When the application that runs on the server partially runs in Java and also in some other language, then we can speak about polyglot programming. For example, we create the order handling application in Java and some of the code that checks the correctness of the order based on the product-specific codes that the order contains is written in JavaScript. Does it ring a bell? We have already done that in this book to demonstrate the scripting API of the JDK. That was real polyglot programing even if we did not mention it that way. The JVM that runs the compiled Java code is a very good target for different language compilers, and thus, there are many languages that compile for it. When the JVM runs the byte code of a class, it does not know what the source language was, and it does not really care; some compiler created the byte code and it just executes that. We can use different languages, such as Jython, Groovy, and Scala, to name a few popular ones that compile for the JVM. We can write one class using one language and the other one using another. When they are put together into a JAR, WAR, or an EAR file, the runtime system will just run them. When do we use polyglot programming? Polyglot configuration Usually, we turn towards polyglot programming when we want to create an application that is more flexible and more configurable. Applications that get installed in many instances, usually, at different customer sites have some configurations. These configurations can be XML files, properties files, and INI files (those come from Windows). As the programs develop sooner or later, these static configuration possibilities reach their limits. Application developers soon see that they need to configure some functionality that is cumbersome to describe using these technologies. Configuration files start being larger and, also, the code that reads and interprets the configuration files grow large. Good developers have to realize that this is the situation, and before the configuration files and the code handling them become unmanageable, some scripting configuration, polyglot programming has to be implemented. Decent developer teams may reach a point when they develop their configuration language and the interpreter of that language. It can be based on XML, or it can just be any other language. After all, writing a language is fun; I have done it a few times myself. Most of these were, however, hobbies and not professional projects. Usually, there is no customer value in crafting another language. We can better use an existing one. In the case of configuration, Groovy is a very handy language that supports complex closure and metaclass syntax and implementation. This way, the language is extremely suitable to create a domain-specific language. Since Groovy is compiled to JVM, Groovy classes can be invoked directly from Java, and in the other way round, reading the configuration is essentially invoking the class compiled from the configuration file. The compilation can be during application build time, but in the case of configuration, it makes more sense to do it during application startup. We have already seen that the Groovy implementation of the scripting API or the special API that Groovy provides is absolutely capable of doing that. Have we seen examples of this in our book? It may be a surprise to you, but we have in fact used Groovy to describe some configuration many times. Gradle build files are nothing more than Groovy DSL developed mainly in Groovy to support project build configuration. Polyglot scripting Configuration is not the only application of polyglot programming. Configuration is executed at the program startup and the configuration data is used as static data afterwards. We can execute scripts during the application's execution any time and not only during its startup. This can be used to provide extra functionality to the program's user with installations that use the same application but are furnished with different scripts. One of the first applications that provided such scripting capability was the emacs editor. The core of the application was written in C language and it contained a Lisp interpreter that let the user to write scripts, which were executed in the editor environment. The engineering program, AutoCAD, also used a Lisp interpreter for similar purposes. Why was Lisp used for this purpose? Lisp has very simple syntax, and therefore, it is easy to parse Lisp code. At the same time, the language is powerful, and last but not least, there were open source Lisp interpreters (at least one) available by the time. To get this kind of flexibility, applications, many times, provide plugin APIs, which a developer can use to extend the application. This, however, requires that the developer sets up coding tools, including IDE, build tool, continuous integration, and so on, that is, a professional programming environment. When the task to be solved by the plugin is simple, the overhead is simply too large. In such a case, a scripting solution is handier. Scripting is not a solution for everything. When the scripts extending the application tend to become too complex, it means that the scripting possibility is just too much. It is difficult, however, to take back a toy from a child. If users get used to the scripting possibility, then they will not take it easy if the next version of the application we release does not provide that possibility. Thus, it is extremely important to assess the possible use of the scripting capability in our application. Scripting and, more generally, any feature of our program will not be used for what we intended them for. They will be used for whatever it is possible to use them for. Users can go beyond all imagination when it comes to abusing some feature. It may be a good idea to think about limiting the scripting possibility beforehand, limiting the running time of the scripts or the size of the script our program agrees to work with. If these limitations are set reasonably, and the users understand and accept these, a plugin structure in addition to the scripting capability has to be considered. The security of an application, including plugin or scripting extension, is also very important. The scripts or plugins run on the same JVM as the core application. Some scripting languages provide some fence around the scripts that limits the access to the core application's objects and classes, but this is an exception. Usually, scripts run with the same privilege as the core application and that way they can do just anything. Thus, scripts should be trusted the same way as the core application. Script installation or modification should never be possible for an unprivileged user of the application. Such an action is almost always reserved for the system administrator. If an unprivileged user can upload a script to the server and then have it executed, we just opened a security hole in our application. Since access restrictions are enforced by the application, it is easy to override these limitations using an uncontrolled script. The hacker can just access other users' data easily, which he is not entitled to, and read and modify our database. Business DSL Polyglot programming may also come into the picture when the application's code can be separated into business code and technology code. The business code contains the top-level business logic that we actually write the application for, and this is the code that contains the logic that the customer pays for. The technology code is to support the algorithms coded in the business DSL. Most of the enterprise applications contain these two types of code but many do not separate them. This leads to a monolithic application that contains repetitive code. When you feel that you are writing the same type of code when you need persistence or networking, and again the same type of code while coding some business rules, then this is the code smell that suggests that the two code types are not separated. DSL and scripting are not a magic wand and do not solve all the problems that stem from a wrong application structure. In such a situation, the code has to be refactored first to separate the business logic and the infrastructure code, and it is only the second step to implement a DSL and a business API supporting it and to rewrite the business code into the DSL. Every step of such a project delivers value for the application and even if it never gets to DSL and scripting, the effort invested is not wasted. The business DSL scripting is very similar to pluggable scripts, except that this time it is not the application that calls the scripts from time to time to execute some special extension functionality. Instead, the DSL code calls the application through the business API that it provides. The advantage of providing the API and using a DSL is that the code that implements the business logic gets rid of the technical details, can be very abstract, and, this way, be much closer to a business-level description of the problem rather than just program code. Even some businessperson can understand a business DSL, and though it is not a goal in real-life examples, they could even write code. At TU Vienna, we also used a similar approach to make semiconductor simulation more usable for the semiconductor design engineer. The core calculating code was written in Fortran. A C language framework that handled the massive simulation data input and output and that embedded the XLISP interpreter executed these programs. The Lisp code contained the simulation configuration data and could also contain simple loops when the simulation was to be executed for many configuration points. It was polyglot programming, except that we did not know that this is going to be the name years after this application coding style. Problems with polyglot Polyglot programming is not only all about advantages. Before jumping into this direction, developers making the decision have to consider a lot of things. Using another language for the application needs knowledge. Finding people who can code in the languages that are used is eventually more difficult than finding developers who only know Java. (This is also true if the kernel application language is not Java.) Different languages require different mindsets and, many times, different people. The team should also have some members who are proficient in both languages, and it is also an advantage if most of the people know at least a bit about the other language. The toolset supporting Java is outstanding. The build tools, integrated development environment, libraries, debugging possibilities, and logging frameworks, to name a few, are all extremely good compared with other languages. Polyglot development needs support for the other language as well, which may not be as advanced as the support for Java. Many times, it is really an issue to debug DSL solutions and IDE support may also be lagging. When we program in Java, many times, we take for granted that the IDE reads the meta-data of the libraries and whenever we need to call a method, or reference a class, the IDE suggests the best possibility. XML and properties files may also be supported and the IDE may know some of the most used frameworks, such as Spring, and understand the XML configuration handling the names of the classes as hyperlinks, even when the class names are inside some attribute strings. This is far from being this easy in the case of other languages. For the languages that have a wide user base, the tooling support may be good, but if you pick some exotic language, you are on your own. The more exotic the language the less support you may have. You can create some tool to support your DSL that you develop. It is not hard to do so using tools such as http://www.eclipse.org/Xtext/. In such a case, you are tied to Eclipse, which may or may not be a problem. You can pick a special language, for example, Kotlin, which is extensively supported by IntelliJ, because the same company supports the language and the IDE, but again, you buy into a special technology that can be expensive to replace in case you have to. It is generally true not only for languages but also for any technology you include into your development. When you select one, you should consider the support and the cost of getting off the horse if or when it starts dying. Annotation processing We have already discussed annotations in great detail. You may recall that we defined our annotation interfaces using the following annotation: @Retention(RetentionPolicy.RUNTIME) This told the Java compiler to keep the annotation and put it into the JVM code so that the code can access it during runtime using reflection. The default value is RetentionPolicy.CLASS, which means that the annotation gets into the byte code, but the JVM does not make it available for the runtime system. If we use RetentionPolicy.SOURCE, the annotation does not even get into the class file. In this case, there is only one possibility to do anything with the annotation: compile time. How can we write code that runs during compile time? Java supports the notion of annotation processors. If there is a class on the classpath of the compiler that implements the javax.annotation.processing.Processor interface, then the compiler will invoke the implemented methods one or more times, passing information about the source file that the compiler is actually processing. The methods will be able to access the compiled methods, classes, or whatever is annotated, and also the annotation that triggered the processor invocation. It is important, however, that this access is not the same as in runtime. What the annotation processor accesses is neither a compiled nor a loaded class, that is, it is available when the code uses reflection. The source file at this time is under compilation; thus, the data structures that describe the code are actually structures of the compiler, as we will see in our next example. The annotation processor is called one or more times. The reason it is invoked many times is that the compiler makes it possible for the annotation processors to generate source code based on what it sees in the partially compiled source code. If the annotation processor generates any Java source file, the compiler has to compile the new source code and perhaps compile some of the already compiled files again. This new compilation phase needs annotation processor support until there are no more rounds to execute. Annotation processors are executed one after the other, and they work on the same set of source files. There is no way to specify the order of the annotation processor executions; thus, two processors working together should perform their tasks, no matter in what order they are invoked. Also, note that these codes run inside the compiler. If an annotation processor throws an exception, then the compilation process will most probably fail. Thus, throwing an exception out of the annotation processor should only be done if there is an error that cannot be recovered and the annotation processor decides that the compilation after that error cannot be complete. When the compiler gets to the phase to execute the annotation processors, it looks at the classes that implement the javax.annotation.processing.Processor interface and creates instances of these classes. These classes have to have a public no-argument constructor. To streamline the execution of the processors and to invoke a processor only for the annotations that it can handle, the interface contains two methods: to return the latest version the annotation processor can support getSupportedAnnotationTypes to return a set of String objects containing the fully qualified class name of getSupportedSourceVersion the annotations that this processor can handle If an annotation processor was created for Java 1.8, it may work with Java 9, but it may also not work. If it declares that the latest supported version is 1.8, then the compiler in a Java 9 environment will not invoke it. It is better not to invoke an annotation processor than calling it and messing up the compilation process, which may even create compiled but erroneous code. The values returned by these methods are fairly constant for an annotation processor. An annotation processor will return the same source version it can handle and will return the same set of annotations. Therefore, it would be clever to have some way to define these values in the source code in a declarative manner. It can be done when we extend the javax.annotation.processing.AbstractProcessor class instead of directly implementing the Processor interface. This abstract class implements these methods. Both of them get the information from the annotation so that we can decorate the class that extends the abstract class. For example, the getSupportedAnnotationTypes method looks at the SupportedAnnotationTypes annotation and returns an array of annotation type strings that are listed in the annotation. Now, this is a bit brain twisting and can also be confusing at first. We are executing our annotation processor during compile time. But the compiler itself is a Java application, and in this way, the time is runtime for the code that runs inside the compiler. The code of AbstractProcessor accesses the SupportedAnnotationTypes annotation as a runtime annotation using reflection methods. There is no magic in it. The method in the JDK 9 is as follows: public Set<String> getSupportedAnnotationTypes() { SupportedAnnotationTypes sat = this.getClass().getAnnotation (SupportedAnnotationTypes.class); if (sat == null) { ... error message is sent to compiler output ... return Collections.emptySet(); } else return arrayToSet(sat.value()); } (The code has been edited for brevity.) To have an example, we will sort of look at the code of a polyglot annotation processor. Our very simple annotation processor will process one simple annotation: com.javax0.scriapt.CompileScript, which can specify a script file. The annotation processor will load the script file and execute it using the scripting interface of Java 9. This code was developed as a demonstration code by the author of this book a few years ago and is available with the Apache license from GitHub. Thus, the package of the classes is retained. The annotation processor contains two code files. One of the annotation itself that the processor will work on: @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) public @interface CompileScript { String value(); String engine() default ""; } As you can see, this annotation will not get into the class file after compilation; thus, there will be no trace during runtime so that any class source may occasionally use this annotation. Target of the annotation is ElementType.TYPE, meaning that this annotation can only be applied to those Java 9 language constructs that are some kind of types: class, interface, and enum. The annotation has two parameters. The value should specify the name of the script file, and the engine may optionally define the type of the script that is in that file. The implementation we'll create will try to identify the type of the script from the filename extension, but if somebody would like to bury some Groovy code into a file that has the .jy extension (which is usually for Jython), so be it. The processor extends AbstractProcessor and, in this way, some of the methods are inherited at the expense of some annotations used in the class: package com.javax0.scriapt; import ... @SupportedAnnotationTypes("com.javax0.scriapt.CompileScript") @SupportedSourceVersion(SourceVersion.RELEASE_9) public class Processor extends AbstractProcessor { There is no need to implement the getSupportedAnnotationTypes and getSupportedSourceVersion methods. These are replaced by the use of the annotations on the class. We support only one annotation in this processor, the one that we defined in the previously listed source file, and we are prepared to manage the source code up to Java version 9. The only method we have to override is process: @Override public boolean process( final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) { for (final Element rootElement : roundEnv.getRootElements()) { try { processClass(rootElement); } catch (Exception e) { throw new RuntimeException(e); } } return false; } This method gets two arguments. The first is the set of annotations that it was invoked for. The second is the round environment. Because the processor can be invoked many times, the different invocations may have different environments. Each invocation is in a round and the RoundEnvironment argument is an object that can be used to get information about the given round. It can be used to get the root elements of the round for which this annotation is invoked. In our case, this will be a set of class elements that have the CompileScript annotation. We iterate over this set, and for each class, we invoke the processClass method (see the next code snippet). The method may throw some checked exception and the method process cannot because it should match the same method of the interface. Thus, we catch any exception that may be thrown and we re-throw these encapsulated in RunTimeException. If any of these exceptions are thrown by the called method, then the compilation could not run the scripts and it should be treated as failed. The compilation should not succeed in such a case: private void processClass(final Element element) throws ScriptException, FileNotFoundException { for (final AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { processAnnotation(annotationMirror); } } The actual annotation is not available during compile time as we already mentioned. Hence, what we have available is only a compile time mirror image of the annotation. It has the AnnotationMirror type, which can be used to get the actual type of the annotation and, also, the values of the annotation. The type of the annotation is available during compile time. The compiler needs it; otherwise, it could not compile the annotation. The values are available from the annotation itself. Our processAnnotation method handles each annotation it gets as an argument: private void processAnnotation( final AnnotationMirror annotationMirror) throws ScriptException, FileNotFoundException { final String script = FromThe.annotation(annotationMirror). getStringValue(); final String engine = FromThe.annotation(annotationMirror). getStringValue("engine"); execute(script, engine); } Our @CompileScript annotation defines two parameters. The first value is the script filename and the second one is the scripting engine name. If the second one is not specified, then an empty string is set as the default value. The execute method is called for each and every occasion of the annotation: private void execute(final String scriptFileName, final String engineName) throws ScriptException, FileNotFoundException { final ScriptEngineManager factory = new ScriptEngineManager(); final ScriptEngine engine; if (engineName != null && engineName.length() > 0) { engine = factory.getEngineByName(engineName); } else { engine = factory.getEngineByExtension (getExtensionFrom(scriptFileName)); } Reader scriptFileReader = new FileReader (new File(scriptFileName)); engine.eval(scriptFileReader); } The method tries to load the script, based on the filename, and tries to instantiate the script engine, based on the given name. If there is no name given, then the filename extension is used to identify the scripting engine. By default, the JavaScript engine is on the classpath as it is part of the JDK. If any other JVMbased scripting engine is in use, then it has to be made available on the classpath or on the module path. The last method of the class is a simple script manipulation method, nothing special. It just chops off the filename extension so that the engine can be identified based on the extension string: private String getExtensionFrom(final String scriptFileName) { final int indexOfExtension = scriptFileName.lastIndexOf('.'); if (indexOfExtension == -1) { return ""; } else { return scriptFileName.substring(indexOfExtension + 1); } } And just for the sake of completeness, we have the closing brace of the class: } Programming in the enterprise When a professional works for an enterprise, she does not work alone. There are a lot of people, developers as well as other coworkers, we have to cooperate with. The older the IT department of the enterprise is, and the larger the enterprise is, the more specialized roles people are in. You will certainly meet business analysts, project managers, test engineers, build engineers, subject-matter experts, testers, architects, scrum masters, and automation engineers, to name a few roles. Some of these roles may overlap, no person may have more than one responsibility, and while in other cases, some roles could even be more specialized. Some of the roles are very technical and require less business-related knowledge; others are more business oriented. Working together as a team with so many people and with so many different roles is not simple. The complexity of the task may be overwhelming for a novice developer and cannot be done without definite policies that all members of the operation follow, more or less. Perhaps your experience will show that it is more times less than more, but that is a different story. For the way developers work together, there are well-established industry practices. These support the Software Development Lifecycle (SDLC) using waterfall, agile, or a mix of the two models in some way. In the following sections, we will look at tools and techniques that are, or at least should have been, used in every software development organization. These are: Static code analysis tools that control the quality of the code examining the source code Source code version control that stores all the versions of the source code and help get the source code for any old version of the development Software versioning to keep some order of how we identify the different versions and do not get lost among the different versions Code review and tools that help in pin-pointing bugs that are not revealed by tests and aid knowledge sharing Knowledge base tools to record and document the findings Issue tracking tools that record bugs, customer issues, and other tasks that somebody has to attend to Selection process and considerations for external products and libraries Continuous integration that keeps the software in a consistent state and reports immediately if there is some error in it before the error propagates to other versions or other code, depending on how the erroneous code gets developed Release management, which keeps track of the different release versions of the software Code repository, which stores the compiled and packed artifacts The following diagram shows the most widely used tools for these tasks: Static code analysis Static code analysis tools read the code just like the compiler and analyze it, but instead of compilation, they try to find errors or mistakes in it. Not the syntax errors. For that, we already have the Java compiler. Mistakes, such as using a loop variable outside a loop, which may be absolutely valid but is usually bad style and, many times, such usage comes from some simple mistakes. They also check that the code follows the styling rules that we set. Static code analyzers help identify many small and obvious errors in the code. Sometimes, they are annoying, warning about something that may not be really a problem. In such a case, it is better to code the program a bit differently, not because we want the static code analysis to run without warning. We should never modify the code because of a tool. If we code something in such a way that it passes some quality check tool and not because it is better that way, then we are serving the tools instead of the tools serving us. The reason to change the code to pass the code analysis is that it is very probable that the code is more readable to an average programmer if it does not violate the coding style. You or the other team members can be excellent programmers who understand the code very easily even if it uses some special construct. However, you cannot say that about all the programmers who will maintain your code in the future. The code lives a long life. I work with some programs that have been written 50 years ago. They are still running and maintained by young professionals around the age of 30. It means that they were not even born when the code was developed. It can easily happen that the person maintaining your code is not even born by the time you write the code. You cannot tell anything about their cleverness and coding practices. The best we can do is to prepare for the average and that is exactly what static code analysis tools are set for. The checks that these tools perform are not hardwired into the tools. Some special language inside the tools describes the rules and they can be deleted, other rules can be added, and rules can be modified. This way, you can accommodate the coding standards of the enterprise you work for. The different rules can be categorized as cosmetic, minor, major, and critical. Cosmetic things are mainly warnings and we do not really care about them, even though it is nice to fix even these issues. Sometimes, these small things may signal some really big issue. We can set limits for the number of minor and major bugs before the check is declared as failing and also for the critical errors. In the last case, this limit is usually zero. If a coding error seems to be critical, then better not have any in the code. The most frequently used tools are Checkstyle, FindBugs, and PMD. The execution of these tools is usually automated, and though they can be executed from the IDE or from the developer's command line, their main use is on the continuous integration (CI) server. During the build, these tools are configured on the CI server to run, and it can be configured such that the build should be broken if the static code analysis fails with some limit. Executing the static code analysis is usually the next step after compilation and unit test execution, and before the actual packaging. The SonarQube tool (https://www.sonarqube.org/) is a special tool in addition to being a static code analysis tool. SonarQube maintains the history of the previous checks as well as supports unit test code coverage and can report the change of the quality over time. This way, you can see how the quality, coverage percentage, and number of different qualifications of code style errors have changed. Many times, you can see that when approaching the release date, the code quality decreases as people are in a rush. This is very bad because this is the time when most of the bugs should be eliminated. Having a statistic about the quality may help change the practice by seeing the trends before the quality, and thus the maintainability of the code gets out of hand. Source code version control Source code version control systems store different versions of the source code. These days, we cannot imagine professional software development without it. This was not always the case, but the availability of free online repositories encouraged hobby developers to use some version control, and when these developers worked for enterprises later, it was evident that the use of these systems is kind of a must. There are many different revision control systems. The most widely used one is Git. The version control that was previously widely used was SVN and, even before that, CVS. These are less and less used these days. We can see SVN as a successor of CVS and Git as a successor of SVN. In addition to these, there are other version control systems such as Mercurial, Bazaar, or Visual Studio Team Services. For a comprehensive list of the available tools, visit the Wikipedia page at https://en.wikipedia.org/wiki/List_of_version_con trol_software. My bet is that you will meet Git in the first place and there is a high probability of you coming across SVN when programming for an enterprise. Mercury may appear in your practice but any of the others that currently exist are very rare, are used for a specific area, or are simply extinct. Version control systems allow the development team to store the different versions of the software in an organized manner on a storage that is maintained (backed up regularly in a reliable manner). This is important for different purposes. The first thing is that different versions of the software may be deployed to different instances. If we develop software for clients and we have many clients with whom we hope to have to make a terrific business, then different clients may have different versions. This is not only because some clients are reluctant to pay for the upgrade, and we just do not want to give the new version for free. Many times, the costs that rise on the side of the customer prevent the upgrade for a long time. Software products do not work on their own in an isolated environment. Different clients have different integrated environments; the software communicates with different other applications. When a new version is to be introduced in an enterprise environment, it has to be tested for whether it works with all the systems it has to cooperate with. This testing takes a lot of effort and money. If the new features or other values that the new version delivers over the old one do not justify the cost, then it would be waste of money to deploy the new version. The fact that there is a new version of our software does not mean that the old versions are not usable. If there is some bug at the customer's end, then it is vital that we fix the bug in that version. To do so, the bug has to be reproduced in the development environment, which eventually means that the source code for that version has to be available for the developers. This does require the customer database to contain references to the different versions of our software products that are installed at the customer site. To make it more complicated, a customer may have more than one version at a time in different systems and may also have different licenses, so the issue is more complex than it first seems. If we do not know which version the client has, then we are in trouble. Since the database registering the versions for the customers and real life may get unsynchronized, software products log their version at startup. We have a separate section about versioning in this chapter. If the bug is fixed in the version that the client has, the incident at the customer's end may be solved after deployment. The problem, though, still remains if the version is not the previous version of the software. The bug fix introduced to an old version of the software may still be lurking around in the later or, for that matter, earlier versions. The development team has to identify which versions are relevant to clients. For example, an old version that is not installed any more at any of the clients' sites does not deserve the investigation. After that, the relevant versions have to be investigated to check whether they exhibit the bug. This can only be done if we have the source version. Some old versions may not have the bug if the code causing the bug is introduced in later versions. Some new versions may also be immune to the bug because the bug was already fixed in the previous version, or simply because the piece of code that caused the bug was refactored even before the bug manifested. Some bugs may even affect a specific version instead of a range of products. Big fixing may be applied to different versions and they may need slightly different fixes. All this needs a maintained source version repository. Even when we do not have different customers with different versions, it is more than likely that we have more than one version of our software in development. The development of a major release is coming to an end, and therefore, one part of the team responsible for testing and bug fixing focuses on those activities. At the same time, the development of features for the next version still goes on. The code implementing the functionalities for the next version should not get into the version that is about to be released. The new code may be very fresh, untested, and may introduce new bugs. It is very common to introduce freeze times during the release process. For example, it may be forbidden to implement any new feature of the upcoming release. This is called feature freeze. Revision control systems deal with these freeze periods, maintaining different branches of the code. The release will be maintained in one branch and the version for later releases in a different one. When the release goes out, the bug fixes that were applied to it should also be propagated to the newer version; otherwise, it might so happen that the next version will contain bugs that were already fixed in the previous version. To do so, the release branch is merged with the ongoing one. Thus, version control systems maintain a graph of the versions, where each version of the code is a node in the graph and the changes are vertices. Git goes very far in this direction. It supports branch creation and merging so well that developers create separate branches for each change that they create and then they merge it back with the master branch when the feature development is done. This also makes for a good opportunity for code review. The developer making the feature development or bug fix creates a pull request in the GitHub application, and another developer is requested to review the change and perform the pull. This is a kind of four-eyed principle applied to code development. Some of the revision control systems keep the repository on a server and any change gets to the server. The advantage of this is that any change committed gets to a server disk that is regularly backed up and is thus safe. Since the server-side access is controlled, any code sent to the server cannot be rolled back without trace. All versions, even the wrong versions, are stored on the server. This may be required by some legal control. On the other hand, if commit requires network access and server interaction, it may be slow and this will, in the long run, motivate developers not to commit their changes frequently. The longer a change remains on the local machine, the more risk we have of losing some of the code, and merging becomes more and more difficult with time. To heal this situation, Git distributes the repository and the commit happens to the local repository, which is exactly the same as the remote one on some server. The repositories are synchronized when one repository pushes the changes to another one. This encourages the developers to make frequent commits to the repository, giving short commit messages, which helps in tracking the change made to the code. Some older version control systems support file locking. This way, when a developer checks out a code file, others cannot work on the same piece of code. This essentially avoids the collisions during code merging. Over the years, this approach did not seem to fit the development methodologies. Merge issues are less of a problem than files that are checked out and forgotten. SVN supports file locking but this is not really serious and does not prevent one developer to commit changes to a file that somebody else locked. It is more of only a suggestion than real locking. Source code repositories are very important but should not be confused with release repositories, which store the compiled released version of the code in binary. Source and release repositories work together. Software versioning Software versioning is magic. Think about the different versions of Windows or Star Wars movies. Well, the latter is not really software versioning but it shows that the issue is very general. In the case of Java, versioning is not that complex. First of all, the version of Java we use now is 9. The previous version was 1.8, before that 1.7, and so on, down to 1.0. Earlier versions of Java were called Oak but that is history. After all, that is, who can tell what Java 2 was? Fortunately, when we create a Java application, the situation is simpler. There has been a suggestion from Oracle, from the time of Java 1.3, about how to version JARs: http://docs.oracle.com/javase/7/docs/technotes/guides/extensions/versioning.html This document distinguishes between specification version and implementation version. If the specification of a JAR content changes, the code has to behave differently from how it was behaving till then; the specification version should change. If the specification is not changed but the implementation does--for example, when we fix a bug--then the implementation version changes. In practice, nobody has used this scheme, although it is a brilliant idea to separate the implementation and specification versions, at least, in theory. I even bet that most of your colleagues have not even ever heard about this versioning. What we use in practice is semantic versioning. Semantic versioning (http://semver.org/) mixes the specification and implementation versions into one single version number triplet. This triplet has the format of mmp, that is: m: major version number m: minor version number p: patch number The specification says that these numbers start with zero and increase by one. If the major number is zero, it means that the software is still in development. In this state, the API is not stable and may change without a new major version number. The major version number gets to 1 when the software is released. Later it has to be increased when the API of the application (library) has changed from the previous version and the application is not backward compatible with the previous version. The minor version number is increased when the change effects only the implementation but the change is significant, perhaps, even the API is also changing but in a backward-compatible manner. The patch version is increased when some bug is fixed, but the change is not major and the API does not change. The minor and the patch levels have to be reset to zero if any version number in the triplet in front of any of them is increased: major version number increase resets both minor and patch version; minor version number increase resets patch number. This way, semantic versioning keeps the first element of the triplet for the specification version. The minor is a mix of the specification and implementation versions. A patch version change is clearly an implementation version change. In addition to these, semantic versioning allows appending a pre-release string, such as -RC1 and -RC2. It also allows the appending of metadata, such as a date after a plus sign, for example, +20160120 as a date. The use of semantic versioning helps those that use the software to easily spot compatible versions and to see which version is older and which is newer. Code review When we create programs in a professional way, it is done in teams. There is no one-man show programming other than in a hobby or going along with the tutorials. It is not only because it is more effective to work in teams but also because one person is vulnerable. If you work alone and get hit by the bus or you hit the lottery and lose your ability or motivation to work on the project, your customer is in trouble. That is not professional. Professional projects should be resilient to any member falling off. Teamwork needs cooperation and one form of cooperation is code review. This is the process when a developer or a group of developers reads a part of the code that some other team members have written. There are direct gains from this activity; The developers reading the code get more knowledge about the code; they learn the code. This way, if the developer creating the code gets out of the process for any reason, the others can continue the work with minimal bump. Coding styles can be aligned. Developers, even seniors, paying careful attention make coding mistakes. This may be a bug or it may be a coding style violation. Coding style is important because the more readable the code is, the less possibility of it having unnoticed bugs. (Also see the next bullet point.) It is also important that the coding style is the same for the team. All team members should use the same style. Looking at a code that has a different style from the one I wrote is a bit harder to follow and understand. The differences may distract the reader and the team members have to be able to read the code. The code belongs to the team and not a single developer. Any team member should know the code and be able to modify it. During code review, a lot of bugs can be discovered. The parties looking at the code and trying to understand the working of it may occasionally discover bugs from the structure of the code, which are otherwise hard to discover using tests. If you want, code review is the whitest white box test. People think differently and different mindsets catch different bugs. Code review can be done online and offline. It can be done in teams or peer-to-peer. Most teams follow the code review process that GitHub supports, which is the simplest. Changes to the code are committed to a branch and are not merged with the code directly but, rather, a pull request is created on the web interface. The local policy may require that a different developer perform the pull. The web interface will highlight the changes and we can add comments to the changed code. If the comments are significant, then the original developer requesting the pull should modify the code to answer the comments and request the pull again. This ensures that at least two developers see any change; the knowledge is shared. Feedback is peer-to-peer. It is not a senior teaching a junior. That needs a different channel. Comments in GitHub are not good for this purpose; at least, there are better channels. Perhaps talking face to face. Comments may come from a senior to a junior or from a junior to a senior. In this work, giving feedback on the quality of the code, seniors and juniors, are equal. The simplest and perhaps the most frequent comment is the following: I can see that Xyz.java was changed in the modification but I see no change made to XyzTest.java. This is almost an instant refusal for the merge. If a new feature is developed, unit tests have to be created to test that feature. If a bug is fixed, then unit tests have to be created to prevent the bug from coming back. I personally got this comment many times, even from juniors. One of them told me, "We know that you were testing us if we dared to give feedback." God knows I was not. They did not believe. While change review and GitHub is a good tool during development, it may not be appropriate when a larger chunk of code has to be reviewed. In such a case, other tools, such as FishEye, have to be used. In this tool, we can select the source files for review even if they were not recently changed. We can also select reviewers and deadlines. Commenting is similar to GitHub. Finally, this type of code review finishes with a code review session, where the developers gather and discuss the code in person. While organizing such a session, it is important that a person who has experience managing other people mediates these sessions. Code and discussion on styles can get very personal. At the same time, when attending such a meeting, you should also pay attention so as not to get personal. There will be enough participants who may not know this or are less disciplined. Never attend a review session without reviewing the code first using the online tools. When you make comments, the language should be very polite for the reason I have already mentioned. Finally, the mediator of the meeting should be able to separate important and not so important issues and to stop debate on bagatelle things. Somehow, the less important issues are more sensitive. I personally do not care about formatting the tab size if it is two or four spaces and if the file should contain only spaces or if tab characters are allowed, but people tend to like to waste time on such issues. The most important issue during code review sessions is that we are professional and it may happen that I review and comment your code today, but tomorrow, it will be just the opposite, and we work together and we have to work together as a team. Knowledge base Knowledge base was a buzzword a few years ago. Few companies were evangelizing the idea of wiki technology and nobody was using it. Today, the landscape of knowledge base is totally different. All enterprises use some kind of wiki implementation that is there to share knowledge. They mostly use Confluence, but there are also other wiki solutions available, commercial and free as well. Knowledge bases store information that you, as a developer, would write down in a paper notebook for your later reference, for example, the IP address of the development server, directories where to install the JAR files, what commands to use, what libraries you have collected, and why you use them. The major difference is that you write it in a formatted way into a wiki and it is available immediately for other developers. It is a bit of a burden on the developer to write these pages, and it needs some selfdiscipline first. Sticking to the example of the IP address of the development server and the install directories, you have to write not only the IP address of the server but also some text explaining what the information is, because the others may not understand it otherwise. It is also a bit of work to place the page with the information in the wiki system with a good name, linking it to other pages, or finding the appropriate position of the page in the tree of pages. If you were using the paper notebook, you could just write down the IP address and the directories on the first free page of the book and you would just remember all others. The wiki approach will pay back when coworkers do not need to find the information themselves; you can find the information in an easier way because other coworkers have also recorded their findings in the knowledge base and, last but not least, a few months later, you find the information you recorded yourself. In the case of a paper notebook, you would turn the pages to find the IP address and you may or may not remember which one is the primary and which is the secondary server. You may even forget by then that there are two servers (or was it a double cluster?). To have a long list of available wiki software, visit https://en.wikipedia.org/wiki/Comparison_of_wiki_software. Issue tracking Issue tracking systems keep track of issues, bugs, and other tasks. The first issue tracking systems were created to maintain the list of bugs and also the state of the bug fixing process to ensure that a bug, identified and recorded, will not get forgotten. Later, these software solutions developed and became fullfledged issue trackers and are unavoidable project management tools in every enterprise. The most widely used issue tracking application used in many enterprises is Jira, but on the https://en.wikipedia .org/wiki/Comparison_of_issue-tracking_systems page, you can find many other applications listed. The most important feature of an issue tracker application is that it has to record an issue in detail in an editable manner. It has to record the person who recorded the issue in case more information is needed during issue handling. The source of the issue is important. Similarly, issues have to be assigned to some responsible person, who is accountable for the progress of issue handling. Modern issue tracking systems provide complex access control, workflow management, relation management, and integration with other systems. Access control will only allow the person who has something to do with an issue access to it, so others cannot alter the state of an issue or even read the information attached to it. An issue may go through different workflow steps depending on the type of issue: a bug may be reported or reproduced, a root cause analyzed, a fix developed or tested, a patch created, a fix merged with the next release version or published in the release. This is a simple workflow with a few states. Relation management allows setting different relations between issues and allowing the user to navigate from issue to issue along these relations. For example, a client reports a bug, and the bug is identified as being the same as another already fixed. In such a case, it would be insane to go through the original workflow and creating a new patch for the same bug. Instead, the issue gets a relation pointing to the original issue and sets the state to be closed. Integration with other systems is also useful to keep a consistent development state. Version control may require that, for every commit, the commit message contains a reference to the issue that describes the requirement, bug, or change that the code modification supports. Issues may be linked to knowledge base articles or agile project management software tools using web links. Testing We have already discussed testing when we talked about unit testing. Unit testing is extremely important in agile development and it helps keep the code clean and reduce the number of errors. But this is not the only type of testing that you will see in enterprise development. Types of tests Testing is performed for many reasons but there are at least two reasons that we have to mention. One is to hunt the bugs and create error-free code as much as possible. The other is to prove that the application is usable and can be utilized for the purpose it was meant for. It is important from the enterprise point of view and considers a lot of aspects that unit test does not. While unit test focuses on one unit and, thus, is an extremely good tool to point out where the error is, it is totally unusable when it comes to discovering bugs that come from erroneous interfaces between modules. The unit tests mock external modules and, thus, test that the unit works as expected. However, if there is an error in this expectation and the other modules do not behave in the same way as the unit test mock, the error will not be discovered. To discover the errors on this level, which is the next level above unit test, we have to use integration tests. During integration tests, we test how individual units can work together. When we program in Java, the units are usually classes; thus, the integration test will test how the different classes work together. While there is a consensus (more or less) about what a unit test is in Java programming, this is less so in the case of integration tests. In this regard, the external dependencies, such as other modules reachable via the network or database layers may be mocked, or may be set up using some test instance during integration testing. The argument is not about whether these parts should be mocked or not, only the terminology. Mocking some components such as the database has advantages as well as drawbacks. As in the case of any mock, the drawback is the cost of setting up the mock as well as the fact that the mock behaves differently from the real system. Such a difference may result in some bugs still remaining in the system and lurking there until a later case of testing or, God forgive, production is used. Integration tests are usually automated in a way similar to unit tests. However, they usually require more time to execute. This is the reason why these tests are not executed at each source code change. Usually, a separate maven or Gradle project is created that has a dependency on the application JAR and contains only integration test code. This project is usually compiled and executed daily. It may happen that daily execution is not frequent enough to discover the integration issues in a timely manner, but a more frequent execution of the integration tests is still not feasible. In such a case, a subset of the integration test cases is executed more frequently, for example, every hour. This type of testing is called smoke testing. The following diagram shows the position of the different testing types: When the application is tested in a fully set up environment, the testing is called system testing. Such testing should discover all the integration bugs that may have been lurking and covered during the previous testing phases. The different type of system tests can also discover non-functional issues. Both functional testing and performance testing are done on this level. Functional testing checks the functions of the application. It ensures that the application functions as expected or at least has functions that are worth installing in the production environment and can lead to cost saving or profit increase. In real life, programs almost never deliver all the functions that were envisioned in any requirement documentation, but if the program is usable in a sane manner, it is worth installing it, assuming that there are no security issues or other issues. In case there are a lot of functions in the application, functional testing may cost a lot. In such a case, some companies perform a sanity test. This test does not check the full functionality of the application, only a subset to ensure that the application reaches a minimal quality requirement and it is worth spending the money on the functional testing. There may be some test cases that are not envisioned when the application was designed and thus there is no test case in the functional test plan. It may be some weird user action, a user pressing a button on the screen when nobody thought it was possible. Users, even if benevolent, happen to press or touch anything and enter all possible unrealistic inputs into a system. Ad-hoc testing tries to amend this shortage. A tester during ad-hoc testing tries all the possible ways of use of the application that he or she can imagine at the moment the test is executed. This is also related to security testing, also called penetration testing when the vulnerabilities of the system are discovered. These are special types of tests that are performed by professionals who have their core area of expertise in security. Developers usually do not have that expertise, but at least, the developers should be able to discuss issues that are discovered during such a test and amend the program to fix the security holes. This is extremely important in the case of Internet applications. Performance testing checks that the application, in a reasonable environment, can handle the expected load that the user puts on the system. A load test emulates the users who attack the system and measures the response times. If the response time is appropriate, that is, lower than the required maximum under the maximum load, then the test passes; otherwise, it fails. If a load test fails, it is not necessarily a software error. It may so happen that the application needs more or faster hardware. Load tests usually test the functionality of the application in only a limited way and only test use scenarios that pose read load on the application. Many years ago, we were testing a web application that had to have a response time of 2 seconds. The load test was very simple: issue GET requests so that there are a maximum of 10,000 requests active at the same time. We started with 10 clients, and then a script was increasing the concurrent users to 100, then 1,000, and then stepping up by thousand every minute. This way, the load test was 12 minutes long. The script printed the average response time, and we were ready to execute the load test at 4:40 pm on a Friday. The average response time started from a few milliseconds and went up to 1.9 seconds as the load was increased to 5,000 concurrent users, and from there, it was descending down to 1 second as the load was increased to 10,000 users. You can understand the attitude of the people on a Friday afternoon, being happy that we met the requirements. My colleagues left for the weekend happily. I remained testing a bit more because I was bothered by the phenomenon that the response time decreases as we increase the load above 5,000. First, I reproduced the measurement and then started looking at the log files. At 7 pm, I already knew what the reason was. When the load went above 5,000, the connections the Apache server was managing started to exhaust and the web server started to send back 500 internal error codes. That is something that Apache can very effectively do. It is very fast in telling you that you cannot be served. When the load was around 10,000 concurrent users, 70% of the responses already had 500 errors. The average went down, but the users were actually not served. I reconfigured the Apache server so that it could serve all the requests and forward each to our application just to learn that the response time of our application was around 10 seconds at the maximum load. Around 10 pm, when my wife was calling my mobile the third time, I also knew how large a memory I should set in the Tomcat startup file in the options for the JVM to get the desired 2-second response time in case of 10,000 concurrent users. Stress test is also a type of performance test that you may also face. This type of test increases the load on the system until it cannot handle the load. That test should ensure that the system can recover from the extreme load automatically or manually but, in no case, will do something that it shouldn't at all. For example, a baking system should not ever commit an unconfirmed transaction, no matter how big the load there is. If the load is too high, then it should leave the dough raw but should not bake extra bread. The most important test at the top of the hierarchy is the user acceptance test. This is usually an official test that the customer, who buys the software, executes and in the case of successful execution, pays the price for the software. Thus, this is extremely important in professional development. Test automation Tests can be automated. It is not a question of whether it is possible to automatize a test, only whether it is worth doing so. Unit tests and integration tests are automated, and as time advances, more and more tests get automated as we move along to higher steps towards the user acceptance test (UAT). UAT is not likely to be automated. After all, this test checks the integration between the application and the user. While the user, as an external module, can be mocked using automation in lower levels, we should reach the level when the integration test happens without mocks. There are many tools that help the automation of tests. The blocker for test automation, these days, is the cost of the tools to do so, the cost of learning and developing the tests, and the fear that the automated tests are not discovering some of the errors. It is true that it is easier to do something wrong with a program than without. This is so true for almost anything not only for testing. And still we do use programs; why else would you read this book? Some of the errors may not be discovered during automated functional testing, which would otherwise have been discovered using manual tests. At the same time, when the same test is executed the hundredth time by the same developer, it is extremely easy to skip an error. An automated test will not ever do that. And most importantly, the cost of the automated test is not 100 times the cost of running it once. We have used test automation tools in this book. SoapUI is a tool that helps you create tests that can be executed automatically. Other testing tools that are worth looking at are Cucumber, Concordion, Fintnesse, and JBehave. There is a good comparison of tools at https://www.qatestingtools.com/. Black box versus white box You may have heard many times that a test is a black box test. This simply means that the test does not know anything about how the system under test (SUT) is implemented. The test relies only on the interface of the SUT that is exported for the outside world. A white box test, on the other end of the scale, tests the internal working of the SUT and very much relies on the implementation: Both the approaches have advantages and disadvantages. We should use one, or the mixture of the two approaches, a way that fits the purpose of the actual testing needs the most. A black box test not relying on the implementation does not need to change if the implementation changes. If the interface of the tested system changes, then the test should also be changed. A white box test may need changes if the implementation changes, even if the interface remains the same. The advantage of the white box test is that, many times, it is easier to create such a test and the testing can be more effective. To get the best of both worlds, systems are designed to be testable. Be careful, though. It means many times that the functionality internal to the tested system is propagated to the interface. That way, the test will use only the interface and, thus, can be declared to be a black box, but it does not help. If something changes in the internal working of the tested system, the test has to follow it. The only difference is that you may call it a black box test if the interface also changes. That does not save any work. Rather, it increases it: we have to check all the modules that rely on the interface if they also need any change. I do not say that we should not pay attention to creating testable systems. Many times making a system testable results in cleaner and simpler code. If the code, however, gets messier and much longer because we want to make it testable, then we are probably not going in the right way. Selecting libraries Programming for the enterprise or even programming a moderately sized project cannot be done without the use of external libraries. In the Java world, most of the libraries that we use are open source and, more or less, free to use. When we buy a library that is sold for money, there is usually a standard process enforced by the purchasing department. In such a case, there is a written policy about how to select the vendor and the library. In the case of "free" software, they do not usually care, though they should. In such a case, the selection process mainly lies with the IT department and it is therefore important to know the major points to be considered before selecting a library even if for free. In the previous paragraph, I put the word free between quotes. That is because there is no software, which is free. There is no such thing as a free lunch, as they say. You have heard this many times but it may not be obvious in the case of an open source code library or framework you are going to select. The major selection factor for any purchase or implementation is the cost, the price. If the software is free, it means that you do not need to pay an upfront fee for the software. However, there is a cost in integrating it and using it. Support costs money. Somebody may say that the support is community support and also available free of charge. The thing is that the time you spend hunting for a workaround that helps you to get over a bug is still money. It is your time, or in case you are a manager, it is the time of the professional in your department whose time you pay for, or, as a matter of fact, it can be an external contractor who will hand you a huge bill in case you do not have the expertise in-house to solve the issue. Since free software does not have a price tag attached, we have to look at the other factors that are important in the selection process. At the end of the day, they all will affect the cost in some way. Sometimes, the way a criterion alters the cost is not obvious or easily calculable. However, for each one, we can set no-go levels that are based on technology decisions, and we can compare libraries for being better or worse along with each of the criteria. Fit for the purpose Perhaps, this is the most important factor. Other factors may be argued about in terms of the scale of importance, but if a library is not appropriate for the purpose we want to use, then this is certainly not something to select, no matter what. It may be obvious in many cases, but you may be surprised how many times I have seen a product selected because it was the favorite of a person in some other project and the library was forced for use in the new project even though the requirements were totally different. License The license is an important question as not all free software is free for all uses. Some of the licenses allow free use for hobby projects and education but require you to purchase the software for professional, profit-oriented use. The most widely used licenses and their explanation (and the whole text of the license) is available on the web page of the Open Source Initiative (https://opensource.org/licenses). It lists nine different licenses, and to make the situation a bit more complex, these licenses have versions. One of the oldest licenses is the General Public License (GPL) standing for GNU. This license contains the following sentences: For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. If you create software for a for-profit enterprise and the company intends to sell software, you probably cannot use any line of code that is from a GPL-licensed software. It would imply that you are required to pass on your own source code, which may not be the best sales strategy. Apache license, on the other hand, may be okay for your company. This is something that the lawyers should decide. Even though this is the lawyers' work, there is one important point that we developers must be aware of and pay close attention to. Sometimes, the libraries contain code from other projects and their license, as advertised, may not be the real one. A library may be distributed under the Apache license but contains code that is GPL-licensed. This is obviously a violation of the GPL license, which was committed by some open source developers. Why would you care? Here comes the explanation via an imagined situation. You develop software for an enterprise. Let's say that this company is one of the largest car manufacturers of the world, or it is one of the largest banks, pharma, whatever. The owner of the GPL software seeks remedies for the misuse of her software. Will she sue the software developer, John Doe, who has a total wealth of 200K, or your company, claiming that you did not duly check the license of the code? She certainly will not dig for gold where there is none. Suing the company you work for may not be successful, but certainly not a good process you or anyone at the company wants. What can we as software professionals do? We have to use libraries that are well known, used widely. We can check the source code of the library to see whether there is some copied code. Some package names may present some clue. You can Google some part of the source code to find matches. Last but not least, the company can subscribe to services that provide similar research for the libraries. Documentation Documentation is an important aspect. If the documentation is not appropriate, it will be hard to learn how to use the library. Some of the team members may have already known the library, but, again, this may not be the case for later team members. We should consider our colleagues, who are expected to be average programmers, and they will have to learn the use of the library. Thus documentation is important. When we speak about documentation, we should not only think about the JavaDoc reference documentation but also tutorials and books if they are available. Project alive It is important not to select a library for use that is not alive. Have a look at the roadmap of the library, the last time a release was shipped, and the frequency of the commits. If the library is not alive, we should consider not using it. Libraries work in an environment and the environment changes. The library may connect to a database. The new version of the database may provide new features that give us better performance only if the library is modified to accommodate these new features. The library communicates over HTTP; will it support the new 2.0 version of the protocol? If nothing else, the version of the Java environment will change over the years and the library we use should sooner or later follow it to leverage the new features. There is no guarantee that an alive library will always stay alive. However, a library that is already dead will certainly not resurrect. Even if the project is alive at the moment, there are some points that may give some hints about the future of the library. If the company developing it is well-established and financially stable, and the library is developed with a reasonable business model, then there is a low risk that the project dies. If there are a lot of companies who use the library, then it is likely that the project will stay alive even if the original team stops working on it or the original financing structure changes. However, these are only small factors and not well-established facts. There is no guarantee, and telling the future is more an art than a science. Maturity Maturity is similar to the previous criterion. A project may very well be alive just starting up, but if it is in its infancy, we better not use the library for a large project. When a project is in its early phase, a lot of bugs can be in the code, the API may change radically, and presumably, there may only be a small number of companies relying on the code. This also means that the community support is lower. Of course, if all the projects select only mature open source code, then no open source project would ever get to the mature state. We should assess the importance of the project. Is the project business-critical? Will the project become business-critical? If the project is not business-critical, the company may afford to invent a fresh library that is not that mature. It may be reasonable if there are no mature libraries for the purpose because the technology you are going to use is relatively new. In such a case, the project in the company is probably also new and not business-critical yet. It will be business-critical, we hope, after some time, but by that time, the library will be mature, or may just die and we can select a competing solution before the project becomes too expensive to switch. Judging the maturity of a library is always difficult and has to be aligned with the maturity and importance of the project that we want to use the library for. Number of users If the library is alive and mature but there are not many users, then something is smelly. Why don't people use the library if it is good? If the number of users for a library or framework is low and there are no large corporations among the users, then it is probably not a good one. Nobody using it may signal that our assessment of the other criteria may not be appropriate. Also note that if there are only a few users of the library, then the knowledge in the community is also scarce and we may not be able to get community support. The "I like it" factor Last but not least, the I like it factor is extremely important. The question is not whether you like the library but rather how much the developers like it. Developers will like a library that is easy to use and fun to work with, and this will result in low cost. If the library is hard to use and developers do not like it, then they will not learn to use it to the level of profession required for good quality, only to the level that is just needed. The end result will be suboptimal software. Continuous integration and deployment Continuous integration means that whenever a new version is pushed to the source code repository, the continuous integration server kicks in, pulls the code to its disk, and starts the build. It compiles the code first, then runs the unit tests, fires the static code analysis tools, and, if all goes right, it packages a snapshot release and deploys it on a development server. CI servers have web interfaces that can be used to create a release. In such a case, the deployment can even go to the test servers or even to production depending on local business needs and on the policy that was created accordingly. Automating the build and deployment process has the same advantages as any other automation: repeated tasks can be performed without manual intervention, which is tedious, boring, and, thus, error-prone if done by a human. The outstanding advantage is that if there is some error in the source code that can be discovered by the automated build process, it will be discovered. Novice developers say that it is cheaper and easier to build the code locally, which the developers do anyway, and then push the code to the server if the build process is already checked. It is partly true. Developers have to check that the code is of good quality and builds well, before sending it to the central repo. However, this cannot always be achieved. Some errors may not manifest on local environments. It may so happen that one developer accidentally uses a newer version of Java than the one supported and uses a new feature of the new version. Enterprises do not generally use the latest technology. They tend to use versions that are proven, have many users, and are mature. This year, in 2017, when Java 9 is going to be released in July, huge enterprises still use Java 1.6 and 1.7. Since Java 9 has many new features that are not trivial to implement, I expect that the adoption of the technology may take even longer than the adoption of Java 1.8, which gave us functional programming and lambda. It may also happen that a new library is added to the dependencies of the build and the developer who added it to the build file (pom.xml, or build.gradle) could use it without any problem on her local machine. It does not mean that the library is officially added to the project, and it may not be available in the central code repository (Artifactory, Nexus, or other implementations of the code repository). The library may have only been on the local repository of the developer, and she may have assumed that since the code compiles, the build is OK. Some large organizations use different code repositories for different projects. The libraries get into these repositories following meticulous examination and decisions. Some libraries may get there, while others may not. The reason to have different repositories could be numerous. Some project is developed for one customer who has a different policy about an open source project than the other. If the enterprise develops code for itself, it may so happen that some library is phased out or not supported anymore, and can only be used for projects that are old. A maintenance release may not need to replace a library, but new projects may be not be allowed to use a dying software library. The CI server can run on a single machine or it can run on several machines. In case it serves many projects, it may be set up as a central server with many agents running on different machines. When some build process has to be started, the central server delegates this task to one of the agents. The agents may have different loads, running several different build processes, and may have different hardware configuration. The build process may have requirements regarding the speed of the processor or about the available memory. Some agent may run simpler builds for smaller projects but would fail to execute the build of a large project or of some small project that still has a huge memory requirement to execute some tests. When a build fails, the build server sends out e-mails to the developers, and the person who sent the last update to the code repository is obligated to fix the bug without delay. This encourages the developers to commit frequently. The smaller the change, the fewer chances there are of a build problem. The build server web interface can be used to see the actual state of the projects, which project is failing to build, and which is just fine. If a build fails, there is a red sign in the line of the build, and if the build is OK, the sign is green. Many times, these reports are continually displayed on some old machine using a huge display so that every developer or just anybody who enters the room can see the actual state of the builds. There is even special hardware that you can buy that has red, yellow, and green lamps to follow the state of the build and ring a bell when the build fails. Release management Developing software means a continuously changing code base. Not every version of the software is supposed to be installed in production. Most of the versions are pushed to the repository on a branch half complete. Some versions are meant only for testing and a few are meant to be installed in production even if only some of those will finally get to production. Almost all the time, the releases follow the semantic versioning that we discussed in an earlier section. The versions that are meant only to be tested usually have the -SNAPSHOT modifier at the end of the version number. For example, the 1.3.12-SNAPSHOT version is the version that was once debugged, and is going to become the 1.3.12 version. The snapshot versions are not definite versions. They are the code as it is by then. Because a snapshot release never gets installed in production, it is not needed to reproduce a snapshot version for maintenance. Thus, the snapshot versions are not increased continually. Sometimes, they may be changed, but that is a rare exception. It may so happen that we work on a bug fix, 1.3.12-SNAPSHOT, and during the development, we change so much code that we decide that it has to be 1.4.0 when it is released, and we rename the snapshot as 1.4.0SNAPSHOT. This is a rare case. Many times, the release creation creates a 1.4.0 version from 1.3.12-SNAPSHOT as the decision about the new release number is taken by the time the release is created. When the release process is started, usually from the web interface of the CI server, the developer creating the release has to specify the release version. This is usually the same as the snapshot version without the -SNAPSHOT postfix. The build process not only creates the build in this case but also tags the source code repository version it was using and loads the packaged program (artifact) to the code repository. The tag can be used later to access the exact version of the source code that was used to create the release. If there is a bug in a specific version, then this version has to be checked out on a developer machine to reproduce the bug and find the root cause. If the build of a release fails, it can be rolled back, or you better just skip that release number and note it as a failed release build. An existing release can never have two versions. The source code is the only one that is for that release and the generated code has to be exactly the one in any storage. Subsequent compilation of the same source may result in slightly different code, for example, if a different version of Java is used to create the latter one. Even in such a case, the one that was created by the build server in the first place is the version that belongs to the release. When a bug is reproduced and the code is recompiled from the exact same source, it is already a snapshot version. Multiple releases may be possible from the same source version, for example, compiled with Java versions from 1.5 to 1.8 and version 9 but a single release always belongs to the exact same source code. If a release that was supposed to be a release version fails during QA checks, then a new release has to be created and the failed release has to be noted as such. The version that marketing uses to name the different versions should not have a relation to the technical version numbers we work with. Many times, it is, and it causes much headache. If you realize that the two are totally different things and one does not have to do anything with the other, life gets simpler. Look at the different versioning of the Windows operating system or Java. As marketing, Java used 1.0 then 1.1, but Java 1.2 was advertised as Java 2 and still the code contained 1.2 (which now seven major releases later also becomes 9 instead of 1.9) The last part of release management is that deployments should register the version numbers. The company has to know which release is installed on which server, and of which client. Code repository Code repository stores the libraries and helps manage the dependencies of the different libraries. In the old times, when Java projects used ANT as a build tool and without the later added Ivy dependency management, the libraries that were needed by a project were downloaded to the source code, usually to the lib library. If a library needed another library, then those were also downloaded and stored manually, and this continued until all the libraries that one of the already downloaded libraries needed were copied to the source code tree. This was a lot of manual work and, also, the library code was stored in the source code repository in many copies. A compiled library is not source code and has nothing to do in the source code repository. Manual work that can be automated has to be automated. Not because developers are lazy (yes, we are and we have to be) but because manual work is error prone and, thus, expensive. This was when Apache Ivy was invented and Maven, following ANT, already supported repository management built in. They all stored the libraries structured in directories and supported metadata that described the dependencies to other libraries. Lucky that Gradle did not invent its own code repository. Instead, it supports both Maven and Ivy repositories. Using the repository, the build tools automatically download the libraries that are needed. In case a library has a new version, then the developer only has to update the version of the needed library in the build configuration and all tasks, including downloading all the new versions of the other libraries that are needed by that version, are done automatically. Walking up the ladder At this point, you have got a lot of information that will rocket your start as an enterprise Java developer. You have got a base knowledge that you can build on. There is a long way to become a professional Java developer. There is a lot of documentation to read, a lot of code to scan and understand, and also a lot of code to write till you can claim to be a professional Java developer. You may probably face many years of continuous education. The good thing is that even after that, you can continue your journey and you can educate yourself, as being a professional Java developer is rarely a job people retire from. No, no! Not because they die while at it! Rather, professional software developers gaining experience start to code less and less and support the development process in different ways, which leverages more of their experience. They can become business analysts, project managers, test engineers, subject-matter experts, architects, scrum masters, automation engineers, and so on. Is it a familiar list? Yes, these are the people you will work with as a developer. Many of them may have started as a developer themselves. The following diagram shows the relative position of these roles: Let's take a bit more detailed look into what these roles perform in enterprise development: Business analysts work with the client and create the documents, specifications, use cases, and user stories needed by the developers to develop the code. Project managers administer the projects and help the team in getting things done in cooperation with other teams, caring for all the project matters that developers cannot attend to or would unnecessarily burn their time that they should have devoted to coding. Subject-matter experts are more advanced in knowing the business needs, so it is a bit rare for a developer to become one, but in case the industry you work in is technology oriented, it may not be incredible to become one. Test engineers control the QA process and understand not only the test methodologies and requirements of testing but also the development process so that they can support bug fixes and not only identify them, which would be poor. Architects work with BAs and design a high-level structure of the applications and code, and document it in a way that helps the developers to focus on the actual tasks they have to perform. Architects are also responsible for the solution to use technologies, solutions, and structures which fit the purpose, are future proof, affordable, and so on. Scrum mates help the development team to follow the agile methodology and help the team in controlling the administration and resolving problems. There are many ways to go as a software developer and I only listed some of the positions that you can find in an enterprise today. As technology develops, I can imagine that in 20 years from today, software developers will teach and curate artificial intelligence systems and that will be what we refer to as programming today. Who can tell? Summary Going in this direction is a good choice. Being a Java developer and becoming a professional in it is a profession that will pay well in the coming 10 to 20 years for sure and perhaps even later. At the same time, I personally find this technology fascinating and interesting, and after more than 10 years of Java programming and more than 35 years of programming, I still learn something new in it every day. In this book, you learned the basics of Java programming. From time to time, I also mentioned issues, suggested directions, and warned you about pitfalls that are not Java-specific. However, we also did the homework of learning the Java language, the infrastructure, the libraries, development tools, and networking in Java. You also learned the most modern approaches that came only with Java 8 and 9, such as functional programming in Java, streams, and reactive programming. If you know all that I have written in this book, you can start working as a Java developer. What's next? Go, and find your treasure in programming and in Java!