Map (map) and reduce (reduction, reduction) are mathematically two very basic concepts, they are very early in the various functional programming language, until 2003, Google will be carried out in the distributed system for parallel computing, The name of the combination begins to shine in the computer world (those functional powders may not think so). In this article, we will see that the first appearance of the map and reduce combinations (here is a preliminary introduction, followed by a topic for them), after Java 8 has been programmed to support functional programming.
To classify a set
So far we've covered a couple of new techniques for manipulating sets: finding matching elements, finding individual elements, and transforming collections. These operations have one thing in common, and they all operate on a single element in the collection. There is no need to compare elements, or to perform operations on two elements. In this section we'll look at how to compare elements and dynamically maintain an operation result during traversal of the collection.
Let's start with a simple example, and then step back. In the first example, let's go through the Friends collection and figure out the total number of characters for all the names.
Copy Code code as follows:
SYSTEM.OUT.PRINTLN ("Total number of characters in all names:" + Friends.stream ()
. Maptoint (Name-> name.length ())
. sum ());
To figure out the total number of all characters we need to know the length of each name. This can be done easily through the Maptoint () method. When we have changed the name to the corresponding length, we only need to add it to the end of the line. We have a built-in sum () method to do this. Here is the final output:
Copy Code code as follows:
Total number of characters in all names:26
We use a variant of the map operation, the Maptoint () method (which has maptoint, maptodouble, etc., corresponds to generating a specific type of flow, such as Intstream,doublestream), and then calculates the total number of characters based on the length of the return.
In addition to using the sum method, there are many similar methods that can be used, such as Max () to find the maximum length, min () is the minimum length, sorted () to the length of the order, average () for the average length, and so on.
One of the attractions of this example is the increasingly popular mapreduce pattern, the map () method is mapped, and the sum () method is a more commonly used reduce operation. In fact, the implementation of the sum () method in JDK uses the reduce () method. Let's look at some of the more commonly used forms of the reduce operation.
Let's say we iterate through all the names and print out the one with the longest name. If the longest name has several, we'll print out the one we found at the beginning. One way is to calculate the maximum length and then select the first element that matches that length. But doing this requires traversing the two-time list--too inefficient. This is the time for the reduce operation to play.
We can use the reduce operation to compare the lengths of two elements, then return the longest one, and then compare it to the remaining elements. Like the other High-order functions we saw earlier, the reduce () method also traverses the entire collection. In addition, it records the computed results returned by the lambda expression. If there's one example that can help us better understand this, let's take a look at a piece of code first.
Copy Code code as follows:
Final optional<string> alongname = Friends.stream ()
. reduce ((name1, name2)->
Name1.length () >= name2.length ()? NAME1:NAME2);
Alongname.ifpresent (Name->
System.out.println (String.Format ("A Longest name:%s", name));
The lambda expression passed to the reduce () method receives two parameters, name1 and name2, which compare their lengths and return the longest one. The reduce () method has no idea what we're going to do. This logic is stripped into the lambda expressions we pass in--a lightweight implementation of the policy pattern.
This lambda expression can fit into the Apply method of a Binaryoperator functional interface in the JDK. This is exactly the type of argument that the reduce method will accept. Let's run this reduce method to see if it correctly picks the first one in the two longest names.
Copy Code code as follows:
While the reduce () method traverses the collection, it invokes a lambda expression on the first two elements of the collection, and the result returned by the call continues to be used for the next call. In the second call, the value of the name1 is bound to the result of the last call, and the Name2 value is the third element of the collection. The remaining elements are then called in turn. The result of the last lambda expression call is the result returned by the entire reduce () method.
The reduce () method returns a optional value, because the collection passed to it may be empty. In that case, there is no longest name. If the list has only one element, the reduce method returns that element directly and does not invoke the lambda expression.
From this example we can infer that the result of reduce can be at most only one element in the collection. If we want to return a default or base value, we can use a variant of the reduce () method, which can receive an extra parameter. For example, if the shortest name is Steve, we can pass it to the reduce () method, like this:
Copy Code code as follows:
Final String Steveorlonger = Friends.stream ()
. Reduce ("Steve", (name1, name2)->
Name1.length () >= name2.length ()? NAME1:NAME2);
If there is a name longer than it, then the name will be selected, otherwise it will return the base value of Steve. This version of the reduce () method does not return the optional object, because if the collection is empty, a default value is returned, regardless of the absence of a return value.
Before we end this chapter, let's take a look at a very basic but not so easy operation within the set operation: merging elements.
Merging elements
We have learned how to search for elements, to traverse them, and to transform the set. But there is also a common operation-stitching together elements of the collection-without the newly added join () function, the previously simple and elegant code can only be dashed. This simple method is so practical that it becomes one of the most commonly used functions in JDK. Let's take a look at how to use it to print the elements in a list, separated by commas.
We still use this friends list. What would you do if you used the old method in the JDK library to print all your names and separate them with commas?
We have to traverse the list and print the elements. The For loop in Java 5 is better than before, so let's use it.
Copy Code code as follows:
for (String name:friends) {
System.out.print (name + ",");
}
System.out.println ();
The code is simple, let's see what it's output.
Copy Code code as follows:
Brian, Nate, Neal, Raju, Sara, Scott,
Damn, there was a nasty comma at the end of the last one (do we blame the last Scott?). How can we let Java not put a comma here? Unfortunately, loops are executed in a step-by-minute way, and it's not easy to make it special at the end of the process. In order to solve this problem, we can use the same way back to the original cycle.
Copy Code code as follows:
for (int i = 0; i < friends.size ()-1; i++) {
System.out.print (Friends.get (i) + ",");
}
if (friends.size () > 0)
System.out.println (Friends.get (Friends.size ()-1));
Let's see if this version of the output is OK.
Copy Code code as follows:
Brian, Nate, Neal, Raju, Sara, Scott.
The result is good, but the code is not flattering. Help us, Java.
We don't have to put up with this pain any longer. The Stringjoiner class in Java 8 helps us to fix these challenges, and more than that, the string class adds a join method that allows us to replace the top piece with a single line of code.
Copy Code code as follows:
System.out.println (String.Join (",", friends));
Come and see, the results are as satisfying as the code.
Copy Code code as follows:
Brian, Nate, Neal, Raju, Sara, Scott.
The result is good, but the code is not flattering. Help us, Java.
We don't have to put up with this pain any longer. The Stringjoiner class in Java 8 helps us to fix these challenges, and more than that, the string class adds a join method that allows us to replace the top piece with a single line of code.
Copy Code code as follows:
System.out.println (String.Join (",", friends));
Come and see, the results are as satisfying as the code.
Copy Code code as follows:
Brian, Nate, Neal, Raju, Sara, Scott.
In the underlying implementation, the String.Join () method calls the Stringjoiner class to concatenate the value of the second parameter (which is a variable length parameter) into a long string, using the first argument as the separator. Of course, this method is not only to be able to splice commas so simple. For example, we can pass in a bunch of paths and then easily spell out a classpath (classpath), which is thanks to these new additions to the methods and classes.
We already know how to connect to the list element, and before we can make a list connection, we'll be able to transform the elements, and of course we know how to use the Map method to convert the list. You can then filter out the elements we want with the filter () method. The last step of the connection list element, comma or what delimiter, is just a simple reduce operation.
We can use the reduce () method to stitch the elements together into a string, but it takes a bit of effort. The JDK has a very handy collect () method, which is also a variant of reduce (), which we can use to combine the elements into a desired value.
Collect () method to perform a reduction operation, but it delegates the specific operation to a collector to execute. We can combine the transformed elements into a ArrayList. To continue with that example, we can concatenate the transformed elements into a comma-delimited string.
Copy Code code as follows:
System.out.println (
Friends.stream ()
. Map (String::touppercase)
. Collect (Joining (","));
We invoked the Collect () method on the transformed list, passing it a joining () method returned collector,joining is a static method in the Collectors tool class. Collector is like a receiver that receives collect objects and stores them in the format you want: ArrayList, string, and so on. We'll explore this approach further in the 52-page collect method and the Collectors class.
This is the name of the output, which is now capitalized and separated by commas.
Copy Code code as follows:
BRIAN, NATE, NEAL, RAJU, SARA, SCOTT.
Summarize
Collections are very common in programming, and when you have lambda expressions, the Java collection operation becomes simpler and easier. The old code for the dilatory set operation can be replaced by this elegant and concise new way. The internal iterator makes the collection traversal and transformation more convenient, away from the variability of the annoyance, and find the elements of the collection has become extremely relaxed. Use these new methods to write a lot less code. This makes the code easier to maintain, more focused on business logic, and fewer basic operations in programming.
In the next chapter we'll see how lambda expressions simplify another basic operation in program development: string manipulation and object comparisons.