Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Design Patterns and Best Practices in Java
Design Patterns and Best Practices in Java

Design Patterns and Best Practices in Java: A comprehensive guide to building smart and reusable code in Java

Arrow left icon
Profile Icon Puri Profile Icon Singh Profile Icon Torje Profile Icon Ianculescu
Arrow right icon
$27.98 $39.99
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.5 (4 Ratings)
eBook Jun 2018 280 pages 1st Edition
eBook
$27.98 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Puri Profile Icon Singh Profile Icon Torje Profile Icon Ianculescu
Arrow right icon
$27.98 $39.99
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.5 (4 Ratings)
eBook Jun 2018 280 pages 1st Edition
eBook
$27.98 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$27.98 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Table of content icon View table of contents Preview book icon Preview Book

Design Patterns and Best Practices in Java

From Object-Oriented to Functional Programming

The objective of this chapter is to introduce the reader to the fundamental concepts of writing robust, maintainable, and extendable code using design patterns and the latest features available in Java. In order to achieve our objective, we will cover the following topics:

  • What are programming paradigms?
  • Imperative paradigm
  • Declarative and functional paradigms
  • Object-oriented paradigm
  • An overview of Unified Modeling Language
  • Object-oriented design principles

Java – an introduction

In 1995, a new programming language was released, inspired by the well-known C++ and the lesser known Smalltalk. Java was the name of this new language, and it tried to fix most of the limitations its predecessors had. For example, one important feature of Java that made it popular was write once and run anywhere; that is, you could develop your code on a Windows machine and run it on a Linux or any other machine, all you needed was a JVM. It provided additional features such as garbage collection, which freed up the developer from needing to maintain memory allocation and deallocations; the Just in Time compiler (JIT) made Java intelligent and fast, and removing features such as pointers made it more secure. All the aforementioned features and the later addition of web support made Java a popular choice among developers. Around 22 years later, in a world where new languages come and disappear in a couple of years, Java version 10 has already been successfully launched and adapted by the community, which says a lot about the success of Java.

Java programming paradigms

What are programming paradigms? Since software development began, there have been different approaches to designing programing languages. For each programming language, we have a set of concepts, principles, and rules. Such a set of concepts, principles, and rules is called a programming paradigm. In theory, languages are considered to fall under one paradigm only, but, in practice, programming paradigms are mostly combined in one language. 

In the following section, we will highlight the programming paradigms on which Java programming language is based, along with the major concepts that describe these paradigms. These are imperative, object-oriented, declarative, and functional programming.

Imperative programming

Imperative programming is a programming paradigm in which statements are written to change the state of the program. This concept emerged at the beginning of computing and is very close to the computer's internal structure. The program is a set of instructions that is run on the processing unit, and it changes the state (which is stored as variables in the memory) in an imperative manner. The name imperative implies the fact that the instructions that are executed dictate how the program operates.

Most of the most popular programming languages today are based, more or less, on the imperative paradigm. The best example of a mainly imperative language is C.

Real-life imperative example

In order to better understand the concept of the imperative programming paradigm, let's take the following example: you're meeting a friend for a hackathon in your town, but he has no idea how to get there. We'll explain to him how to get there in an imperative way:

  1. From the Central Station, take tram 1.
  2. Get off the tram at the third station.
  3. Walk to the right, toward Sixth Avenue, until you reach the third junction.

Object-oriented paradigm

The object-oriented paradigm is often associated with imperative programming, but, in practice, both functional and object-oriented paradigms can coexist. Java is living proof that supports this collaboration.

In the following section, we will briefly highlight the main object-oriented concepts as they are implemented in the Java language.

Objects and classes

Objects are the main elements of an object-oriented programming (OOP) language. An object holds both the state and the behavior.

If we think of classes as a template, objects are the implementation of the template. For example, if human is a class that defines the behavior and properties that a human being can have, you and I are objects of this human class, as we have fulfilled all the requirements of being a human. Or, if we think of car as a class, a particular Honda Civic car will be an object of this class. It will fulfill all the properties and behaviors that a car has, such as it has an engine, a steering wheel, headlights, and so on, and it has behaviors of moving forward, moving backward, and so on. We can see how the object-oriented paradigm can relate to the real world. Almost everything in the real world can be thought of in terms of classes and objects, hence it makes OOP effortless and popular.

Object-oriented programming is based on four fundamental principles:

  • Encapsulation
  • Abstraction
  • Inheritance
  • Polymorphism (subtyping polymorphism).

Encapsulation

Encapsulation basically means the binding of attributes and behaviors. The idea is to keep the properties and behavior of an object in one place, so that it is easy to maintain and extend. Encapsulation also provides a mechanism to hide unnecessary details from the user. In Java, we can provide access specifiers to methods and attributes to manage what is visible to a user of the class, and what is hidden.

Encapsulation is one of the fundamental principles of object-oriented languages. It helps in the decoupling of different modules. Decoupled modules can be developed and maintained more or less independently. The technique through which decoupled modules/classes/code are changed internally without affecting their external exposed behavior is called code refactoring.

Abstraction

Abstraction is closely related to encapsulation, and, to some extent, it overlaps with it. Briefly, abstraction provides a mechanism that exposes what an object does and hides how the object does what it's supposed to do.

A real-world example of abstraction is a car. In order to drive a car, we don't really need to know what the car has under the hood, but we need to know the data and behavior it exposes to us. The data is exposed on the car's dashboard, and the behavior is represented by the controls we can use to drive a car.

Inheritance

Inheritance is the ability to base an object or class on another one. There is a parent or base class, which provides the top-level behavior for an entity. Every subclass entity or child class that fulfills the criteria to be a part of the parent class can inherit from the parent class and add additional behavior as required.

Let's take a real-world example. If we think of a Vehicle as a parent class, we know a Vehicle can have certain properties and behaviors. For example, it has an engine, doors, and so on, and behavior-wise it can move. Now all entities that fulfill these criteria—for example, Car, Truck, Bike, and so on—can inherit from Vehicle and add on top of given properties and behavior. In other words, we can say that a Car is a type of Vehicle.

Let's see how this will look as code; we will first create a base class named Vehicle. The class has a single constructor, which accepts a String (the vehicle name):

public class Vehicle 
{
private Stringname;
public Vehicle(Stringname)
{
this.name=name;
}
}

Now we can create a Car class with a constructor. The Car class is derived from the Vehicle class, so it inherits and can access all the members and methods declared as protected or public in the base class:

public class Car extends Vehicle
{
public Car(String name)
{
super(name)
}
}

Polymorphism

In broad terms, polymorphism gives us an option to use the same interface for entities of different types. There are two major types of polymorphism, compile time and runtime. Say you have a Shape class that has two area methods. One returns the area of a circle and it accepts single integer; that is, the radius is input and it returns the area. Another method calculates the area of a rectangle and takes two inputs, length and breadth. The compiler can decide, based on the number of arguments in the call, which area method is to be called. This is the compile-time type of polymorphism.

There is a group of techies who consider only runtime polymorphism as real polymorphism. Runtime polymorphism, also sometimes known as subtyping polymorphism, comes into play when a subclass inherits a superclass and overrides its methods. In this case, the compiler cannot decide whether the subclass implementation or superclass implementation will be finally executed, and hence a decision is taken at runtime.

To elaborate, let's take our previous example and add a new method to the vehicle type to print the type and name of the object:

public String toString()
{
return "Vehicle:"+name;
}

We override the same method in the derived Car class:

public String toString()
{
return "Car:"+name;
}

Now we can see subtyping polymorphism in action. We create one Vehicle object and one Car object. We assign each object to a Vehicle variable type because a Car is also a Vehicle. Then we invoke the toString method for each of the objects. For vehicle1, which is an instance of the Vehicle class, it will invoke the Vehicle.toString() class. For vehicle2, which is an instance of the Car class, the toString method of the Car class will be invoked:

Vehicle vehicle1 = new Vehicle("A Vehicle");
Vehicle vehicle2 = new Car("A Car")
System.out.println(vehicle1.toString());
System.out.println(vehicle2.toString());

Declarative programming

Let's go back to the real-life imperative example, where we gave directions to a friend on how to get to a place. When we think in terms of the declarative programming paradigm, instead of telling our friend how to get to the specific location, we can simply give him the address and let him figure out how to get there. In this case, we tell him what to do and we don't really care if he uses a map or a GPS, or if he asks somebody for instructions: Be at the junction between Fifth Avenue and Ninth Avenue at 9:30 in the morning.

As opposed to imperative programming, declarative programming is a programming paradigm that specifies what a program should do, without specifying how to do it. Among the purely declarative languages are database query languages, such as SQL and XPath, and regular expressions.

Declarative programming languages are more abstract compared to imperative ones. They don't mimic the hardware structure, and, as a consequence, they don't change the programs' states but transform them to new states, and are closer to mathematical logic.

In general, the programming styles that are not imperative are considered to fall in the declarative category. This is why there are many types of paradigms that fall under the declarative category. In our quest, we will look at the only one that is relevant to the scope of our journey: functional programming.

Functional programming

Functional programming is a sub-paradigm of declarative programming. As opposed to imperative programming, functional programming does not change the internal state of the program.

In imperative programming, the functions can be regarded more as sequences of instructions, routines, or procedures. They not only depend on the state stored in the memory but can also change that state. This way, invoking an imperative function with the same arguments can produce different results depending on the current program's state, and at the same time, the executed function can change the program's variables.

In functional programming terminology, functions are similar to mathematical functions, and the output of a function depends only on its arguments, regardless of the program's state, which, at the same time, remains unaffected by the execution of the function.

Paradoxically, while imperative programming has existed since computers were first created, the basic concepts of functional programming dates back before that. Most functional languages are based on lambda calculus, a formal system of mathematical logic created in the 1930s by mathematician Alonzo Church.

One of the reasons why functional languages become so popular in those days is the fact that they can easily run in parallel environments. This should not be confused with multithreading. The main feature that allows functional languages to run in parallel is the basic principle on which they reside: the functions rely only on the input arguments and not on the program's state. That is, they can be run anywhere, and the results of the multiple parallel executions are then joined and used further.

Working with collections versus working with streams

Everyone working with Java is aware of collections. We use collections in an imperative way: we tell the program how to do what it's supposed to do. Let's take the following example in which we instantiate a collection of 10 integers, from 1 to 10:

List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10; i++)
{
list.add(i);
}

Now, we will create another collection in which we will filter in only the odd numbers:

List<Integer> odds = new ArrayList<Integer>();
for (int val : list)
{
if (val % 2 == 0)
odds.add(val);
}

At the end, we want to print the results:

for (int val : odds)
{
System.out.print(val);
}

As you can see, we wrote quite a bit of code to perform three basic operations: to create a collection of numbers, to filter the odd numbers, and then to print the results. Of course, we could do all the operations in only one loop, but what if we could do it without using a loop at all? After all, using a loop means we tell the program how to do its task. From Java 8 onwards, we have been able to use streams to do the same things in a single line of code:

IntStream
.range(0, 10)
.filter(i -> i % 2 == 0)
.forEach( System.out::print );

Streams are defined in the java.util.stream package, and are used to manage streams of objects on which functional-style operations can be performed. Streams are the functional correspondent of collections, and provide support for map-reduce operations.

We will further discuss streams and functional programming support in Java in later chapters.

An introduction to Unified Modeling Language

Unified Modeling Language (UML) is a modeling language that helps us to represent how the software is structured; how different modules, classes, and objects interact with each other, and what the relations between them are.

UML is frequently used in association with object-oriented design, but it has a much broader scope. However, that is beyond the scope of this book, so, in the next sections, we will highlight the UML features relevant to this book.

In UML, we can define the structure and behavior of a system, and we can visualize the model or parts of it through diagrams. There are two types of diagram:

  • Structure diagrams are used to represent the structure of a system. There are many types of structure diagrams, but we are only interested in class diagrams. object, package, and component diagrams are similar to class diagrams.
  • Behavior diagrams are used to describe the behavior of a system. Interaction diagrams are a subset of behavior diagrams and are used to describe the flow of control and data among different components of a system. Among the behavior diagrams, the sequence diagram is used extensively in object-oriented design.

Class diagrams are the type of diagrams used most in object-oriented design and development stages. They are a type of structure diagram, and are used to illustrate the structure of classes and the relations among them:

Class diagrams are useful for describing how the classes are structured in an application. Most of the time, just looking at the structure can be enough to be able to understand how the classes interact, but sometimes this is not enough. For those cases, we can use behavior and interaction diagrams, of which the sequence diagram is used to describe class and object interaction. Let's use a sequence diagram to show how the Car and Vehicle objects interact in the inheritance and polymorphism example:

Class relations

In object-oriented programming, besides the inheritance relation that represents one of the fundamental concepts, there are a few other class relations that help us to model and develop complex software systems:

  • Generalization and realization
  • Dependency
  • Association, aggregation, and composition

Generalization

Inheritance is also called an is-a relationship because the class inherited from another class can be used as the superclass.

When a class represents the shared characteristics of more than one class, it is called a generalization; for example, Vehicle is a generalization of Bike, Car, and Truck. Similarly, when a class represents a special instance of a general class, it is called a specialization, so a Car is a specialization of Vehicle, as shown in the following diagram:

In UML terminology, the relation to describe inheritance is called Generalization.

Realization

If generalization is the corresponding term in UML for object-oriented inheritance, realization, in UML, represents the implementation of an interface by a class in object-oriented programming.

Let's assume we create an interface called Lockable, which is implemented only by Vehicles that can be locked. In this case, a version of the previous diagram implementing Lockable for the Car class will look like this:

Dependency

Dependency is one of the most generic types of UML relationship. It is used to define that one class depends in some way or other on another class, while the other class may or may not depend on the first one. A dependent relationship is used to represent relations that do not fall into one of the cases described in the following sections. Dependency is sometimes called Uses-A relationship.

In general, in object-oriented programming languages dependency is used to describe whether one class contains a parameter of the second class in the signature of a method, or whether it creates instances of the second class by passing them to other classes without using them (without invoking its methods):

Association

An association represents the relationship between two entities. There are two types of association, namely composition and aggregation. In general, an association is represented by an arrow, as shown in the following diagram:

Aggregation

An aggregation is a special type of association. If inheritance is considered to be the is-a relationship, aggregation can be considered to be the HAS-A relationship.

Aggregation is used to describe a relation between two or more classes, when one class contains the other from a logical point of view, but instances of the contained class can live independently of the first class, outside of its context, or can be shared among other classes. For example, a Department HAS-A Teacher; additionally, every Teacher must belong to Department, but if a Department ceases to exist, a Teacher can still be active as shown in the following diagram:

Composition

As the name suggests, a class is a composition of another one. This is somewhat similar to aggregation, with the difference being that the dependent class ceases to exist when the main class ceases to exist. For example, a House is made up of a Room, but the Room ceases to exist if the House is destroyed, as shown in the following diagram:

In practice, especially in languages such as Java that have garbage collectors, the boundary between composition and aggregation is not so well defined. Objects are not destroyed manually; when they are no longer referenced, they are automatically destroyed by the garbage collector. For this reason, from a coding point of view, we should not really be concerned if we deal with a composition or an aggregation relationship, but it's important if we want to have a well-defined model in UML.

Design patterns and principles

Software development is a process that is not only about writing code, regardless of whether you are working in a large team or on a one-person project. The way an application is structured has a huge impact on how successful a software application is.

When we are talking about a successful software application, we are not only discussing how the application does what it's supposed to do but also how much effort we put into developing it, and if it's easy to test and maintain. If this is not done in a correct manner, the skyrocketing development cost will result in an application that nobody wants.

Software applications are created to meet needs, which are constantly changing and evolving. A successful application should also provide an easy way through which it can be extended to meet the continuously changing expectations.

