Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Java EE 8 and Angular

You're reading from   Java EE 8 and Angular A practical guide to building modern single-page applications with Angular and Java EE

Arrow left icon
Product type Paperback
Published in Jan 2018
Publisher Packt
ISBN-13 9781788291200
Length 348 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Prashant Padmanabhan Prashant Padmanabhan
Author Profile Icon Prashant Padmanabhan
Prashant Padmanabhan
Arrow right icon
View More author details
Toc

Table of Contents (16) Chapters Close

Preface 1. What's in Java EE 8? 2. The CDI Advantage Combined with JPA FREE CHAPTER 3. Understanding Microservices 4. Building and Deploying Microservices 5. Java EE Becomes JSON Friendly 6. Power Your APIs with JAXRS and CDI 7. Putting It All Together with Payara 8. Basic TypeScript 9. Angular in a Nutshell 10. Angular Forms 11. Building a Real-World Application 12. Connecting Angular to Java EE Microservices 13. Testing Java EE Services 14. Securing the Application 15. Other Books You May Enjoy

Overview of Java SE 8

One of the goals of Java EE 8 was better alignment with Java SE 8. SE 8 was a major update; it was released in March 2014 and brought with it some major changes to the language and APIs. Lambdas, streams, default methods, and functional-style programming were introduced and were the highlights of the release. With these capabilities, the method of writing code was no longer going to be the same. A few other noteworthy additions in this release were optionals, repeating annotations, the date/time APIs, type annotations, and CompletableFutures.

If you would like to dig deeper into this release, then considering reading a book specific to Java 8. Here, we will cover just enough for getting to grips with some of the language features.

Lambdas, streams, and default methods

Lambdas have been the biggest change in the language since generics were introduced in Java 5. This was a fundamental change that impacted many of the APIs to follow. Anonymous classes are very useful to pass code around, but they come at the cost of readability as they lead to some boilerplate code (think Runnable or ActionListener). Those wanting to write clean code that is readable and void of any boilerplate would appreciate what lambda expressions have to offer.

In general, lambda expressions can only be used where they will be assigned to a variable whose type is a functional interface. The arrow token (->) is called the lambda operator. A functional interface is simply an interface having exactly one abstract method:

Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("anonymous inner class method");
}
};

With lambdas similar to those in the preceding code, the code can be rewritten as follows, where the empty parenthesis is used for the no args method:

Runnable runWithLambda = () -> System.out.println("hello lambda");

To understand some of the enhancements, let us look at an example. Consider the Hero class, which is a plain Java object with two properties, telling us the name of the Hero and whether the hero can fly or not. Well, yes there are a few who can't fly, so let's keep the flag around:

 class Hero {  
String name;
boolean canFly;

Hero(String name, boolean canFly) {
this.name = name;
this.canFly = canFly;
}
// Getters & Setters omitted for brevity
}

Now, it's typical to see code that iterates over a collection and does some processing with each element in the collection. Most of the methods would typically repeat the code for iterating over a list, but what varies is usually the condition and the processing logic. Imagine if you had to find all heroes who could fly and find all heroes whose name ends with man. You would probably end up with two methods—one for finding flying heroes and another for the name-based filter. Both these methods would have the looping code repeated in them, which would not be that bad, but we could do better. A solution is to use anonymous inner class blocks to solve this, but then it becomes too verbose and obscures the code readability. Since we are talking about lambdas, then you must have guessed by now what solution we can use. The following sample iterates over our Hero list, filtering the elements by some criteria and then processing the matching ones:

List<String> getNamesMeetingCondition(List<Hero> heroList,
Predicate<Hero> condition) {
List<String> foundNames = new ArrayList<>();
for (Hero hero : heroList) {
if (condition.test(hero)) {
foundNames.add(hero.name);
}
}
return foundNames;
}

Here, Predicate<T> is a functional interface new to Java 8; it has one abstract method called test, which returns a Boolean. So, you can assign a lambda expression to the Predicate type. We just made the condition a behavior that can be passed dynamically.

Given a list of heroes, our code can now take advantage of lambdas without having to write the verbose, anonymous inner classes:

List<Hero> heroes = Arrays.asList(
new Hero("Hulk", false),
new Hero("Superman", true),
new Hero("Batman", false));

List<String> result = getNamesMeetingCondition(heroes, h -> h.canFly);
result = getNamesMeetingCondition(heroes, h -> h.name.contains("man"));

And finally, we could print the hero names using the new forEach method available for all collection types:

result.forEach( s -> System.out.println(s));

Moving onto streams, these are a new addition along with core collection library changes. The Stream interface comes with many methods that are helpful in dealing with stream processing. You should try to familiarize yourself with a few of these. To establish the value of streams, let's solve the earlier flow using streams. Taking our earlier example of the hero list, let's say we wanted to filter the heroes by the ability to fly and output the filtered hero names. Here's how its done in the stream world of Java:

heroes.stream().filter(h -> h.canFly)
.map( h -> h.name)
.forEach(s -> System.out.println(s));

The preceding code is using the filter method, which takes a Predicate and then maps each element in the collection to another type. Both filter and map return a stream, and you can use them multiple times to operate on that stream. In our case, we map the filtered Hero objects to the String type, and then finally we use the forEach method to output the names. Note that forEach doesn't return a stream and thus is also considered a terminal method.

If you hadn't noticed earlier, then look again at the previous examples in which we already made use of default methods. Yes, we have been using the forEach method on a collection which accepts a lambda expression. But how did they add this method without breaking existing implementations? Well, it's now possible to add new methods to existing interfaces by means of providing a default method with its own body. For collection types, this method has been defined in the Iterable interface.

These capabilities of Java 8 are now powering many of the EE 8 APIs. For example, the Bean Validation 2.0 release is now more aligned to language constructs such as repeatable annotations, date and time APIs, and optionals. This allows for using annotations to validate both the input and output of various APIs. We will learn more about this as we explore the APIs throughout the book.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime