This series of articles translates from functional programming in Java Venkat Subramaniam
Chapter II: The use of collections
We often use a variety of collections, numbers, strings, and objects. They are everywhere, even if the code to operate a set can be slightly optimized, it can make the code a lot clearer. In this chapter, we explore how to use lambda expressions to manipulate collections. We use it to iterate over the collection, to transform the set into a new set, to remove elements from the collection, and to merge the collection.
Traverse List
Traversing a list is the most basic set operation, and over the years its operations have changed. We use a small example of traversing a name, from the oldest version to the most elegant version of the present.
With the following code we can easily create a list of immutable names:
Final List friends =
Arrays.aslist ("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
System.out.println (Friends.get (i));
}
This is the most common way to traverse a list and print it, although it is most general:
for (int i = 0; i < friends.size (); i++) {
System.out.println (Friends.get (i));
}
I call this a masochistic style--long-winded and error-prone. We have to stop and think, "Is it i< or i<=?" "This only makes sense when we need to manipulate specific elements, but even then we can use a functional style that adheres to the immutable principle, which we'll soon discuss."
Java also provides a relatively advanced for structure.
Collections/fpij/iteration.java
for (String name:friends) {
SYSTEM.OUT.PRINTLN (name);
}
At the bottom, the iteration of this approach is implemented using the iterator interface, calling its Hasnext and next methods.
Both of these methods belong to an external iterator that combines how and what they want to do. We explicitly control the iteration, tell it where to start and where it ends, and the second version at the bottom through the iterator method. In an explicit operation, you can also use break and continue statements to control iterations.
The second version is something less than the first one. If we're not going to modify an element of a collection, it's better than the first. Both are imperative, however, and should be discarded in the current Java format.
There are several reasons to change to function:
The For loop itself is serial and difficult to parallelization.
Such a loop is not polymorphic; the income is the demand. Instead of using a method (which supports polymorphism) to perform a specific operation, we pass the collection directly to the for loop rather than to the collection.
From a design level, this code violates the "Tell,don ' t ask" principle. Instead of leaving the iterations to the underlying library, we ask for an iteration to execute.
It's time to switch from the old imperative programming to the more elegant, functional programming of the internal iterator. After using the internal iterator we throw a lot of concrete operations to the underlying method library to perform, and you can focus more on the specific business requirements. The underlying function is responsible for iterating. Let's first enumerate the list of names with an internal iterator.
The Iterable interface is reinforced in JDK8, which has a special name, foreach, that receives a parameter of a comsumer type. As the name says, consumer's example is the object passed to it by its accept method. We use this foreach method with a familiar syntax for anonymous inner classes:
Friends.foreach (New Consumer () {public void accept (final String name) {
SYSTEM.OUT.PRINTLN (name); }
});
We called the Foreach method on the Friends collection and passed it a consumer anonymous implementation. This foreach method calls the incoming consumer accept method from each element in the collection to handle the element. In this example we just print out its value, which is the name.
Let's look at the output of this version, which is the same as the two results:
Brian
Nate
Neal
Raju
Sara
Scott
We only changed one place: We abandoned the obsolete for loop and used a new internal iterator. The good thing is that we don't have to specify how to iterate over this collection, we can focus more on how to handle each element. The downside is that the code looks more verbose--and it's almost completely out of the joy of the new coding style. Fortunately, this is easy to get rid of, and this is the time for lambda expressions and the power of a new compiler. Let's make a little change to replace the anonymous inner class with a lambda expression.
Friends.foreach (final String name)-> System.out.println (name);
That would look much better. There's less code, but let's take a look at what that means. This foreach method is a high-order function that receives a lambda expression or code block to manipulate the elements in the list. At each call, the elements in the collection are bound to the variable name. The underlying library hosts the live of a lambda expression call. It can determine the execution of deferred expressions and can be computed in parallel if appropriate.
The output of this version is the same as the previous one.
{% Highlight java%}
Brian
Nate
Neal
Raju
Sara
Scott
The version of the internal iterator is more concise. And, using it, we can focus more on the processing of each element rather than how to traverse it-which is declarative.
But there are flaws in this version. Once the Foreach method has been implemented, unlike the other two versions, we cannot jump out of the iteration. (There are other ways to do this, of course). Therefore, this type of writing is more commonly used when dealing with each element in a set. Later we will introduce some other functions that allow us to control the loop process.
The standard syntax for lambda expressions is to put parameters in (), provide type information, and use commas to separate parameters. The Java compiler can also automate type derivation in order to liberate us. It's more convenient to write types, less work, and the world is quiet. The following is after the previous version removed the parameter type:
Friends.foreach ((name)-> System.out.println (name));
In this example, the Java compiler, through context analysis, knows that the type of name is string. It looks at the signature of the invoked method foreach and then analyzes the function interface in the argument. It then analyzes the abstract method in this interface to see the number and type of parameters. Even if the lambda expression receives more than one argument, we can do the same type deduction, but in this case all parameters cannot be of parameter type; In a lambda expression, the parameter type is either all written or written in full.
The Java compiler specifically handles lambda expressions for a single parameter: If you want to type derivation, the parentheses on both sides of the parameter can be omitted.
Friends.foreach (name-> System.out.println (name));
Here's a little warning: the arguments for type derivation are not final types. In the previous explicit declaration type example, we also mark the argument as final. This prevents you from modifying the value of the parameter in the lambda expression. In general, modifying the value of a parameter is a bad habit, which can easily cause bugs, so it's a good habit to mark final. Unfortunately, if we want to use type derivation, we have to follow the rules ourselves and not modify the parameters, because the compiler can no longer escort us.
It's a bit of a struggle to get there, and there's really a little less code. But that's not the simplest. Let's experience the last minimalist version.
Friends.foreach (System.out::p rintln);
In the above code we used a method reference. We can replace the entire code directly with the method name. In the next section we'll delve into this, but now we're going to recall Antoine de Saint-exupéry's famous saying that perfection is not something that cannot be added, but something that can no longer be removed.
Lambda expressions allow us to do a simple and straightforward traversal of the collection. In the next section, we'll talk about how it enables us to write such concise code when we do the deletion and set conversions.
To be continued, follow-up articles please continue to pay attention to deepinmind.
Original article reproduced please specify the source: http://it.deepinmind.com