Java functional programming of three: list conversion

  • 2020-04-01 03:31:07
  • OfStack

Conversion of lists

Converting a collection to a new set is as easy as traversing it. Suppose we want to convert the names in the list to all caps. So let's see what we can do.

Strings in Java are immutable, so it cannot be changed. We can generate new strings to replace the original elements in the list. However, if you do that, the original list is gone; Another problem is that the original list may also be immutable, such as the ones generated by arrays.aslist (), so modifying the original list won't work. Another drawback is that it's hard to do in parallel.

Generating a new all-caps list is a good option.

At first glance, this advice sounds too weak; Performance is an issue that we are all concerned about. Surprisingly, functional programming generally performs better than imperative programming, as we'll see on page 153 on performance issues.

So let's start by generating a new set of uppercase letters from this set.


final List<String> uppercaseNames = new ArrayList<String>();
for(String name : friends) {
uppercaseNames.add(name.toUpperCase());
}

In imperative code, we create an empty list, fill it with capitalized names, and insert one at a time as we iterate through the original list. To improve the functional version, consider replacing the for loop with the internal iterator forEach mentioned in the 19 page traversal list, as shown in the following example.

final List<String> uppercaseNames = new ArrayList<String>();
friends.forEach(name -> uppercaseNames.add(name.toUpperCase()));
System.out.println(uppercaseNames);

We used an internal iterator, but we had to create a new list and then insert elements into it. We can improve it further.

Using lambda expressions

A newly introduced Stream interface has a map method that can help us get away from variability and make the code look cleaner. Steam is a bit like an iterator for collections, and it also provides the capability of fluent functions. Using this interface method, we can combine a series of calls to make the code read more readable, like the order in which the problem is described.

Steam's map method can be used to convert an input sequence into an output sequence -- this is a good match for what we're going to do.


friends.stream()
.map(name -> name.toUpperCase())
.forEach(name -> System.out.print(name + " "));
System.out.println();

All collections in JDK8 support this stream method, which encapsulates the collection as a Steam instance. The map method invokes the specified lambda expression or block of code for each element in the Stream. The map method is very different from the forEach method, which simply performs the specified function on the elements in the collection. The map method collects the results of the lambda expression and returns a result set. Finally, we printed all the elements using the forEach method.

The names in the new collection are all capitalized:


BRIAN NATE NEAL RAJU SARA SCOTT

The map method is good for converting an input set to a new output set. This method ensures that the number of elements in the I/o sequence is the same. However, the types of input and output elements can be different. In this example, what we're putting in and out is a collection of strings. We can pass the map method a piece of code that returns, for example, the number of characters in the name. In this case, the input is still a sequence of strings and the output is a sequence of Numbers, like this.


friends.stream()
.map(name -> name.length())
.forEach(count -> System.out.print(count + " "));

The result is the number of letters in each name:

5 4 4 4 4 5

Later versions of lambda expressions are used to avoid explicit modification operations; This code is very clean. So it's no longer necessary to initialize an empty set and that garbage variable; This variable is nicely hidden in the underlying implementation.

Use method references

We can also use method references to make it more concise. Where an implementation of a functional interface needs to be passed in, the Java compiler can accept lambda expressions or method references. With this feature, you can replace the name -> with String::toUpperCase; Name. toUpperCase(), like this:


friends.stream()
.map(String::toUpperCase)
.forEach(name -> System.out.println(name));

Java calls the toUpperCase method of the String parameter when the argument is passed into the generated method, an implementation of the abstract method of the functional interface. The parameter reference is hidden here. In a simple scenario like the one above, we can replace lambda expressions with method references; More on when to use method references on page 26.


My partner asked:
When should method references be used? When using Java When we're programming, we usually use lambda There are many more expressions than method references. But that doesn't mean that method references aren't important or useful. when lambda When expressions are very short, it's a good alternative to calling instance methods or static methods directly. In other words, if lambda If the expression simply passes an argument to a method call, we should use a method reference instead.
Like this, lambda The expression, it's kind of like Tom Smykowski In the movie "work bug", it does its job " Take the requirements from the customer to the software engineer " . Because of this, I call the pattern referenced by this reconstitution method work bug pattern.
In addition to conciseness, the method reference, the meaning and function of the method name itself can be better reflected.
The compiler plays a key role behind the use of method references. The target object and the parameters that the method references are derived from the parameters passed in the generated method. This allows you to use the method reference to write out than to use lambda A cleaner code for expressions. However, this handy notation is not useful if the arguments are to be changed before they are passed to the method or if the result of the call is to be modified after it is returned.

In the previous example, a method reference refers to an instance method. Method references can also refer to a static method and methods that accept arguments. We'll see an example of this later.

Lambda expressions can help us traverse the set and transform the set. As we'll see below, it also helps us quickly select an element from the collection.


Related articles: