Java knowledge about lambda 8

Tram Ho

As you all know, Java 8 is a big change. Making Java syntax slimmer and easier to read.

But many of you have a hard time getting started, so I will write a thorough article why using Java lambda Java 8, it does not help us.

Note: Due to thorough analysis of the article, the code will be long. You can use the clips function to save and read slowly.

I want to help you read only once and understand thoroughly, instead of reading many times, many places but still do not understand how to use.

There are three things ignorant: Not knowing what we need to know; Know not know what you know; Know what you shouldn’t know. (La Rochefoucauld)

Coping with change

Writing code to adapt to changing requirements is a difficult task. Let’s take a look at the examples, step by step improving the code, making your code more flexible.

In the context of the farm management application, you perform the following function:

  • Search for the green apples in the list.

Method 1: filter the green apples

The method you often use will be as follows:

Filter the green apple with the condition as follows: "green".equals(apple.getColor()) . But the farmer wants to change his mind and wants to search for the apple in red.

What will you do with this problem? What we often do is copy the current code, rename the function from filterGreenApple to filterRedApple , and change the search condition to "red".equals(apple.getColor()) .

However, this way will not meet the requirements of the farm owner, who can search for a variety of colors such as blue, red black, yellow.

There is a rule to solve this problem: when encountering duplicate code, abstract it.

Method 2: parameterize colors

What you can do is add a parameter to the function to parameterize the color to help the code more flexible with the change:

And now, the rancher is very happy because he can search by all colors:

List<Apple> greenApples = filterApplesByColor(inventory, "green");

List<Apple> redApples = filterApplesByColor(inventory, "red");

It’s easy, isn’t it? We will now explore with a harder example.

The owner of the farm meets you and tells you that

It would be great to separate apples based on weight.

As you know the answer will be like:

It looks fine, but after a closer look you’ll realize that only the search term is changed if ( apple.getWeight() > weight ) . All that code repeats.

This breaks the DRY programming principle (don’t repeat yourself).

If you want to speed up the search terms, then you have to fix the entire executable code, instead of just fixing one place. This is very maintenance time, and very easy to create bugs.

And you want to combine two search terms by color and weight into one place. But you need to have an attribute that distinguishes a search term (by color or weight) by creating a flag variable.

Method 3: Search with multiple attributes

You can execute the following code: (but it looks confusing, quite confusing)

When flag is true will search by color.

List<Apple> greenApples = filterApples(inventory, "green", 0, true);

When flag is false will search by size.

List<Apple> heavyApples = filterApples(inventory, "", 150, false);

This solution is very bad.

  1. The code client looks horrible. What is true false ?
  2. Not responding when request changes. What if the farmer asked to search by place of production, type, etc.?
  3. If the farmer asks for a combination of conditions: Looking for green apples weighing over 600g? You have to copy the code somewhere else and then edit the code, or create a very complicated function like creating a flag variable as above.

Parameterization by value can be solved in some specific cases. But in this case, you need a better way, and the next part I will mention it.

Behavior parameterization

As you saw in the previous section, you need a better solution instead of adding many parameters.

You just need to change the search conditions and the remaining code remains the same. An object only returns true or false .

alt text

We will create an interface with a function that is a search criteria

And now you define your search term the way you want:

Look for apples that weigh more than 150g:

Search for green apples:

As you can see, we have divided two types of searches, based on user needs.

What you have just seen is the Strategy Design Pattern, which helps pack the changes, and can run in real time.

The second part is the search conditions, so we created the ApplePredicate interface with two implementation classes: AppleHeavyWeightPredicate and AppleGreenColorPredicate .

You can refer to the following article about Strategy Design Pattern, introduce what is Design Pattern, and how to design Strategy Design Pattern:

https://viblo.asia/p/design-pattern-la-gi-V3m5WPbyKO7

But how to implement ApplePredicate ?

You need a filterApples function, whose parameter is the ApplePredicate object to check the condition of the apple.

The meaning of parameterizing behavior: allows the function to accept multiple behaviors (strategies) as a parameter, and use them to execute.

Method 4: Search by statistic field behavior

The code becomes more flexible than previous times, the code is easy to read and use.

You can create additional classes that implement the ApplePredicate interface and pass the filterApples function.

If the rancher asks you to look for red apples and weighs over 150g, all you need to do is create the corresponding ApplePredicate class.

Your code is now very flexible to apply to the new request:

You’ve just done something amazing: the behavior of the filterApples function depends on the object you pass in. In other words, you’ve just parameterized the behavior of the filterApples function.

alt text

Many behaviors, one parameter

As explained earlier, the parameterization of the behavior is great, because it allows you to separate the “browse each part of the for loop” and “search behavior”.

