Preface:

To meet the needs of our readers, Pei has brought you a new issue of dry goods!

Take you to solve the big factory will use Lambda expressions, functional interface

This guide will show you the Stream and method references that must be used by large factories

If IT helps you and your friends, pay attention. Thumb up! Thumb up! Comment! Collection! Share it with more friends to learn and communicate, and keep digging gold every day without your support!


Chapter 3 Stream

In Java 8, thanks to the functional programming brought about by Lambda, a new Stream concept was introduced to address the shortcomings of the existing collection libraries.

3.1 the introduction

Multi-step traversal code for traditional collections

Almost all collections, such as the Collection interface or the Map interface, support direct or indirect traversal operations. When we need to operate on the elements in the collection, in addition to the necessary addition, deletion, acquisition, the most typical is the collection traversal. Such as:

public class Demo10ForEach {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Zhang Wuji");
        list.add("Zhou Zhiruo");
        list.add("Zhao");
        list.add("Zhang qiang");
        list.add("Zhang Sanfeng");
        for(String name : list) { System.out.println(name); }}}Copy the code

This is a very simple collection traversal: print out every string in the collection.

Disadvantages of loop traversal

Lambdas in Java 8 allow us to focus more on What rather than How, as previously illustrated in relation to inner classes. Now, if we take a closer look at the above code, we can see that:

  • The syntax of the for loop is “How to”
  • The body of the for loop is the “do”

Why use loops? Because we’re going to iterate. But is a loop the only way to iterate? A traversal is a loop where each element is processed one by one, not from the first to the last. The former is the end, the latter the means.

Imagine if you wanted to filter the elements of a collection:

  1. Set A is filtered into subset B according to condition 1.
  2. And then we filter it into subset C based on condition two.

So what? Prior to Java 8, this might have been done:

There are three loops in this code, each with a different effect:

  1. First, screen all zhangs;
  2. And then we screened people with three characters in their names;
  3. Finally, the results are printed out.
public class Demo11NormalFilter {
  	public static void main(String[] args) {
      	List<String> list = new ArrayList<>();
        list.add("Zhang Wuji");
        list.add("Zhou Zhiruo");
        list.add("Zhao");
        list.add("Zhang qiang");
        list.add("Zhang Sanfeng");

        List<String> zhangList = new ArrayList<>();
        for (String name : list) {
            if (name.startsWith("Zhang")) {
              	zhangList.add(name);
            }
        }

        List<String> shortList = new ArrayList<>();
        for (String name : zhangList) {
            if (name.length() == 3) { shortList.add(name); }}for(String name : shortList) { System.out.println(name); }}}Copy the code

Every time we need to operate on an element in a collection, we need to loop, loop, recycle. Is that a given? It isn’t. A cycle is a way of doing things, not an end. Using a linear loop, on the other hand, means traversing only once. If you want to iterate again, you have to start from scratch with another loop.

So what’s a more elegant way to write Lambda’s derivative Stream?

A better way of writing Stream

Let’s take a look at what’s elegant with Java 8’s Stream API:

public class Demo12StreamFilter {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Zhang Wuji");
        list.add("Zhou Zhiruo");
        list.add("Zhao");
        list.add("Zhang qiang");
        list.add("Zhang Sanfeng");

        list.stream()
          	.filter(s -> s.startsWith("Zhang"))
            .filter(s -> s.length() == 3) .forEach(s -> System.out.println(s)); }}Copy the code

Reading the literal meaning of the code perfectly illustrates the semantics of the irrelevant logic approach: get stream, filter name, filter length 3, print one by one. Instead of iterating through the code using a linear loop or any other algorithm, what we really need to do is better represented in the code.

3.2 Overview of streaming ideas

Note: Forget about traditional IO streams for a moment!

Taken as a whole, the flow idea is similar to the “assembly line” on the factory floor.

When you need to operate on multiple elements (especially multi-step operations), for performance and convenience, you should first put together a “model” step scheme and then execute it.

This diagram shows multi-step operations such as filtering, mapping, skipping, and counting. It is a scheme for processing collection elements, and the scheme is a “functional model”. Each box in the diagram is a “flow” that can be converted from one flow model to another by calling the specified method. And the number 3 on the far right is the final result.

Here filter, map, and SKIP are all operating on the functional model, and the collection elements are not really processed. Only when the finalization method count is executed does the entire model execute according to the specified policy. This is thanks to the delayed execution nature of Lambda.

Note: A “Stream” is actually a functional model of collection elements. It is not a collection, nor is it a data structure. It does not store any elements (or their address values).

3.3 Obtaining the Flow Mode

Stream

is the most common new stream interface added to Java 8. (This is not a functional interface.)

Getting a stream is very simple. There are several common ways to get a stream:

  • All of theCollectionAll sets can pass throughstreamThe default method gets the stream;
  • StreamStatic methods of the interfaceofYou can get the corresponding stream of the array.

Method 1: Get streams by Collection

First, the java.util.Collection interface adds the default method stream to fetch streams, so all of its implementation classes can fetch streams.

import java.util.*;
import java.util.stream.Stream;
1. Stream () 2.Stream (T... T) Add multiple data to Stream */
public class Demo13GetStream {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        // ...
        Stream<String> stream1 = list.stream();

        Set<String> set = new HashSet<>();
        // ...Stream<String> stream2 = set.stream(); }}Copy the code

Method 2: Get the stream from the array

If you are using arrays instead of collections or maps, the Stream interface provides the static method of, which is easy to use, since it is impossible to add default methods to array objects:

import java.util.stream.Stream;

public class Demo14GetStream {
    public static void main(String[] args) {
        String[] array = { "Zhang Wuji"."Zhang Cuishan"."Zhang Sanfeng"."Zhang Yi Yuan"}; Stream<String> stream = Stream.of(array); }}Copy the code

Note: The argument to the of method is actually a mutable argument, so arrays are supported.

3.4 Common Methods

The operation of the flow model is very rich, and here are some commonly used apis. These methods can be divided into two categories:

  • Put an end to the methodThe return value type is no longerStreamMethods of the interface’s own type, so similar is no longer supportedStringBuilderChain calls like that. In this section, the termination methods includecountandforEachMethods.
  • Nonterminal methodThe return value type is stillStreamA method of the interface’s own type, and therefore supports chained calls. (All methods except finalizing methods are non-finalizing methods.)

Note: Please refer to the API documentation for more methods beyond this section.

ForEach: One by one

Although the name of the method is forEach, unlike the “for-each” nickname in the for loop, this method does not guarantee that eleme-by-element consumption actions will be executed in order in the flow.

void forEach(Consumer<? super T> action);
Copy the code

This method receives a Consumer interface function that hands each stream element to the function for processing. Such as:

import java.util.stream.Stream;

public class Demo15StreamForEach {
    public static void main(String[] args) {
        Stream<String> stream =  Stream.of("Big baby"."She"."Three dolls"."Four Eva"."Five Eva"."Six dolls"."Seven Eva"."Grandpa"."Snake essence".Scorpion essence);
        //Stream
      
        Stream = stream. of(" ", ""," ");
      
        stream.forEach((String str)->{System.out.println(str);});
    }
}
Copy the code

Here, lambda expression (String STR)->{system.out.println (STR); } is an example of a Consumer functional interface.

Filter: filter

A stream can be replaced with another subset stream using the Filter method. Method declaration:

Stream<T> filter(Predicate<? super T> predicate);
Copy the code

The interface accepts a Predicate function interface argument (which can be a Lambda) as a filter.

The basic use

The basic code for the filter method in Stream is as follows:

public class Demo16StreamFilter {
    public static void main(String[] args) {
        Stream<String> original = Stream.of("Zhang Wuji"."Zhang Sanfeng"."Zhou Zhiruo");
        Stream<String> result = original.filter((String s) -> {return s.startsWith("Zhang");});
    }
}
Copy the code

Here the criteria for filtering are specified by a Lambda expression: the last name must be Zhang.

Count: indicates the number of statistics

Just like the size method in the old Collection, the stream provides the count method to count the number of elements in it:

long count(a);
Copy the code

This method returns a long value representing the number of elements (no longer an int like the old collection). Basic use:

public class Demo17StreamCount {
    public static void main(String[] args) {
        Stream<String> original = Stream.of("Zhang Wuji"."Zhang Sanfeng"."Zhou Zhiruo");
        Stream<String> result = original.filter(s -> s.startsWith("Zhang"));
        System.out.println(result.count()); / / 2}}Copy the code

Limit: Take the first few

The limit method can intercept convection, taking only the first n. Method signature:

Stream<T> limit(long maxSize): Gets the first n elements of the Stream object and returns a new Stream objectCopy the code

The parameter is a long. If the current length of the collection is greater than the parameter, it is truncated. Otherwise, no operation is performed. Basic use:

import java.util.stream.Stream;

public class Demo18StreamLimit {
    public static void main(String[] args) {
        Stream<String> original = Stream.of("Zhang Wuji"."Zhang Sanfeng"."Zhou Zhiruo");
        Stream<String> result = original.limit(2);
        System.out.println(result.count()); / / 2}}Copy the code

Skip the first few

If you want to skip the first few elements, you can use the skip method to get a new truncated stream:

Stream<T> skip(long n): Skips the first n elements of the Stream object and returns a new Stream objectCopy the code

If the current length of the stream is greater than n, the first n are skipped; Otherwise you get an empty stream of length 0. Basic use:

import java.util.stream.Stream;

public class Demo19StreamSkip {
    public static void main(String[] args) {
        Stream<String> original = Stream.of("Zhang Wuji"."Zhang Sanfeng"."Zhou Zhiruo");
        Stream<String> result = original.skip(2);
        System.out.println(result.count()); / / 1}}Copy the code

Combination of concat:

If you have two streams that you want to merge into one, you can use the static method concat of the Stream interface:

static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b): Merges two Stream objects a and B from the argument list into a new Stream objectCopy the code

Note: This is a static method, unlike the concat method in java.lang.String.

The basic usage code for this method is as follows:

import java.util.stream.Stream;

public class Demo20StreamConcat {
    public static void main(String[] args) {
        Stream<String> streamA = Stream.of("Zhang Wuji");
        Stream<String> streamB = Stream.of("Zhang Cuishan"); Stream<String> result = Stream.concat(streamA, streamB); }}Copy the code

3.5 Stream Comprehensive case

There are now two ArrayList collections that store the names of multiple members of a queue, requiring the following steps in sequence using a traditional for loop (or enhanced for loop) :

  1. The first team requires only a three-character member name;
  2. Only the first three players are required after the first team is selected;
  3. The second team only requires the name of the member surnamed Zhang;
  4. The second team is screened without the first 2 people;
  5. Merge two teams into one team
  6. Print the name information for the entire queue.

The codes for the two teams (collections) are as follows:

public class Demo21ArrayListNames {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("Dilieba");
        one.add(Song Yuan Bridge);
        one.add("Suxing River");
        one.add("Lao zi");
        one.add("Chuang tzu");
        one.add("Grandson");
        one.add("Hong Qi Gong");

        List<String> two = new ArrayList<>();
        two.add(gulinaza);
        two.add("Zhang Wuji");
        two.add("Zhang Sanfeng");
        two.add("Zhao Liying");
        two.add("Zhang Ergou");
        two.add("Zhang Tian 'ai");
        two.add("Zhang");
		/ /...}}Copy the code

The traditional way

Example code for the for loop:

public class Demo22ArrayListNames {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        // ...

        List<String> two = new ArrayList<>();
        // ...

        // The first team only needs a member name of 3 characters;
        List<String> oneA = new ArrayList<>();
        for (String name : one) {
            if (name.length() == 3) { oneA.add(name); }}// Only the first 3 players are required after the first team selection;
        List<String> oneB = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            oneB.add(oneA.get(i));
        }

        // The second team only needs the member's surname Zhang;
        List<String> twoA = new ArrayList<>();
        for (String name : two) {
            if (name.startsWith("Zhang")) { twoA.add(name); }}// Do not select the first 2 after the second team;
        List<String> twoB = new ArrayList<>();
        for (int i = 2; i < twoA.size(); i++) {
            twoB.add(twoA.get(i));
        }

        // Merge two teams into one team;
        List<String> totalNames = new ArrayList<>();
        totalNames.addAll(oneB);
        totalNames.addAll(twoB);        

        // Print the name of the entire queue.
        for(String name : totalNames) { System.out.println(name); }}}Copy the code

The running results are as follows:

Song Yuan Bridge, Su Xing River, Hong Qigong, Zhang Ergou, Zhang Tian 'ai, Zhang SANCopy the code

The Stream way

The equivalent Stream processing code is:

public class Demo23StreamNames {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        // ...

        List<String> two = new ArrayList<>();
        // ...

        // The first team only needs a member name of 3 characters;
        // Only the first 3 players are required after the first team selection;
        Stream<String> streamOne = one.stream().filter(s -> s.length() == 3).limit(3);

        // The second team only needs the member's surname Zhang;
        // Do not select the first 2 after the second team;
        Stream<String> streamTwo = two.stream().filter(s -> s.startsWith("Zhang")).skip(2);

        // Merge two teams into one team;
        // Create a Person object based on the name;
        // Prints the Person object information for the entire queue.Stream.concat(streamOne, streamTwo).forEach(s->System.out.println(s)); }}Copy the code

It works exactly the same:

Song Yuan Bridge, Su Xing River, Hong Qigong, Zhang Ergou, Zhang Tian 'ai, Zhang SANCopy the code

3.6 Function splicing and termination methods

Of the methods described above, those that still return a Stream interface are function concatenation methods that support chained calls. Terminating methods that no longer return a Stream interface no longer support chained calls. As shown in the following table:

The method name Methods effect Method type Whether chain calls are supported
count The number of statistical Put an end to no
forEach Handle them one by one Put an end to no
filter filter Function together is
limit Take the first couple Function together is
skip Skip the first few Function together is
concat combination Function together is

Chapter 4 Method citation

4.1 Overview and method references

Take a look at a simple functional interface to apply a Lambda expression and accept a string in the accept method in order to print a display string. The code for using Lambda is simple:

public class DemoPrintSimple {
    private static void printString(Consumer<String> data, String str) {
        data.accept(str);
    }
    public static void main(String[] args) {
      	printString(s -> System.out.println(s), "Hello World"); }}Copy the code

Since the implemented println method is called in lambda expressions, method references can be used instead of lambda expressions.

The symbol represents :: :

Notation: The double colon is the method reference operator, and the expression it is in is called a method reference.

** Method references can be used if the function scheme Lambda is expressing already exists in an implementation of a method.

In the example above, the println(String) method in the system. out object is exactly what we need, so for the Consumer interface as a parameter, the following two methods are exactly equivalent:

  • Lambda expression: s -> system.out.println (s); Lambda takes the argument and passes it to the system.out.println method for processing.
  • Out ::println Directly replaces Lambda with the println method in system. out.

** Derivation and elision: ** If Lambda is used, there is no need to specify parameter types and no need to specify overloaded forms — they are all automatically derived, according to the “derivable is elided” principle. If you use method references, you can also derive from context. Functional interfaces are the basis of Lambda, and method references are a simplified form of Lambda.

4.2 Method reference simplification

Just “quote” the past:

public class DemoPrintRef {
    private static void printString(Consumer<String> data, String str) {
        data.accept(str);
    }
    public static void main(String[] args) {
      	printString(System.out::println, "HelloWorld"); }}Copy the code

Notice the double colon ::, which is called a “method reference,” and the double colon is a new syntax.

4.3 Extended Reference Mode

Object name – references member methods

This is the most common usage and is the same as the example above. If a member method already exists in a class, it can be referenced by the object name, with the code:

public class DemoMethodRef {
     public static void main(String[] args) {
        String str = "hello";
        printUP(str::toUpperCase);
    }

    public static void printUP(Supplier< String> sup ){ String apply =sup.get(); System.out.println(apply); }}Copy the code

Class name – references static methods

Because the static method random already exists in the java.lang.Math class, when we need to call the method with a Lambda, we can use a method reference, written like this:

public class DemoMethodRef {
  public static void main(String[] args) {
        printRanNum(Math::random);
    }

    public static void printRanNum(Supplier<Double> sup ){ Double apply =sup.get(); System.out.println(apply); }}Copy the code

In this case, the following two forms are equivalent:

  • Lambda expressions:n -> Math.abs(n)
  • Method reference:Math::abs

Class – Construct reference

Because the constructor name is exactly the same as the class name, it is not fixed. So the constructor reference is formatted with the class name ::new. The first is a simple Person class:

public class Person {
    private String name;
    public Person(String name) {
      	this.name = name;
    }
    public String getName(a) {
      	returnname; }}Copy the code

To use this functional interface, you can pass it by method reference:

public class Demo09Lambda {
    public static void main(String[] args) {
		String name = "tom";
        Person person = createPerson(Person::new, name);
        System.out.println(person);
        
    }

    public static Person createPerson(Function<String, Person> fun , String name){
        Person p = fun.apply(name);
        returnp; }}Copy the code

In this case, the following two forms are equivalent:

  • Lambda expressions:name -> new Person(name)
  • Method reference:Person::new

Array – Construct reference

Arrays are subclasses of Object, so they also have constructors with slightly different syntax. If Lambda is used, a functional interface is required:

When this interface is applied, it can be passed by method reference:

public class Demo11ArrayInitRef {   
   public static void main(String[] args) {

        int[] array = createArray(int[] : :new.3);
        System.out.println(array.length);

    }

    public static int[] createArray(Function<Integer , int[]> fun , int n){
        int[] p = fun.apply(n);
        returnp; }}Copy the code

In this case, the following two forms are equivalent:

  • Lambda expressions:length -> new int[length]
  • Method reference:int[]::new

Note: A method reference is an abbreviation for a Lambda expression that conforms to a specific case. It makes our Lambda expressions more concise, It can also be referred to as a short form of a Lambda expression. Students can try to rewrite the previous use of a Lambda as a method reference, but note that method references can only refer to existing methods.

Follow-up wonderful serialized articles, please look forward to:

  • Feel free to leave a comment, write down any technical topics you are interested in.

For more articles, please move on to back-end development and learn from him. 🔥


If IT helps you and your friends, pay attention. Thumb up! Thumb up! Comment! Collection! Share it with more friends to learn and exchange, and keep updating every day without your support!

Welcome to pay attention to my B station, the future will publish articles synchronous video ~~~Welcome to follow my public number, get more information ~~~ welcome to follow my public number, get more information ~~~