Java 9: Building Robust Modular Applications Master advanced Java features and implement them to build amazing projects A learning path in two sections BIRMINGHAM - MUMBAI Java 9: Building Robust Modular Applications Copyright © 2018 Packt Publishing All rights reserved No part of this learning path 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 learning path to ensure the accuracy of the information presented However, the information contained in this learning path is sold without warranty, either express or implied Neither the authors, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this learning path Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this learning path by the appropriate use of capitals However, Packt Publishing cannot guarantee the accuracy of this information Authors: Dr Edward Lavieri, Peter Verhas, Jason Lee Reviewer: Mandar Jog, Dionisios Petrakopoulos Content Development Editor: Rohit Kumar Singh Graphics: Jason Monteiro Production Coordinator: ArvindKumar Gupta Published on: April 2018 Production reference: 1020418 Published by Packt Publishing Ltd Livery Place 35 Livery Street Birmingham B3 2PB, UK ISBN 978-1-78883-282-3 www.packtpub.com mapt.io Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career For more information, please visit our website Why subscribe? Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals Improve your learning with Skill Plans built especially for you Get a free eBook or video every month Mapt is fully searchable Copy and paste, print, and bookmark content 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 service@packtpub.com 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 Table of Contents Title Page - Courses Copyright and Credits - Courses Java 9: Building Robust Modular Applications Packt Upsell - Courses Why subscribe? PacktPub.com Preface Who this learning path is for What this learning path covers To get the most out of this learning path Download the example code files Conventions used Get in touch Reviews 1 Mastering Java The Java Landscape Java at 20,000 feet Breaking the monolith Playing around with the Java Shell Taking control of external processes Boosting performance with G1 Measuring performance with JMH Getting started with HTTP 2.0 Encompassing reactive programming Expanding the wish list Summary Discovering Java Improved Contended Locking [JEP 143] Improvement goals Segmented code cache [JEP 197] Memory allocation Smart Java compilation, phase two [JEP 199] Resolving Lint and Doclint warnings [JEP 212] Tiered attribution for javac [JEP 215] Annotations pipeline 2.0 [JEP 217] New version-string scheme [JEP 223] Generating run-time compiler tests automatically [JEP 233] Testing class-file attributes generated by Javac [JEP 235] Storing interned strings in CDS archives [JEP 250] The problem The solution Preparing JavaFX UI controls and CSS APIs for modularization [JEP 253] JavaFX overview Implications for Java Compact strings [JEP 254] Pre-Java status New with Java Merging selected Xerces 2.11.0 updates into JAXP [JEP 255] Updating JavaFX/Media to newer version of GStreamer [JEP 257] HarfBuzz Font-Layout Engine [JEP 258] HiDPI graphics on Windows and Linux [JEP 263] Marlin graphics renderer [JEP 265] Unicode 8.0.0 [JEP 267] New in Unicode 8.0.0 Updated Classes in Java Reserved stack areas for critical sections [JEP 270] The pre-Java situation New in Java Dynamic linking of language-defined object models [JEP 276] Proof of concept Additional tests for humongous objects in G1 [JEP 278] Improving test-failure troubleshooting [JEP 279] Environmental information Java process information Optimizing string concatenation [JEP 280] HotSpot C++ unit-test framework [JEP 281] Enabling GTK on Linux [JEP 283] New HotSpot build system [JEP 284] Summary Java Language Enhancements Working with variable handlers [JEP 193] Working with the AtoMiC Toolkit Using the sun.misc.Unsafe class Eliding depreciation warnings on import statements [JEP 211] Milling Project Coin [JEP 213] Using the @SafeVarargs annotation The try-with-resource statement Using the diamond operator Discontinuing use of the underscore Making use of private interface methods Processing import statements correctly [JEP 216] Summary Building Modular Applications with Java A modular primer Reviewing Java's platform module system [JEP-200] Modularizing JDK source code [JEP-201] Pre-Java JDK source code organization Development tools Deployment Internationalization Monitoring RMI Security Troubleshooting Web services JavaFX tools Java runtime environment Source code Libraries C header files Database JDK source code reorganized Understanding modular run-time images [JEP-220] Runtime format adoption Runtime image restructure Supporting common operations De-privileging JDK classes Preserving existing behaviors Getting to know the module system [JEP-261] Module paths Access-control boundary violations Runtime Modular Java application packaging [JEP-275] Advanced look at the Java Linker Java Packager options JLink - The Java Linker [JEP-282] Encapsulating most internal APIs [JEP-260] Summary Migrating Applications to Java Quick review of Project Jigsaw Classpath The monolithic nature of the JDK How modules fit into the Java landscape Base module Reliable configuration Strong encapsulation Migration planning Testing a simple Java application Potential migration issues The JRE Access to internal APIs Accessing internal JARs JAR URL depreciation Extension mechanism The JDK's modularization Advice from Oracle Preparatory steps Getting the JDK early access build Project Panama While not yet targeted for any particular Java release, Project Panama offers some hope for those who use, or hope to use, thirdparty, native libraries Currently, the primary way of exposing native libraries (that is, OS-specific libraries written in, say, C or C++) to the JVM is via the Java Native Interface (JNI) The problem with JNI, or at least one of them, is that it requires that every Java programmer who wants to expose a native library to the JVM also become a C programmer, which means not only the C language itself, but also the related build tools for each supported platform Project Panama hopes to ameliorate that issue by offering the Java developer a new means of exposing native libraries without needing a deep understanding of the library language's ecosystem, or the JVM's The JEP for Project Panama (http://openjdk.java.net/jeps/191) lists these design goals: A metadata system to describe native library calls (call protocol, argument list structure, argument types, return type) and the native memory structure (size, layout, typing, life cycle) Mechanisms to discover and load native libraries These capabilities may be provided by the current System.loadLibrary or may include additional enhancements for locating platform or version-specific binaries appropriate to the host system Mechanisms for binding, based on metadata, a given library/function coordinate to a Java endpoint, likely via a user-defined interface backed by plumbing to make the native downcall Mechanisms for binding, based on metadata, a specific memory structure (layout, endianness, logical types) to a Java endpoint, either via a user-defined interface or a user-defined class, in both cases backed by plumbing to manage a real block of native memory Appropriate support code to marshal Java data types to native data types and vice-versa This will, in some cases, require the creation of FFI-specific types to support bit widths and numeric signs that Java can't represent JNI has been available for quite some time, and it's finally getting some long overdue attention Project Amber Project Amber's goal is to explore and incubate smaller, productivity-oriented Java language features The current list includes local-variable type inference, enhanced enums, and lambda leftovers Local-Variable Type Inference As we have seen countless times in this book alone, when you declare a variable in Java, you have to declare the type twice, once on the left-hand and once on the right-hand side, plus a variable name: AtomicInteger atomicInt = new AtomicInteger(42); The problem here is that this code is verbose and repetitive The Local-Variable Type Inference effort hopes to fix that, enabling something like this: var atomicInt = new AtomicInteger(42); This code is more concise, making it more readable Notice the addition of the val keyword Typically, the compiler knows that a line of code, for example, is a variable declaration when it sees = Since the effort would remove the need for a type on the left-hand side of the declaration, we need a cue for the compiler, which the authors of this JEP propose as var There is also some discussion around simplifying the declaration of immutable, or final, variables Among the proposals are final var as well as val, as seen in other languages such as Scala At the time of writing, no decision that has been made on which proposal will make the final cut Enhanced enums Enhanced enums will augment the expressiveness of the enum construct in the Java Language by allowing type-variables in enums (generic enums), and performing sharper type-checking for enum constants (http://openjdk.java.net/jeps/301) What this means is that enums will finally support a parameterized type, allowing something like this (taken from the JEP at the link mentioned previously): enum Primitive { INT(Integer.class, 0) { int mod(int x, int y) { return x % y; } int add(int x, int y) { return x + y; } }, FLOAT(Float.class, 0f) { long add(long x, long y) { return x + y; } }, ; final Class boxClass; final X defaultValue; Primitive(Class boxClass, X defaultValue) { this.boxClass = boxClass; this.defaultValue = defaultValue; } } Note that, in addition to specifying a generic type for each enum value, we can also define type-specific methods for each enum type This will make it much easier to define a set of predefined constants, but also to define type-safe and type-aware methods for each of the constants Lambda leftovers There are currently two items labeled as leftovers from the lambda work in Java The first is the use of the underscore for unused parameters in lambda declarations For example, in this very contrived example, all we care about are the Map values: Map numbers = new HashMap(); numbers.forEach((k, v) -> System.out.println(v*2)); That results in things like this in the IDE: Once the use of the underscore is allowed, this code will look like this: numbers.forEach((_, v) -> System.out.println(v*2)); This allows better static checking of unused variables, allowing tools (and developers) to more easily identify such parameters and either correct or mark them The other leftover is allowing lambda parameters to shadow variables from the enclosing scope If you were to try that now, you would get the same error if you tried to redefine a variable inside a statement block variable is already defined: Map numbers = new HashMap(); String key = someMethod(); numbers.forEach((key, value) -> System.out.println(value*2)); // error With this change, the preceding code would compile and run just fine Looking around The JVM has supported alternative languages for years Some of the better known ones include Groovy and Scala Both of these languages have influenced Java in one way or another over the years, but, like any language, they are not without their problems Many feel that Groovy doesn't perform as well as Java (though the invokedynamic bytecode instruction is supposed to have addressed that), and many find Groovy's more dynamic nature less appealing Scala, on the other hand, suffers (fairly or not, depending on who you ask) from the perception that it's too complex Compilation time is also a common complaint Also, many organizations are quite happily using both, so they are definitely worth considering to see if they will work in your environment and for your needs While those may be great languages, we are taking some time here to see what's next, and there are at least two languages that seem to stand out from the crowd Ceylon and Kotlin We can't give each of these languages an exhaustive treatment, but, over the next few pages, we'll take a quick look at the languages to see what they offer JVM developers now, and, perhaps, see how they might influence future changes to the Java language Ceylon Ceylon, a language sponsored by Red Hat, first appeared around 2011 Led by Gavin King of the Hibernate and Seam Framework fame, the team set out to solve, at a language and library level, some of the pain points they had experienced over the years in developing their own frameworks and libraries While they confess to being unapologetic fans of the Java language, they also readily acknowledge that the language is not perfect, especially with regard to some of the standard libraries, and aim to fix those flaws in Ceylon The goals of the language include readability, predictability, toolability, modularity, and metaprogrammability (https://ceylon-lang.org/blog/2012/01/10/goals) One of the biggest differences you are likely to notice when getting started with Ceylon is that the idea of modules is already baked into the language In many ways, it looks very similar to Java 9's module declaration, which is as follows: module com.example.foo "1.0" { import com.example.bar "2.1"; } There is, however, a very obvious difference Ceylon modules have version information, which allows various modules to depend on different versions of a module that may already be in the system There is at least one more rather significant difference between Ceylon and, say, Java Ceylon has a build tool built in While there is, for example, a Maven plugin, the preferred approach is to use Ceylon's native tooling to build and run the project: $ ceylonb new hello-world Enter project folder name [helloworld]: ceylon-helloworld Enter module name [com.example.helloworld]: Enter module version [1.0.0]: Would you like to generate Eclipse project files? (y/n) [y]: n Would you like to generate an ant build.xml? (y/n) [y]: n $ cd ceylon-helloworld $ ceylonb compile Note: Created module com.example.helloworld/1.0.0 $ ceylonb run com.example.helloworld/1.0.0 Hello, World! Other than the module system, what might Ceylon offer a Java developer? One of the more immediately useful and practical features is improved null-handling support Just as we have to in Java, we still have to check for null in Ceylon, but the language offers a much nicer approach, and it all starts with the type system One of the complaints about Scala (whether its truly warranted or not) is that the type system is too complicated Regardless of whether or not you agree, it seems clear that there's certainly room for improvement over what Java offers (even the Java language architects agree as evidenced by, for example, the proposed local variable type inference proposal) Ceylon offers a very powerful addition to the type system union types and intersection types Union types allow a variable to have more than one type, but only one at a time Where this comes into play in discussing nulls is that String? foo = , which declares a variable of type String that is nullable, is actually the same as String|Null foo = This declares a variable, foo, whose type is either String or Null, but not both The ? syntax is just syntactic sugar over the union type declaration (A | B or A or B) If we have a method, then that takes this union type; we know that the variable is nullable, so we need to check it using the following code snippet: void bar (String? Foo) { if (exists foo) { print (foo); } } Since this is a union type, we can also this: void bar (String? Foo) { if (is String foo) { print (foo); } } Note that, once we've tested with exists or is, we can assume that the variable is not null and is a String The compiler won't complain, and we won't have an unexpected NullPointerException at runtime (they actually don't exist in Ceylon as the compiler requires that you be very explicit in your handling of nullable variables) This type of compiler awareness of null and type checks is called flowsensitive typing Once you've verified the type of something, the compiler knows and remembers, so to speak, the results of that check for that remainder of that scope so you can write cleaner, more concise code While union types are either A or B, intersection types are A and B For a completely arbitrary example, let's say you have a method whose parameter must be, say, Serializable and Closeable In Java, you'd have to check manually by writing the following lines of code: public void someMethod (Object object) { if (!(object instanceof Serializable) || !(object instanceof Closeable)) { // throw Exception } } With intersection types, Ceylon would let us write this: void someMethod(Serializable&Closeable object) { // } If we try to call that method with something that doesn't implement both interfaces, or, say, extends one class and implements the other interfaces, then we get an error at compile time That's very powerful Before adopting a new language, or even a library, in an enterprise, one often looks to see who else is using it Are there notable adoption stories? Are there other companies confident enough in the technology to build a production system using it? Unfortunately, the Ceylon website (at the time of writing) is very thin on the details of adoption outside Red Hat, so it's hard to answer that question However, Red Hat is spending a good deal of money designing the language and building tooling and a community around it, so it should be a safe bet It is, of course, a decision your enterprise will have to make after careful consideration You can find out more about Ceylon at https://ceylonlang.org Kotlin Another up-and-coming language is Kotlin It is a statically-typed language from JetBrains, the makers of IntelliJ IDEA, that targets both the JVM and Javascript It even has nascent support to compile directly to machine code via LLVM for those environments, such as iOS, embedded systems, and so on, where a virtual machine is not desired or allowed Kotlin was started in 2010, and open sourced in 2012, as a means to address some common issues JetBrains was facing in large-scale Java development Having surveyed the then-current language landscape, their engineers felt that none of those languages adequately addressed their concerns Scala, considered for years now by many to be the next Java, was, for example, deemed to be too slow in compiling, despite having an acceptable feature set, so JetBrains began designing their own, eventually releasing 1.0 in February of 2016 The design goals of the Kotlin team include expressiveness, scalability, and interoperability They aim to allow developers to write less code that does more in a clearer fashion via language and library features, and in a language that is 100% interoperable with Java They have added features such as coroutines to enable Kotlinbased systems to scale quickly and easily With all of that said, what does Kotlin look like and why should we, as Java developers, be interested? Let's start with variables As you'll recall, Java has both primitive (int, double, float, char, and so on) and reference, or wrapper types (Integer, Double, Float, String, and so on) As we've discussed in this chapter, the JVM engineers are working on ways to ameliorate some of the behavioral and capability differences this dichotomy brings Kotlin avoids this altogether, as every value is an object, so there's no concern over List versus List Furthermore, Kotlin already supports local variable type inference, as well as immutablity For example, consider the following Java code as an example: Integer a = new Integer(1); final String s = "This is a string literal"; The preceding lines of code could be written like this in Kotlin: var a = 1; val s = "This is a string literal"; Notice the use of the var and val keywords As discussed earlier with regard to future Java language changes, these keywords allow us to declare mutable and immutable variables (respectively) Also notice that we need not declare the type of the variable, as the compiler handles that for us In certain situations, we may need to explicitly declare the type, for example, in situations where the compiler might guess incorrectly or when it just does not have enough information to make a guess, at which point, it will stop compiling and present an error message In those situations, we can declare the type this way: var a: Int = 1; val s: String = "This is a string literal"; With Java 8, as we've seen, we have Optional to help deal with null values Kotlin has null support as well, but it's built into the language By default, all variables in Kotlin are not nullable That is to say, if the compiler can tell that you are attempting to assign a null value to a variable, or if it can't determine whether or not a value might be null (for example, a return value from a Java API), you'll get a compiler error To indicate that a value is null-capable, you add a ? to the variable declaration as follows: var var1 : String = null; // error var var2 : String? = null; // ok Kotlin also offers improved null-handling support in method calls Suppose, for example, you want to get a user's city In Java, you may something like this: String city = null; User user = getUser(); if (user != null) { Address address = user.getAddress(); if (address != null) { city address.getCity(); } } In Kotlin, that can be expressed in a single line, as follows: var city : String? = getUser()?.getAddress()?.getCity(); If, at any point, one of the methods returns null, the method call chain ends, and null is assigned to the variable city Kotlin doesn't stop there with null handling It provides, for an example, the let function that can serve as a shortcut for if-not-null checks For example, consider the following lines of code: if (city != null) { System.out.println(city.toUpperCase()); } The preceding lines of code become this in Kotlin: city?.let { println(city.toUpperCase()) } This could, of course, be written as city?.toUpperCase() What this should demonstrate, though, is the ability to safely use a nullable variable in an arbitrarily large, complex block of code It's also worth noting that, inside the let block, the compiler knows that city is not null so no further null checks are necessary Hidden, perhaps, in the preceding example is Kotlin's support for lambdas, without which, it seems, no modern language is worth considering Kotlin does, indeed, have full support for lambdas, higher order functions, underscores as lambda parameter names, and so on Its support and syntax are very similar to Java's, so Java developers should be very comfortable with Kotlin's lambdas The big question is, of course, Is Kotlin ready for prime time? JetBrains definitely thinks so, as they have it in use in many of their applications, both internal and external Other notable users include Pinterest, Gradle, Evernote, Uber, Pivotal, Atlassian, and Basecamp Kotlin is even officially supported by Google (in Android Studio) for Android development, so it's definitely a productiongrade language There's much, much more to this great new language, of course, and space won't allow us to discuss all of it, but you can browse through https://kotlinlang.org to learn more and see if Kotlin is a good fit for your organization Summary There is much more that can be discussed of course, about Java 10 and these two languages, and the myriad of other projects happening in and around the Java Virtual Machine After over 20 years of development, Java the language and the environment is still going strong In the pages of this book, I've tried to demonstrate some of these great advancements in the language, giving you a variety of starting points for your own projects, sample code to study and reuse, and explanations of various libraries, APIs, and technologies that may be helpful in your day-to-day work I hope you've enjoyed the examples and explanations as much as I've enjoyed preparing them, and, more importantly, I hope they help you build the Next Big Thing Good luck! Bibliography This Learning Path combines some of the best that Packt has to offer in one complete, curated package It includes content from the following Packt products: Mastering Java 9, Dr Edward Lavieri and Peter Verhas Java Programming Blueprints, Jason Lee .. .Java 9: Building Robust Modular Applications Master advanced Java features and implement them to build amazing projects A learning path in two sections BIRMINGHAM - MUMBAI Java 9: Building Robust. .. at the history of email protocols JavaMail, the Standard Java API for Email Building the CLI Building the GUI Building the service Summary 24 Photo Management with PhotoBeans Getting started Bootstrapping... newsletters, and receive exclusive discounts and offers on Packt books and eBooks Table of Contents Title Page - Courses Copyright and Credits - Courses Java 9: Building Robust Modular Applications