Luckily, we are not the first to encounter these problems. Some of the problems have already been faced and handled. These common problems can be avoided or solved if a set of object-oriented design principles and patterns are applied while designing and developing software.

The object-oriented design principles are also called SOLID. These principles are a set of rules that can be applied when designing and developing software, in order to create programs that are easy to maintain and develop. They were first introduced by Robert C. Martin, and they are part of the agile software-development process. The SOLID principles include the single responsibility principle, open/closed principle, Liskov Substitution Principle, Interface Segregation Principle, and dependency inversion principle.

In addition to the design principles, there are object-oriented design patterns. Design patterns are general reusable solutions that can be applied to commonly occurring problems. Following Christopher Alexander's concept, design patterns were first applied to programming by Kent Beck and Ward Cunningham, and they were popularized by the so-called Gang Of Four (GOF) book in 1994. In the following section, we will present the SOLID design principles, which will be followed by the design patterns in the next chapters.

Single responsibility principle

The single responsibility principle is an object-oriented design principle that states that a software module should have only one reason to change. In most cases, when writing Java code, we will apply this to classes.

The single responsibility principle can be regarded as a good practice for making encapsulation work at its best. A reason to change is something that triggers the need to change the code. If a class is subject to more than one reason to change, each of them might introduce changes that affect others. When those changes are managed separately but affect the same module, one set of changes might break the functionality related to the other reasons for change.

On the other hand, each responsibility/reason to change will add new dependencies, making the code less robust and harder to change.

In our example, we will use a database to persist the objects. Let's assume that, for the Car class, we will add methods to handle the database operations of create, read, update, and delete, as shown in the following diagram:

In this case, the Car will not only encapsulate the logic, but also the database operations (two responsibilities are two reasons to change). This will make our classes harder to maintain and test, as the code is tightly coupled. The Car class will depend on the database, so if in the future we want to change the database system, we have to change the Car code. This might generate errors in the Car logic.

Conversely, changing the Car logic might generate errors in the data persistence.

The solution would create two classes: one to encapsulate the Car logic and the other to be responsible for persistence:

Open/closed principle

This principle is as follows:

"Modules, classes, and functions should be open for extension but closed for modifications."

Applying this principle will help us to develop complex and robust software. We must imagine the software we develop is building a complex structure. Once we finish a part of it, we should not modify it any more but build on top of it.

When developing software, it's the same. Once we have developed and tested a module, if we want to change it, we must test not only the functionality we are changing but the entire functionality it's responsible for. That involves a lot of additional resources, which might not have been estimated from the beginning, and also can bring additional risks. Changes in one module might affect functionality in others or on the whole. The following is a diagrammatic representation:

For this reason, best practice is to try to keep modules unchanged once finished and to add new functionality by extending them using inheritance and polymorphism. The open/closed principle is one of the most important design principles being the base for most of the design patterns.

 

Liskov Substitution Principle

Barbara Liskov states that, Derived types must be completely substitutable for their base types. The Liskov Substitution Principle (LSP) is strongly related to subtyping polymorphism. Based on subtyping polymorphism in an object-oriented language, a derived object can be substituted with its parent type. For example, if we have a Car object, it can be used in the code as a Vehicle.

The LSP states that, when designing the modules and classes, we must make sure that the derived types are substitutable from a behavior point of view. When the derived type is substituted with its supertype, the rest of the code will operate with it as it is the subtype. From this point of view, the derived type should behave as its supertype and should not break its behavior. This is called strong behavioral subtyping.

In order to understand the LSP, let's take an example in which the principle is violated. While we are working on the car-service software, we discover we need to model the following scenario. When a car is left for service, the owner leaves the car. The service assistant takes the key and, when the owner leaves, he goes to check that he has the right key and that he has spotted the right car. He simply goes to unlock and lock the car, then he puts the key in a designated place with a note on it so the mechanic can easily pick it up when he has to inspect the car.

We already have defined a Car class. We are now creating a Key class and adding two methods into the car class: lock and unlock. We add a corresponding method, so the assistant checks the key matches the car:

public class Assistant
{
void checkKey(Car car, Key key)
{
if ( car.lock(key) == false ) System.out.println("Alert! Wrong
key, wrong car or car lock is broken!");
}
}

The diagram is as follows:

While working on our software, we realize that buggies are sometimes repaired through the car service. As buggies are four-wheel cars, we create a Buggy class, which is inherited from the Car:

Buggies don't have doors, so they cannot be locked or unlocked. We implement our code accordingly:

public bool lock(Key key)
{
// this is a buggy so it can not be locked return false;
}

We design our software to work with cars, regardless of whether they are buggies or not, so in the future we might extend it with other types of cars. A problem may arise from the fact that cars are expected to be locked and unlocked.

Interface Segregation Principle

The following quote is taken from https://www.oodesign.com/interface-segregation-principle.html link:

"Clients should not be forced to depend upon interfaces that they don't use."  

When applied, the Interface Segregation Principle (ISP) reduces the code coupling, making the software more robust, and easier to maintain and extend. ISP was first announced by Robert Martin, when he realized that if the principle is broken and clients are forced to depend on interfaces they don't use, the code becomes so tightly coupled that it's almost impossible to add new functionality to it.

In order to better understand this, let's again take the car-service example (refer to the following diagram). Now we need to implement a class named Mechanic. The mechanic repairs cars, so we add a method of repair car. In this case, the Mechanic class depends upon the I class. However, the Car class exposes a richer sets of methods than the Mechanic class needs:

This is a bad design because if we want to replace a car with another one, we need to make changes in the Mechanic class, which violates the open/closed principle. Instead, we must create an interface that exposes only the relevant methods required in the Mechanic class, as shown in the following diagram:

Dependency inversion principle

"High-level modules should not depend on low-level modules. Both should depend on abstractions."
"Abstractions should not depend on details. Details should depend on abstractions."

In order to understand this principle, we must explain the important concept of coupling and decoupling. Coupling refers to the degree to which modules of a software system are dependent on one another. The lower the dependency is, the easier it is to maintain and extend the system.

There are different approaches to decoupling the components of a system. One of them is to separate the high-level logic from the low-level modules, as shown in the following diagram. When doing this, we should try to reduce the dependency between the two by making them depend on abstractions. This way, any of them can be replaced or extended without affecting other modules:

Summary

In this chapter, we presented the main programming paradigms used in Java. We have learned that two different paradigms, such as imperative programming and functional programming, can coexist in the same language; and we have learned how Java went from pure, imperative object-oriented programming to integrating functional programming elements.

Although Java introduced new functional elements, starting from version 8, it is at its core still an object-oriented language. In order to write solid and robust code that is easy to extend and maintain, we learned about the fundamental principles of object-oriented programming languages.

An important part of developing software is designing the structure and the desired behavior of the components of our programs. This way, we can work on large systems, in large teams, sharing our object-oriented designs within or between teams. In order to be able to do this, we highlighted the main UML diagrams and concepts relevant to object-oriented design and programming. We also use UML extensively in our book to describe the examples.

After introducing the class relationships and showing how to represent them in diagrams, we dove into the next section, where we described what the object-oriented design patterns and principles are, and we presented the main principles.

In the next chapter, we will move on to presenting the group of design patterns dealing with object creation in such a way that our code is robust and extendable.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • This book demonstrates the shift from OOP to functional programming and covers reactive and functional patterns in a clear and step-by-step manner
  • All the design patterns come with a practical use case as part of the explanation, which will improve your productivity
  • Tackle all kinds of performance-related issues and streamline your development

Description

Having a knowledge of design patterns enables you, as a developer, to improve your code base, promote code reuse, and make the architecture more robust. As languages evolve, new features take time to fully understand before they are adopted en masse. The mission of this book is to ease the adoption of the latest trends and provide good practices for programmers. We focus on showing you the practical aspects of smarter coding in Java. We'll start off by going over object-oriented (OOP) and functional programming (FP) paradigms, moving on to describe the most frequently used design patterns in their classical format and explain how Java’s functional programming features are changing them. You will learn to enhance implementations by mixing OOP and FP, and finally get to know about the reactive programming model, where FP and OOP are used in conjunction with a view to writing better code. Gradually, the book will show you the latest trends in architecture, moving from MVC to microservices and serverless architecture. We will finish off by highlighting the new Java features and best practices. By the end of the book, you will be able to efficiently address common problems faced while developing applications and be comfortable working on scalable and maintainable projects of any size.

Who is this book for?

This book is for those who are familiar with Java development and want to be in the driver’s seat when it comes to modern development techniques. Basic OOP Java programming experience and elementary familiarity with Java is expected.

What you will learn