With this application you can reuse the function, and can pass all the desired behavior.

This is why parameterizing behavior is a good concept, so you should keep it as a tool to generate flexible lines of code.

Parameterize the behavior of filterApples () and pass different strategies (behaviors)

alt text

To give you a better understanding of behavior parameterization, we will look at the following example:

Write the function that outputs the apple information

We will create a function named prettyPrintApple

  • Input: apple list (Apple).
  • Output: export to many different formats.

In this example I will give 2 types of output, in fact you can create 5 or 10 or 100 types:

  1. Output type of apple: heavy or light and their color.
  2. Export the weight of the apple.

To help you easily visualize yourself as a model frame for you:

String output = ???.???(apple); . As you can see we need a handler function, the input value is Apple and the result is a processed string.

You will do the same when you create an ApplePredicate interface:

And now we will create classes to implement the AppleFormatter interface

And finally we will modify the prettyPrintApple function

Great! And now we can pass any behavior into prettyPrintApple function. Do this by initializing the implementation class of the corresponding AppleFormatter interface.

We want to export color and apple information so we will use the behavior of AppleFancyFormatter

prettyPrintApple(inventory, new AppleFancyFormatter());

Result:

A light green apple A heavy red apple …

Or just export the size of the apple:

prettyPrintApple(inventory, new AppleSimpleFormatter());

Result:

An apple of 80g An apple of 155g …

By abstracting the behavior, it makes it possible for the code to respond to many different requirements, but the problem is that we have to create many classes. To solve this problem we will explore the next example.

Resolve redundancy

Java has a technique called anonymous class, which helps you declare and initialize the class at the same time.

As the name implies (anonymous class) this class is used just like the normal class, but there will be no class name.

Method 5: use an anonymous class

The code below will create an anonymous class that implements the ApplePredicate interface

Anonymous classes are often used in the context of Java applications to create event handlers.

But the anonymous class is still not good enough to review the code to search for red apples:

return "red".equals(apple.getColor()); Only this paragraph is changed. Other code we have to copy and paste, very redundant.

One more thing is that the excess code will make us confused. For example, the following scenario:

When executing the code below, what is the output: 4, 5, 6 or 42?

The result will be 5, because it is in the scope of the Runnable, not the MeaningOfThis class.

Excess is often not good, and is not recommended in the programming language because it takes time to write code and maintain, and makes it difficult to read the code.

A good piece of code is an easy-to-understand, interesting code for readers.

Method 6: use lambda expressions (lambda expressions)

With the lambda expression you can rewrite the following:

You have to admit that the above code looks easier to understand than the previous one.

It is great because it only executes code that is related to the problem it needs to solve -> I want to get red apples (Apple apple) -> "red".equals(apple.getColor()) apples (Apple apple) -> "red".equals(apple.getColor())

The graph compares the parameter with value vs acts parameterized

alt text

Method 7: Abstractizing the list type (list type)

Currently the filterApple function is specifically designed for apples, but what about oranges, grapefruit, plums and mangoes?

We will use generic to solve this problem:

And now you can search by list of apples, bananas, oranges, Interger or String.

It is amazing, isn’t it? You have realized the brevity and concise of Java 8, something that previous versions did not.

Bonus practical examples:

Sort with Comparator:

Farmers want to rearrange the list of apples by size. Or he changed his mind about wanting to sort by color.

You need a behavior to show how different types of arrangements respond to customers’ changing requirements.

In java, the List class has a sort function with the parameter passed as a behavioral parameter of the java.util.Comparator arrangement with the following interface:

And we can create the corresponding behavior according to customer requirements, using the anonymous class.

Sorting by increasing weight according to apple’s weight:

Lambda expression:

summary

Here are the points to note:

  • Behavioral parameterization allows you to pass different behaviors in response to customers’ constantly changing requirements.
  • Behavioral parameterization makes your code readable, easy to maintain, and eliminates redundancy.
  • Creating new classes or using anonymous classes makes your code redundant. Java 8 solves this problem by using lambda, which allows you to generate code that is only relevant to the problem.
  • The Java API contains many functions that help you parameterize your behavior: search, threads, and Java app processing.

If you have time, you should learn about Strategy Design Pattern:

https://viblo.asia/p/design-pattern-la-gi-V3m5WPbyKO7

Source code

https://github.com/java8/Java8InAction/tree/master/src/main/java/lambdasinaction/chap2

Contribute

Please give me a minute to help me. Please leave your comments to help the latter to read and understand better.

Thank you for your interest in this article. I wish you a good day! ?

References from: Java 8 in Action (Raoul-Gabriel Urma, Mario Fusco, and Alan Mycroft).

Blessed.

Share the news now

Source : Viblo