  • Understand the OOP and FP paradigms
  • Explore the traditional Java design patterns
  • Get to know the new functional features of Java
  • See how design patterns are changed and affected by the new features
  • Discover what reactive programming is and why is it the natural augmentation of FP
  • Work with reactive design patterns and find the best ways to solve common problems using them
  • See the latest trends in architecture and the shift from MVC to serverless applications
  • Use best practices when working with the new features

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jun 27, 2018
Length: 280 pages
Edition : 1st
Language : English
ISBN-13 : 9781786469014
Vendor :
Oracle
Category :
Languages :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Jun 27, 2018
Length: 280 pages
Edition : 1st
Language : English
ISBN-13 : 9781786469014
Vendor :
Oracle
Category :
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 131.97
Design Patterns and Best Practices in Java
$48.99
Modular Programming in Java 9
$38.99
Java 9 Data Structures and Algorithms
$43.99
Total $ 131.97 Stars icon
Banner background image

Table of Contents

10 Chapters
From Object-Oriented to Functional Programming Chevron down icon Chevron up icon
Creational Patterns Chevron down icon Chevron up icon
Behavioral Patterns Chevron down icon Chevron up icon
Structural Patterns Chevron down icon Chevron up icon
Functional Patterns Chevron down icon Chevron up icon
Let&#x27;s Get Reactive Chevron down icon Chevron up icon
Reactive Design Patterns Chevron down icon Chevron up icon
Trends in Application Architecture Chevron down icon Chevron up icon
Best Practices in Java Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.5
(4 Ratings)
5 star 50%
4 star 0%
3 star 0%
2 star 50%
1 star 0%
Sal Jan 03, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I was quite pleased by the way the authors approached the content.The first few chapters did a nice introduction and overview of patterns. Once we rolled into Chapter 5, and investigated Functional Patterns can simplify existing patterns, I was more than happy with my purchase.I never expect a book to be an end-all-be-all to all problems, but this is a great spring board to start anyone off.
Amazon Verified review Amazon
AJ Aug 12, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I liked that most of chapters have good examples regarding usage of design patterns in Java. It helps you visualize the exact usage of these best practices and patterns in real world problems.
Amazon Verified review Amazon
Viorel Contu Aug 12, 2018
Full star icon Full star icon Empty star icon Empty star icon Empty star icon 2
This book fails at its intended purpose: to teach you Design Patterns.Most of the design patterns concepts are explained on one or two pages. It usually starts with a short description, then it continues with a few sentences about why it is important. The UML diagram and the code snippet is not enough to grasp the whole idea behind the design pattern presented. The examples are very basic and not good enough.Then it tries to condense into this book principles of Functional programming and how they affect design patterns. I am sorry, but the authors did a terrible job at explaining all the concepts including: functors and monads.At it stands, it is not worth your money. The are better alternatives out there. There are free youtube tutorials that do does a better job at explaining the design patterns. If you really want a book to read, buy head first design patterns.
Amazon Verified review Amazon
Don't show me Sep 05, 2018
Full star icon Full star icon Empty star icon Empty star icon Empty star icon 2
The book covers most (if not all) typical design patterns in Java, however there's no depth to it. The examples are text descriptions on how you would "use this to...", but there are no implementation details. I thought there would be much more details and some code. Very disappointed in the book. There are free examples on the web that are better.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.